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