vi.c revision 37199
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)
38static 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
47private el_action_t cv_action __P((EditLine *, int));
48
49/* cv_action():
50 *	Handle vi actions.
51 */
52private el_action_t
53cv_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 */
106protected el_action_t
107cv_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 */
136protected el_action_t
137/*ARGSUSED*/
138vi_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 */
150protected el_action_t
151/*ARGSUSED*/
152vi_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 */
164protected el_action_t
165/*ARGSUSED*/
166vi_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				      c___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 */
191protected el_action_t
192/*ARGSUSED*/
193vi_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				      cv__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 */
218protected el_action_t
219/*ARGSUSED*/
220vi_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				      c___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 */
245protected el_action_t
246/*ARGSUSED*/
247vi_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				      cv__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 */
274protected el_action_t
275vi_change_case(el, c)
276    EditLine *el;
277    int c;
278{
279    if (el->el_line.cursor < el->el_line.lastchar) {
280	c = (unsigned char)*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 */
298protected el_action_t
299/*ARGSUSED*/
300vi_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 */
316protected el_action_t
317/*ARGSUSED*/
318vi_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 */
337protected el_action_t
338/*ARGSUSED*/
339vi_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_ARGHACK;
350}
351
352
353/* vi_replace_mode():
354 *	Vi enter replace mode
355 *	[R]
356 */
357protected el_action_t
358/*ARGSUSED*/
359vi_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_ARGHACK;
370}
371
372
373/* vi_substitute_char():
374 *	Vi replace character under the cursor and enter insert mode
375 *	[s]
376 */
377protected el_action_t
378/*ARGSUSED*/
379vi_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 */
393protected el_action_t
394/*ARGSUSED*/
395vi_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 */
409protected el_action_t
410/*ARGSUSED*/
411vi_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 */
425protected el_action_t
426/*ARGSUSED*/
427vi_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 */
445protected el_action_t
446/*ARGSUSED*/
447vi_add(el, c)
448    EditLine *el;
449    int c;
450{
451    el_action_t ret;
452
453    el->el_map.current = el->el_map.key;
454    if (el->el_line.cursor < el->el_line.lastchar) {
455	el->el_line.cursor++;
456	if (el->el_line.cursor > el->el_line.lastchar)
457	    el->el_line.cursor = el->el_line.lastchar;
458	ret = CC_CURSOR;
459    }
460    else
461	ret = CC_NORM;
462
463    el->el_chared.c_vcmd.ins = el->el_line.cursor;
464    el->el_chared.c_undo.ptr = el->el_line.cursor;
465    el->el_chared.c_undo.action = DELETE;
466
467    return ret;
468}
469
470
471/* vi_add_at_eol():
472 *	Vi enter insert mode at end of line
473 *	[A]
474 */
475protected el_action_t
476/*ARGSUSED*/
477vi_add_at_eol(el, c)
478    EditLine *el;
479    int c;
480{
481    el->el_map.current = el->el_map.key;
482    el->el_line.cursor = el->el_line.lastchar;
483
484    /* Mark where insertion begins */
485    el->el_chared.c_vcmd.ins = el->el_line.lastchar;
486    el->el_chared.c_undo.ptr = el->el_line.lastchar;
487    el->el_chared.c_undo.action = DELETE;
488    return CC_CURSOR;
489}
490
491
492/* vi_delete_meta():
493 *	Vi delete prefix command
494 *	[d]
495 */
496protected el_action_t
497/*ARGSUSED*/
498vi_delete_meta(el, c)
499    EditLine *el;
500    int c;
501{
502    return cv_action(el, DELETE);
503}
504
505
506/* vi_end_word():
507 *	Vi move to the end of the current space delimited word
508 *	[E]
509 */
510protected el_action_t
511/*ARGSUSED*/
512vi_end_word(el, c)
513    EditLine *el;
514    int c;
515{
516    if (el->el_line.cursor == el->el_line.lastchar)
517	return CC_ERROR;
518
519    el->el_line.cursor = cv__endword(el->el_line.cursor, el->el_line.lastchar,
520				     el->el_state.argument);
521
522    if (el->el_chared.c_vcmd.action & DELETE) {
523	el->el_line.cursor++;
524	cv_delfini(el);
525	return CC_REFRESH;
526    }
527
528    return CC_CURSOR;
529}
530
531
532/* vi_to_end_word():
533 *	Vi move to the end of the current word
534 *	[e]
535 */
536protected el_action_t
537/*ARGSUSED*/
538vi_to_end_word(el, c)
539    EditLine *el;
540    int c;
541{
542    if (el->el_line.cursor == el->el_line.lastchar)
543	return CC_ERROR;
544
545    el->el_line.cursor = cv__endword(el->el_line.cursor, el->el_line.lastchar,
546				     el->el_state.argument);
547
548    if (el->el_chared.c_vcmd.action & DELETE) {
549	el->el_line.cursor++;
550	cv_delfini(el);
551	return CC_REFRESH;
552    }
553
554    return CC_CURSOR;
555}
556
557
558/* vi_undo():
559 *	Vi undo last change
560 *	[u]
561 */
562protected el_action_t
563/*ARGSUSED*/
564vi_undo(el, c)
565    EditLine *el;
566    int c;
567{
568    char *cp, *kp;
569    char temp;
570    int	 i, size;
571    c_undo_t *un = &el->el_chared.c_undo;
572
573#ifdef DEBUG_UNDO
574    (void) fprintf(el->el_errfile, "Undo: %x \"%s\" +%d -%d\n",
575		   un->action, un->buf, un->isize, un->dsize);
576#endif
577    switch (un->action) {
578    case DELETE:
579	if (un->dsize == 0)
580	    return CC_NORM;
581
582	(void) memcpy(un->buf, un->ptr, un->dsize);
583	for (cp = un->ptr; cp <= el->el_line.lastchar; cp++)
584	    *cp = cp[un->dsize];
585
586	el->el_line.lastchar -= un->dsize;
587	el->el_line.cursor   =  un->ptr;
588
589	un->action = INSERT;
590	un->isize = un->dsize;
591	un->dsize = 0;
592	break;
593
594    case DELETE|INSERT:
595	size = un->isize - un->dsize;
596	if (size > 0)
597	    i = un->dsize;
598	else
599	    i = un->isize;
600	cp = un->ptr;
601	kp = un->buf;
602	while (i-- > 0) {
603	    temp = *kp;
604	    *kp++ = *cp;
605	    *cp++ = temp;
606	}
607	if (size > 0) {
608	    el->el_line.cursor = cp;
609	    c_insert(el, size);
610	    while (size-- > 0 && cp < el->el_line.lastchar) {
611		temp = *kp;
612		*kp++ = *cp;
613		*cp++ = temp;
614	    }
615	}
616	else if (size < 0) {
617	    size = -size;
618	    for (; cp <= el->el_line.lastchar; cp++) {
619		*kp++ = *cp;
620		*cp = cp[size];
621	    }
622	    el->el_line.lastchar -= size;
623	}
624	el->el_line.cursor = un->ptr;
625	i = un->dsize;
626	un->dsize = un->isize;
627	un->isize = i;
628	break;
629
630    case INSERT:
631	if (un->isize == 0)
632	    return CC_NORM;
633
634	el->el_line.cursor = un->ptr;
635	c_insert(el, un->isize);
636	memcpy(un->ptr, un->buf, un->isize);
637	un->action = DELETE;
638	un->dsize = un->isize;
639	un->isize = 0;
640	break;
641
642    case CHANGE:
643	if (un->isize == 0)
644	    return CC_NORM;
645
646	el->el_line.cursor = un->ptr;
647	size = (int) (el->el_line.cursor - el->el_line.lastchar);
648	if (size < un->isize)
649	    size = un->isize;
650	cp = un->ptr;
651	kp = un->buf;
652	for(i = 0; i < size; i++) {
653	    temp = *kp;
654	    *kp++ = *cp;
655	    *cp++ = temp;
656	}
657	un->dsize = 0;
658	break;
659
660    default:
661	return CC_ERROR;
662    }
663
664    return CC_REFRESH;
665}
666
667
668/* vi_undo_line():
669 *	Vi undo all changes
670 *	[U]
671 */
672protected el_action_t
673/*ARGSUSED*/
674vi_undo_line(el, c)
675    EditLine *el;
676    int c;
677{
678
679    return hist_get(el);
680}
681
682
683/* vi_command_mode():
684 *	Vi enter command mode (use alternative key bindings)
685 *	[<ESC>]
686 */
687protected el_action_t
688/*ARGSUSED*/
689vi_command_mode(el, c)
690    EditLine *el;
691    int c;
692{
693    int size;
694    /* [Esc] cancels pending action */
695    el->el_chared.c_vcmd.ins = 0;
696    el->el_chared.c_vcmd.action = NOP;
697    el->el_chared.c_vcmd.pos = 0;
698
699    el->el_state.doingarg = 0;
700    size = el->el_chared.c_undo.ptr - el->el_line.cursor;
701    if (size < 0)
702	size = -size;
703    if (el->el_chared.c_undo.action == (INSERT|DELETE) ||
704        el->el_chared.c_undo.action == DELETE)
705	el->el_chared.c_undo.dsize = size;
706    else
707	el->el_chared.c_undo.isize = size;
708
709    el->el_state.inputmode = MODE_INSERT;
710    el->el_map.current = el->el_map.alt;
711#ifdef VI_MOVE
712    if (el->el_line.cursor > el->el_line.buffer)
713	el->el_line.cursor--;
714#endif
715    return CC_CURSOR;
716}
717
718/* vi_zero():
719 *	Vi move to the beginning of line
720 *	[0]
721 */
722protected el_action_t
723vi_zero(el, c)
724    EditLine *el;
725    int c;
726{
727    if (el->el_state.doingarg) {
728	if (el->el_state.argument > 1000000)
729	    return CC_ERROR;
730	el->el_state.argument =
731		(el->el_state.argument * 10) + (c - '0');
732	return CC_ARGHACK;
733    }
734    else {
735	el->el_line.cursor = el->el_line.buffer;
736	if (el->el_chared.c_vcmd.action & DELETE) {
737	   cv_delfini(el);
738	   return CC_REFRESH;
739        }
740	return CC_CURSOR;
741    }
742}
743
744
745/* vi_delete_prev_char():
746 * 	Vi move to previous character (backspace)
747 *	[^H]
748 */
749protected el_action_t
750/*ARGSUSED*/
751vi_delete_prev_char(el, c)
752    EditLine *el;
753    int c;
754{
755    if (el->el_chared.c_vcmd.ins == 0)
756	return CC_ERROR;
757
758    if (el->el_chared.c_vcmd.ins >
759	el->el_line.cursor - el->el_state.argument)
760	return CC_ERROR;
761
762    c_delbefore(el, el->el_state.argument);
763    el->el_line.cursor -= el->el_state.argument;
764
765    return CC_REFRESH;
766} /* end v_del_char_prev  */
767
768
769/* vi_list_or_eof():
770 *	Vi list choices for completion or indicate end of file if empty line
771 *	[^D]
772 */
773protected el_action_t
774/*ARGSUSED*/
775vi_list_or_eof(el, c)
776    EditLine *el;
777    int c;
778{
779#ifdef notyet
780    if (el->el_line.cursor == el->el_line.lastchar &&
781	el->el_line.cursor == el->el_line.buffer) {
782#endif
783	term_overwrite(el, STReof, 4);	/* then do a EOF */
784	term__flush();
785	return CC_EOF;
786#ifdef notyet
787    }
788    else {
789	re_goto_bottom(el);
790	*el->el_line.lastchar = '\0';	/* just in case */
791	return CC_LIST_CHOICES;
792    }
793#endif
794}
795
796
797/* vi_kill_line_prev():
798 *	Vi cut from beginning of line to cursor
799 *	[^U]
800 */
801protected el_action_t
802/*ARGSUSED*/
803vi_kill_line_prev(el, c)
804    EditLine *el;
805    int c;
806{
807    char *kp, *cp;
808
809    cp = el->el_line.buffer;
810    kp = el->el_chared.c_kill.buf;
811    while (cp < el->el_line.cursor)
812	*kp++ = *cp++;		/* copy it */
813    el->el_chared.c_kill.last = kp;
814    c_delbefore(el, el->el_line.cursor - el->el_line.buffer);
815    el->el_line.cursor = el->el_line.buffer;		/* zap! */
816    return CC_REFRESH;
817}
818
819
820/* vi_search_prev():
821 *	Vi search history previous
822 *	[?]
823 */
824protected el_action_t
825/*ARGSUSED*/
826vi_search_prev(el, c)
827    EditLine *el;
828    int c;
829{
830    return cv_search(el, ED_SEARCH_PREV_HISTORY);
831}
832
833
834/* vi_search_next():
835 *	Vi search history next
836 *	[/]
837 */
838protected el_action_t
839/*ARGSUSED*/
840vi_search_next(el, c)
841    EditLine *el;
842    int c;
843{
844    return cv_search(el, ED_SEARCH_NEXT_HISTORY);
845}
846
847
848/* vi_repeat_search_next():
849 *	Vi repeat current search in the same search direction
850 *	[n]
851 */
852protected el_action_t
853/*ARGSUSED*/
854vi_repeat_search_next(el, c)
855    EditLine *el;
856    int c;
857{
858    if (el->el_search.patlen == 0)
859	return CC_ERROR;
860    else
861	return cv_repeat_srch(el, el->el_search.patdir);
862}
863
864
865/* vi_repeat_search_prev():
866 *	Vi repeat current search in the opposite search direction
867 *	[N]
868 */
869/*ARGSUSED*/
870protected el_action_t
871vi_repeat_search_prev(el, c)
872    EditLine *el;
873    int c;
874{
875    if (el->el_search.patlen == 0)
876	return CC_ERROR;
877    else
878	return cv_repeat_srch(el,
879			      el->el_search.patdir == ED_SEARCH_PREV_HISTORY ?
880			      ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY);
881}
882
883
884/* vi_next_char():
885 *	Vi move to the character specified next
886 *	[f]
887 */
888protected el_action_t
889/*ARGSUSED*/
890vi_next_char(el, c)
891    EditLine *el;
892    int c;
893{
894    char ch;
895
896    if (el_getc(el, &ch) != 1)
897	return ed_end_of_file(el, 0);
898
899    el->el_search.chadir = CHAR_FWD;
900    el->el_search.chacha = ch;
901
902    return cv_csearch_fwd(el, ch, el->el_state.argument, 0);
903
904}
905
906
907/* vi_prev_char():
908 *	Vi move to the character specified previous
909 *	[F]
910 */
911protected el_action_t
912/*ARGSUSED*/
913vi_prev_char(el, c)
914    EditLine *el;
915    int c;
916{
917    char ch;
918
919    if (el_getc(el, &ch) != 1)
920	return ed_end_of_file(el, 0);
921
922    el->el_search.chadir = CHAR_BACK;
923    el->el_search.chacha = ch;
924
925    return cv_csearch_back(el, ch, el->el_state.argument, 0);
926}
927
928
929/* vi_to_next_char():
930 *	Vi move up to the character specified next
931 *	[t]
932 */
933protected el_action_t
934/*ARGSUSED*/
935vi_to_next_char(el, c)
936    EditLine *el;
937    int c;
938{
939    char ch;
940
941    if (el_getc(el, &ch) != 1)
942	return ed_end_of_file(el, 0);
943
944    return cv_csearch_fwd(el, ch, el->el_state.argument, 1);
945
946}
947
948
949/* vi_to_prev_char():
950 *	Vi move up to the character specified previous
951 *	[T]
952 */
953protected el_action_t
954/*ARGSUSED*/
955vi_to_prev_char(el, c)
956    EditLine *el;
957    int c;
958{
959    char ch;
960    if (el_getc(el, &ch) != 1)
961	return ed_end_of_file(el, 0);
962
963    return cv_csearch_back(el, ch, el->el_state.argument, 1);
964}
965
966
967/* vi_repeat_next_char():
968 *	Vi repeat current character search in the same search direction
969 *	[;]
970 */
971protected el_action_t
972/*ARGSUSED*/
973vi_repeat_next_char(el, c)
974    EditLine *el;
975    int c;
976{
977    if (el->el_search.chacha == 0)
978	return CC_ERROR;
979
980    return el->el_search.chadir == CHAR_FWD ?
981	cv_csearch_fwd(el, el->el_search.chacha, el->el_state.argument, 0) :
982        cv_csearch_back(el, el->el_search.chacha, el->el_state.argument, 0);
983}
984
985
986/* vi_repeat_prev_char():
987 *	Vi repeat current character search in the opposite search direction
988 *	[,]
989 */
990protected el_action_t
991/*ARGSUSED*/
992vi_repeat_prev_char(el, c)
993    EditLine *el;
994    int c;
995{
996    if (el->el_search.chacha == 0)
997	return CC_ERROR;
998
999    return el->el_search.chadir == CHAR_BACK ?
1000	cv_csearch_fwd(el, el->el_search.chacha, el->el_state.argument, 0) :
1001        cv_csearch_back(el, el->el_search.chacha, el->el_state.argument, 0);
1002}
1003