xref: /netbsd-src/lib/libedit/vi.c (revision d9158b13b5dfe46201430699a3f7a235ecf28df3)
1 /*-
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Christos Zoulas of Cornell University.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #if !defined(lint) && !defined(SCCSID)
38 static char sccsid[] = "@(#)vi.c	8.1 (Berkeley) 6/4/93";
39 #endif /* not lint && not SCCSID */
40 
41 /*
42  * vi.c: Vi mode commands.
43  */
44 #include "sys.h"
45 #include "el.h"
46 
47 private el_action_t cv_action __P((EditLine *, int));
48 
49 /* cv_action():
50  *	Handle vi actions.
51  */
52 private el_action_t
53 cv_action(el, c)
54     EditLine *el;
55     int c;
56 {
57     register char *cp, *kp;
58 
59     if (el->el_chared.c_vcmd.action & DELETE) {
60 	el->el_chared.c_vcmd.action = NOP;
61 	el->el_chared.c_vcmd.pos = 0;
62 
63 	el->el_chared.c_undo.isize = 0;
64 	el->el_chared.c_undo.dsize = 0;
65 	kp = el->el_chared.c_undo.buf;
66 	for (cp = el->el_line.buffer; cp < el->el_line.lastchar; cp++) {
67 	    *kp++ = *cp;
68 	    el->el_chared.c_undo.dsize++;
69 	}
70 
71 	el->el_chared.c_undo.action = INSERT;
72 	el->el_chared.c_undo.ptr  = el->el_line.buffer;
73 	el->el_line.lastchar = el->el_line.buffer;
74 	el->el_line.cursor   = el->el_line.buffer;
75 	if (c & INSERT)
76 	    el->el_map.current = el->el_map.key;
77 
78 	return CC_REFRESH;
79     }
80 
81     el->el_chared.c_vcmd.pos = el->el_line.cursor;
82     el->el_chared.c_vcmd.action = c;
83     return CC_ARGHACK;
84 
85 #ifdef notdef
86     /*
87      * I don't think that this is needed. But we keep it for now
88      */
89     else if (el_chared.c_vcmd.action == NOP) {
90 	el->el_chared.c_vcmd.pos = el->el_line.cursor;
91 	el->el_chared.c_vcmd.action = c;
92 	return CC_ARGHACK;
93     }
94     else {
95 	el->el_chared.c_vcmd.action = 0;
96 	el->el_chared.c_vcmd.pos = 0;
97 	return CC_ERROR;
98     }
99 #endif
100 }
101 
102 
103 /* cv_paste():
104  *	Paste previous deletion before or after the cursor
105  */
106 protected el_action_t
107 cv_paste(el, c)
108     EditLine *el;
109     int c;
110 {
111     char *ptr;
112     c_undo_t *un = &el->el_chared.c_undo;
113 #ifdef DEBUG_PASTE
114     (void) fprintf(el->el_errfile, "Paste: %x \"%s\" +%d -%d\n",
115 		   un->action, un->buf, un->isize, un->dsize);
116 #endif
117     if (un->isize == 0)
118 	return CC_ERROR;
119 
120     if (!c && el->el_line.cursor < el->el_line.lastchar)
121 	el->el_line.cursor++;
122     ptr = el->el_line.cursor;
123 
124     c_insert(el, un->isize);
125     if (el->el_line.cursor + un->isize > el->el_line.lastchar)
126 	return CC_ERROR;
127     (void) memcpy(ptr, un->buf, un->isize);
128     return CC_REFRESH;
129 }
130 
131 
132 /* vi_paste_next():
133  *	Vi paste previous deletion to the right of the cursor
134  *	[p]
135  */
136 protected el_action_t
137 /*ARGSUSED*/
138 vi_paste_next(el, c)
139     EditLine *el;
140     int c;
141 {
142     return cv_paste(el, 0);
143 }
144 
145 
146 /* vi_paste_prev():
147  *	Vi paste previous deletion to the left of the cursor
148  *	[P]
149  */
150 protected el_action_t
151 /*ARGSUSED*/
152 vi_paste_prev(el, c)
153     EditLine *el;
154     int c;
155 {
156     return cv_paste(el, 1);
157 }
158 
159 
160 /* vi_prev_space_word():
161  *	Vi move to the previous space delimited word
162  *	[B]
163  */
164 protected el_action_t
165 /*ARGSUSED*/
166 vi_prev_space_word(el, c)
167     EditLine *el;
168     int c;
169 {
170     if (el->el_line.cursor == el->el_line.buffer)
171 	return CC_ERROR;
172 
173     el->el_line.cursor = cv_prev_word(el, el->el_line.cursor,
174 				      el->el_line.buffer,
175 			 	      el->el_state.argument,
176 				      cv__isword);
177 
178     if (el->el_chared.c_vcmd.action & DELETE) {
179 	cv_delfini(el);
180 	return CC_REFRESH;
181     }
182 
183     return CC_CURSOR;
184 }
185 
186 
187 /* vi_prev_word():
188  *	Vi move to the previous word
189  *	[B]
190  */
191 protected el_action_t
192 /*ARGSUSED*/
193 vi_prev_word(el, c)
194     EditLine *el;
195     int c;
196 {
197     if (el->el_line.cursor == el->el_line.buffer)
198 	return CC_ERROR;
199 
200     el->el_line.cursor = cv_prev_word(el, el->el_line.cursor,
201 				      el->el_line.buffer,
202 			 	      el->el_state.argument,
203 				      ce__isword);
204 
205     if (el->el_chared.c_vcmd.action & DELETE) {
206 	cv_delfini(el);
207 	return CC_REFRESH;
208     }
209 
210     return CC_CURSOR;
211 }
212 
213 
214 /* vi_next_space_word():
215  *	Vi move to the next space delimited word
216  *	[W]
217  */
218 protected el_action_t
219 /*ARGSUSED*/
220 vi_next_space_word(el, c)
221     EditLine *el;
222     int c;
223 {
224     if (el->el_line.cursor == el->el_line.lastchar)
225 	return CC_ERROR;
226 
227     el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
228 				      el->el_line.lastchar,
229 				      el->el_state.argument,
230 				      cv__isword);
231 
232     if (el->el_map.type == MAP_VI)
233 	if (el->el_chared.c_vcmd.action & DELETE) {
234 	    cv_delfini(el);
235 	    return CC_REFRESH;
236 	}
237 
238     return CC_CURSOR;
239 }
240 
241 /* vi_next_word():
242  *	Vi move to the next word
243  *	[w]
244  */
245 protected el_action_t
246 /*ARGSUSED*/
247 vi_next_word(el, c)
248     EditLine *el;
249     int c;
250 {
251     if (el->el_line.cursor == el->el_line.lastchar)
252 	return CC_ERROR;
253 
254     el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
255 				      el->el_line.lastchar,
256 				      el->el_state.argument,
257 				      ce__isword);
258 
259     if (el->el_map.type == MAP_VI)
260 	if (el->el_chared.c_vcmd.action & DELETE) {
261 	    cv_delfini(el);
262 	    return CC_REFRESH;
263 	}
264 
265     return CC_CURSOR;
266 }
267 
268 
269 
270 /* vi_change_case():
271  *	Vi change case of character under the cursor and advance one character
272  *	[~]
273  */
274 protected el_action_t
275 vi_change_case(el, c)
276     EditLine *el;
277     int c;
278 {
279     if (el->el_line.cursor < el->el_line.lastchar) {
280 	c = *el->el_line.cursor;
281 	if (isupper(c))
282 	    *el->el_line.cursor++ = tolower(c);
283 	else if (islower(c))
284 	    *el->el_line.cursor++ = toupper(c);
285 	else
286 	    el->el_line.cursor++;
287 	re_fastaddc(el);
288 	return CC_NORM;
289     }
290     return CC_ERROR;
291 }
292 
293 
294 /* vi_change_meta():
295  *	Vi change prefix command
296  *	[c]
297  */
298 protected el_action_t
299 /*ARGSUSED*/
300 vi_change_meta(el, c)
301     EditLine *el;
302     int c;
303 {
304     /*
305      * Delete with insert == change: first we delete and then we leave in
306      * insert mode.
307      */
308     return cv_action(el, DELETE|INSERT);
309 }
310 
311 
312 /* vi_insert_at_bol():
313  *	Vi enter insert mode at the beginning of line
314  *	[I]
315  */
316 protected el_action_t
317 /*ARGSUSED*/
318 vi_insert_at_bol(el, c)
319     EditLine *el;
320     int c;
321 {
322     el->el_line.cursor = el->el_line.buffer;
323     el->el_chared.c_vcmd.ins = el->el_line.cursor;
324 
325     el->el_chared.c_undo.ptr = el->el_line.cursor;
326     el->el_chared.c_undo.action = DELETE;
327 
328     el->el_map.current = el->el_map.key;
329     return CC_CURSOR;
330 }
331 
332 
333 /* vi_replace_char():
334  *	Vi replace character under the cursor with the next character typed
335  *	[r]
336  */
337 protected el_action_t
338 /*ARGSUSED*/
339 vi_replace_char(el, c)
340     EditLine *el;
341     int c;
342 {
343     el->el_map.current = el->el_map.key;
344     el->el_state.inputmode = MODE_REPLACE_1;
345     el->el_chared.c_undo.action = CHANGE;
346     el->el_chared.c_undo.ptr = el->el_line.cursor;
347     el->el_chared.c_undo.isize = 0;
348     el->el_chared.c_undo.dsize = 0;
349     return CC_NORM;
350 }
351 
352 
353 /* vi_replace_mode():
354  *	Vi enter replace mode
355  *	[R]
356  */
357 protected el_action_t
358 /*ARGSUSED*/
359 vi_replace_mode(el, c)
360     EditLine *el;
361     int c;
362 {
363     el->el_map.current = el->el_map.key;
364     el->el_state.inputmode = MODE_REPLACE;
365     el->el_chared.c_undo.action = CHANGE;
366     el->el_chared.c_undo.ptr = el->el_line.cursor;
367     el->el_chared.c_undo.isize = 0;
368     el->el_chared.c_undo.dsize = 0;
369     return CC_NORM;
370 }
371 
372 
373 /* vi_substitute_char():
374  *	Vi replace character under the cursor and enter insert mode
375  *	[r]
376  */
377 protected el_action_t
378 /*ARGSUSED*/
379 vi_substitute_char(el, c)
380     EditLine *el;
381     int c;
382 {
383     c_delafter(el, el->el_state.argument);
384     el->el_map.current = el->el_map.key;
385     return CC_REFRESH;
386 }
387 
388 
389 /* vi_substitute_line():
390  *	Vi substitute entire line
391  *	[S]
392  */
393 protected el_action_t
394 /*ARGSUSED*/
395 vi_substitute_line(el, c)
396     EditLine *el;
397     int c;
398 {
399     (void) em_kill_line(el, 0);
400     el->el_map.current = el->el_map.key;
401     return CC_REFRESH;
402 }
403 
404 
405 /* vi_change_to_eol():
406  *	Vi change to end of line
407  *	[C]
408  */
409 protected el_action_t
410 /*ARGSUSED*/
411 vi_change_to_eol(el, c)
412     EditLine *el;
413     int c;
414 {
415     (void) ed_kill_line(el, 0);
416     el->el_map.current = el->el_map.key;
417     return CC_REFRESH;
418 }
419 
420 
421 /* vi_insert():
422  *	Vi enter insert mode
423  *	[i]
424  */
425 protected el_action_t
426 /*ARGSUSED*/
427 vi_insert(el, c)
428     EditLine *el;
429     int c;
430 {
431     el->el_map.current = el->el_map.key;
432 
433     el->el_chared.c_vcmd.ins = el->el_line.cursor;
434     el->el_chared.c_undo.ptr = el->el_line.cursor;
435     el->el_chared.c_undo.action = DELETE;
436 
437     return CC_NORM;
438 }
439 
440 
441 /* vi_add():
442  *	Vi enter insert mode after the cursor
443  *	[a]
444  */
445 protected el_action_t
446 /*ARGSUSED*/
447 vi_add(el, c)
448     EditLine *el;
449     int c;
450 {
451     int ret;
452     el->el_map.current = el->el_map.key;
453     if (el->el_line.cursor < el->el_line.lastchar) {
454 	el->el_line.cursor++;
455 	if (el->el_line.cursor > el->el_line.lastchar)
456 	    el->el_line.cursor = el->el_line.lastchar;
457 	ret = CC_CURSOR;
458     }
459     else
460 	ret = CC_NORM;
461 
462     el->el_chared.c_vcmd.ins = el->el_line.cursor;
463     el->el_chared.c_undo.ptr = el->el_line.cursor;
464     el->el_chared.c_undo.action = DELETE;
465 
466     return ret;
467 }
468 
469 
470 /* vi_add_at_eol():
471  *	Vi enter insert mode at end of line
472  *	[A]
473  */
474 protected el_action_t
475 /*ARGSUSED*/
476 vi_add_at_eol(el, c)
477     EditLine *el;
478     int c;
479 {
480     el->el_map.current = el->el_map.key;
481     el->el_line.cursor = el->el_line.lastchar;
482 
483     /* Mark where insertion begins */
484     el->el_chared.c_vcmd.ins = el->el_line.lastchar;
485     el->el_chared.c_undo.ptr = el->el_line.lastchar;
486     el->el_chared.c_undo.action = DELETE;
487     return CC_CURSOR;
488 }
489 
490 
491 /* vi_delete_meta():
492  *	Vi delete prefix command
493  *	[d]
494  */
495 protected el_action_t
496 /*ARGSUSED*/
497 vi_delete_meta(el, c)
498     EditLine *el;
499     int c;
500 {
501     return cv_action(el, DELETE);
502 }
503 
504 
505 /* vi_end_word():
506  *	Vi move to the end of the current space delimited word
507  *	[E]
508  */
509 protected el_action_t
510 /*ARGSUSED*/
511 vi_end_word(el, c)
512     EditLine *el;
513     int c;
514 {
515     if (el->el_line.cursor == el->el_line.lastchar)
516 	return CC_ERROR;
517 
518     el->el_line.cursor = cv__endword(el->el_line.cursor, el->el_line.lastchar,
519 				     el->el_state.argument);
520 
521     if (el->el_chared.c_vcmd.action & DELETE) {
522 	el->el_line.cursor++;
523 	cv_delfini(el);
524 	return CC_REFRESH;
525     }
526 
527     return CC_CURSOR;
528 }
529 
530 
531 /* vi_to_end_word():
532  *	Vi move to the end of the current word
533  *	[e]
534  */
535 protected el_action_t
536 /*ARGSUSED*/
537 vi_to_end_word(el, c)
538     EditLine *el;
539     int c;
540 {
541     if (el->el_line.cursor == el->el_line.lastchar)
542 	return CC_ERROR;
543 
544     el->el_line.cursor = cv__endword(el->el_line.cursor, el->el_line.lastchar,
545 				     el->el_state.argument);
546 
547     if (el->el_chared.c_vcmd.action & DELETE) {
548 	el->el_line.cursor++;
549 	cv_delfini(el);
550 	return CC_REFRESH;
551     }
552 
553     return CC_CURSOR;
554 }
555 
556 
557 /* vi_undo():
558  *	Vi undo last change
559  *	[u]
560  */
561 protected el_action_t
562 /*ARGSUSED*/
563 vi_undo(el, c)
564     EditLine *el;
565     int c;
566 {
567     char *cp, *kp;
568     char temp;
569     int	 i, size;
570     c_undo_t *un = &el->el_chared.c_undo;
571 
572 #ifdef DEBUG_UNDO
573     (void) fprintf(el->el_errfile, "Undo: %x \"%s\" +%d -%d\n",
574 		   un->action, un->buf, un->isize, un->dsize);
575 #endif
576     switch (un->action) {
577     case DELETE:
578 	if (un->dsize == 0)
579 	    return CC_NORM;
580 
581 	(void) memcpy(un->buf, un->ptr, un->dsize);
582 	for (cp = un->ptr; cp <= el->el_line.lastchar; cp++)
583 	    *cp = cp[un->dsize];
584 
585 	el->el_line.lastchar -= un->dsize;
586 	el->el_line.cursor   =  un->ptr;
587 
588 	un->action = INSERT;
589 	un->isize = un->dsize;
590 	un->dsize = 0;
591 	break;
592 
593     case DELETE|INSERT:
594 	size = un->isize - un->dsize;
595 	if (size > 0)
596 	    i = un->dsize;
597 	else
598 	    i = un->isize;
599 	cp = un->ptr;
600 	kp = un->buf;
601 	while (i-- > 0) {
602 	    temp = *kp;
603 	    *kp++ = *cp;
604 	    *cp++ = temp;
605 	}
606 	if (size > 0) {
607 	    el->el_line.cursor = cp;
608 	    c_insert(el, size);
609 	    while (size-- > 0 && cp < el->el_line.lastchar) {
610 		temp = *kp;
611 		*kp++ = *cp;
612 		*cp++ = temp;
613 	    }
614 	}
615 	else if (size < 0) {
616 	    size = -size;
617 	    for (; cp <= el->el_line.lastchar; cp++) {
618 		*kp++ = *cp;
619 		*cp = cp[size];
620 	    }
621 	    el->el_line.lastchar -= size;
622 	}
623 	el->el_line.cursor = un->ptr;
624 	i = un->dsize;
625 	un->dsize = un->isize;
626 	un->isize = i;
627 	break;
628 
629     case INSERT:
630 	if (un->isize == 0)
631 	    return CC_NORM;
632 
633 	el->el_line.cursor = un->ptr;
634 	c_insert(el, un->isize);
635 	memcpy(un->ptr, un->buf, un->isize);
636 	un->action = DELETE;
637 	un->dsize = un->isize;
638 	un->isize = 0;
639 	break;
640 
641     case CHANGE:
642 	if (un->isize == 0)
643 	    return CC_NORM;
644 
645 	el->el_line.cursor = un->ptr;
646 	size = (int) (el->el_line.cursor - el->el_line.lastchar);
647 	if (size < un->isize)
648 	    size = un->isize;
649 	cp = un->ptr;
650 	kp = un->buf;
651 	for(i = 0; i < size; i++) {
652 	    temp = *kp;
653 	    *kp++ = *cp;
654 	    *cp++ = temp;
655 	}
656 	un->dsize = 0;
657 	break;
658 
659     default:
660 	return CC_ERROR;
661     }
662 
663     return CC_REFRESH;
664 }
665 
666 
667 /* vi_command_mode():
668  *	Vi enter command mode (use alternative key bindings)
669  *	[<ESC>]
670  */
671 protected el_action_t
672 /*ARGSUSED*/
673 vi_command_mode(el, c)
674     EditLine *el;
675     int c;
676 {
677     int size;
678     /* [Esc] cancels pending action */
679     el->el_chared.c_vcmd.ins = 0;
680     el->el_chared.c_vcmd.action = NOP;
681     el->el_chared.c_vcmd.pos = 0;
682 
683     el->el_state.doingarg = 0;
684     size = el->el_chared.c_undo.ptr - el->el_line.cursor;
685     if (size < 0)
686 	size = -size;
687     if (el->el_chared.c_undo.action == (INSERT|DELETE) ||
688         el->el_chared.c_undo.action == DELETE)
689 	el->el_chared.c_undo.dsize = size;
690     else
691 	el->el_chared.c_undo.isize = size;
692 
693     el->el_state.inputmode = MODE_INSERT;
694     el->el_map.current = el->el_map.alt;
695 #ifdef VI_MOVE
696     if (el->el_line.cursor > el->el_line.buffer)
697 	el->el_line.cursor--;
698 #endif
699     return CC_CURSOR;
700 }
701 
702 /* vi_zero():
703  *	Vi move to the beginning of line
704  *	[0]
705  */
706 protected el_action_t
707 vi_zero(el, c)
708     EditLine *el;
709     int c;
710 {
711     if (el->el_state.doingarg) {
712 	if (el->el_state.argument > 1000000)
713 	    return CC_ERROR;
714 	el->el_state.argument =
715 		(el->el_state.argument * 10) + (c - '0');
716 	return CC_ARGHACK;
717     }
718     else {
719 	el->el_line.cursor = el->el_line.buffer;
720 	if (el->el_chared.c_vcmd.action & DELETE) {
721 	   cv_delfini(el);
722 	   return CC_REFRESH;
723         }
724 	return CC_CURSOR;
725     }
726 }
727 
728 
729 /* vi_delete_prev_char():
730  * 	Vi move to previous character (backspace)
731  *	[^H]
732  */
733 protected el_action_t
734 /*ARGSUSED*/
735 vi_delete_prev_char(el, c)
736     EditLine *el;
737     int c;
738 {
739     if (el->el_chared.c_vcmd.ins == 0)
740 	return CC_ERROR;
741 
742     if (el->el_chared.c_vcmd.ins >
743 	el->el_line.cursor - el->el_state.argument)
744 	return CC_ERROR;
745 
746     c_delbefore(el, el->el_state.argument);
747     el->el_line.cursor -= el->el_state.argument;
748 
749     return CC_REFRESH;
750 } /* end v_del_char_prev  */
751 
752 
753 /* vi_list_or_eof():
754  *	Vi list choices for completion or indicate end of file if empty line
755  *	[^D]
756  */
757 protected el_action_t
758 /*ARGSUSED*/
759 vi_list_or_eof(el, c)
760     EditLine *el;
761     int c;
762 {
763 #ifdef notyet
764     if (el->el_line.cursor == el->el_line.lastchar &&
765 	el->el_line.cursor == el->el_line.buffer) {
766 #endif
767 	term_overwrite(el, STReof, 4);	/* then do a EOF */
768 	term__flush();
769 	return CC_EOF;
770 #ifdef notyet
771     }
772     else {
773 	re_goto_bottom(el);
774 	*el->el_line.lastchar = '\0';	/* just in case */
775 	return CC_LIST_CHOICES;
776     }
777 #endif
778 }
779 
780 
781 /* vi_kill_line_prev():
782  *	Vi cut from beginning of line to cursor
783  *	[^U]
784  */
785 protected el_action_t
786 /*ARGSUSED*/
787 vi_kill_line_prev(el, c)
788     EditLine *el;
789     int c;
790 {
791     char *kp, *cp;
792 
793     cp = el->el_line.buffer;
794     kp = el->el_chared.c_kill.buf;
795     while (cp < el->el_line.cursor)
796 	*kp++ = *cp++;		/* copy it */
797     el->el_chared.c_kill.last = kp;
798     c_delbefore(el, el->el_line.cursor - el->el_line.buffer);
799     el->el_line.cursor = el->el_line.buffer;		/* zap! */
800     return CC_REFRESH;
801 }
802 
803 
804 /* vi_search_prev():
805  *	Vi search history previous
806  *	[?]
807  */
808 protected el_action_t
809 /*ARGSUSED*/
810 vi_search_prev(el, c)
811     EditLine *el;
812     int c;
813 {
814     return cv_search(el, ED_SEARCH_PREV_HISTORY);
815 }
816 
817 
818 /* vi_search_next():
819  *	Vi search history next
820  *	[/]
821  */
822 protected el_action_t
823 /*ARGSUSED*/
824 vi_search_next(el, c)
825     EditLine *el;
826     int c;
827 {
828     return cv_search(el, ED_SEARCH_NEXT_HISTORY);
829 }
830 
831 
832 /* vi_repeat_search_next():
833  *	Vi repeat current search in the same search direction
834  *	[n]
835  */
836 protected el_action_t
837 /*ARGSUSED*/
838 vi_repeat_search_next(el, c)
839     EditLine *el;
840     int c;
841 {
842     if (el->el_search.patlen == 0)
843 	return CC_ERROR;
844     else
845 	return cv_repeat_srch(el, el->el_search.patdir);
846 }
847 
848 
849 /* vi_repeat_search_prev():
850  *	Vi repeat current search in the opposite search direction
851  *	[N]
852  */
853 /*ARGSUSED*/
854 protected el_action_t
855 vi_repeat_search_prev(el, c)
856     EditLine *el;
857     int c;
858 {
859     if (el->el_search.patlen == 0)
860 	return CC_ERROR;
861     else
862 	return cv_repeat_srch(el,
863 			      el->el_search.patdir == ED_SEARCH_PREV_HISTORY ?
864 			      ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY);
865 }
866 
867 
868 /* vi_next_char():
869  *	Vi move to the character specified next
870  *	[f]
871  */
872 protected el_action_t
873 /*ARGSUSED*/
874 vi_next_char(el, c)
875     EditLine *el;
876     int c;
877 {
878     char ch;
879 
880     if (el_getc(el, &ch) != 1)
881 	return ed_end_of_file(el, 0);
882 
883     el->el_search.chadir = CHAR_FWD;
884     el->el_search.chacha = ch;
885 
886     return cv_csearch_fwd(el, ch, el->el_state.argument, 0);
887 
888 }
889 
890 
891 /* vi_prev_char():
892  *	Vi move to the character specified previous
893  *	[F]
894  */
895 protected el_action_t
896 /*ARGSUSED*/
897 vi_prev_char(el, c)
898     EditLine *el;
899     int c;
900 {
901     char ch;
902 
903     if (el_getc(el, &ch) != 1)
904 	return ed_end_of_file(el, 0);
905 
906     el->el_search.chadir = CHAR_BACK;
907     el->el_search.chacha = ch;
908 
909     return cv_csearch_back(el, ch, el->el_state.argument, 0);
910 }
911 
912 
913 /* vi_to_next_char():
914  *	Vi move up to the character specified next
915  *	[t]
916  */
917 protected el_action_t
918 /*ARGSUSED*/
919 vi_to_next_char(el, c)
920     EditLine *el;
921     int c;
922 {
923     char ch;
924 
925     if (el_getc(el, &ch) != 1)
926 	return ed_end_of_file(el, 0);
927 
928     return cv_csearch_fwd(el, ch, el->el_state.argument, 1);
929 
930 }
931 
932 
933 /* vi_to_prev_char():
934  *	Vi move up to the character specified previous
935  *	[T]
936  */
937 protected el_action_t
938 /*ARGSUSED*/
939 vi_to_prev_char(el, c)
940     EditLine *el;
941     int c;
942 {
943     char ch;
944     if (el_getc(el, &ch) != 1)
945 	return ed_end_of_file(el, 0);
946 
947     return cv_csearch_back(el, ch, el->el_state.argument, 1);
948 }
949 
950 
951 /* vi_repeat_next_char():
952  *	Vi repeat current character search in the same search direction
953  *	[;]
954  */
955 protected el_action_t
956 /*ARGSUSED*/
957 vi_repeat_next_char(el, c)
958     EditLine *el;
959     int c;
960 {
961     if (el->el_search.chacha == 0)
962 	return CC_ERROR;
963 
964     return el->el_search.chadir == CHAR_FWD ?
965 	cv_csearch_fwd(el, el->el_search.chacha, el->el_state.argument, 0) :
966         cv_csearch_back(el, el->el_search.chacha, el->el_state.argument, 0);
967 }
968 
969 
970 /* vi_repeat_prev_char():
971  *	Vi repeat current character search in the opposite search direction
972  *	[,]
973  */
974 protected el_action_t
975 /*ARGSUSED*/
976 vi_repeat_prev_char(el, c)
977     EditLine *el;
978     int c;
979 {
980     if (el->el_search.chacha == 0)
981 	return CC_ERROR;
982 
983     return el->el_search.chadir == CHAR_BACK ?
984 	cv_csearch_fwd(el, el->el_search.chacha, el->el_state.argument, 0) :
985         cv_csearch_back(el, el->el_search.chacha, el->el_state.argument, 0);
986 }
987