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