xref: /netbsd-src/lib/libedit/vi.c (revision 6cac535e1778c7ad8537c11a918d674465c204ae)
1*6cac535eSchristos /*	$NetBSD: vi.c,v 1.64 2021/08/28 17:17:47 christos Exp $	*/
22543e3e6Slukem 
36dc2f1dbScgd /*-
46dc2f1dbScgd  * Copyright (c) 1992, 1993
56dc2f1dbScgd  *	The Regents of the University of California.  All rights reserved.
66dc2f1dbScgd  *
76dc2f1dbScgd  * This code is derived from software contributed to Berkeley by
86dc2f1dbScgd  * Christos Zoulas of Cornell University.
96dc2f1dbScgd  *
106dc2f1dbScgd  * Redistribution and use in source and binary forms, with or without
116dc2f1dbScgd  * modification, are permitted provided that the following conditions
126dc2f1dbScgd  * are met:
136dc2f1dbScgd  * 1. Redistributions of source code must retain the above copyright
146dc2f1dbScgd  *    notice, this list of conditions and the following disclaimer.
156dc2f1dbScgd  * 2. Redistributions in binary form must reproduce the above copyright
166dc2f1dbScgd  *    notice, this list of conditions and the following disclaimer in the
176dc2f1dbScgd  *    documentation and/or other materials provided with the distribution.
18eb7c1594Sagc  * 3. Neither the name of the University nor the names of its contributors
196dc2f1dbScgd  *    may be used to endorse or promote products derived from this software
206dc2f1dbScgd  *    without specific prior written permission.
216dc2f1dbScgd  *
226dc2f1dbScgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
236dc2f1dbScgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
246dc2f1dbScgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
256dc2f1dbScgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
266dc2f1dbScgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
276dc2f1dbScgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
286dc2f1dbScgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
296dc2f1dbScgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
306dc2f1dbScgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
316dc2f1dbScgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
326dc2f1dbScgd  * SUCH DAMAGE.
336dc2f1dbScgd  */
346dc2f1dbScgd 
350e0ac6b7Schristos #include "config.h"
366dc2f1dbScgd #if !defined(lint) && !defined(SCCSID)
372543e3e6Slukem #if 0
386dc2f1dbScgd static char sccsid[] = "@(#)vi.c	8.1 (Berkeley) 6/4/93";
392543e3e6Slukem #else
40*6cac535eSchristos __RCSID("$NetBSD: vi.c,v 1.64 2021/08/28 17:17:47 christos Exp $");
412543e3e6Slukem #endif
426dc2f1dbScgd #endif /* not lint && not SCCSID */
436dc2f1dbScgd 
446dc2f1dbScgd /*
456dc2f1dbScgd  * vi.c: Vi mode commands.
466dc2f1dbScgd  */
47e84df91eSchristos #include <sys/wait.h>
48e84df91eSchristos #include <ctype.h>
49e84df91eSchristos #include <limits.h>
50e84df91eSchristos #include <stdlib.h>
51e84df91eSchristos #include <string.h>
52e84df91eSchristos #include <unistd.h>
53e84df91eSchristos 
546dc2f1dbScgd #include "el.h"
55747f6811Schristos #include "common.h"
56747f6811Schristos #include "emacs.h"
574fc1f47dSchristos #include "fcns.h"
58747f6811Schristos #include "vi.h"
596dc2f1dbScgd 
60469d44f8Schristos static el_action_t	cv_action(EditLine *, wint_t);
61469d44f8Schristos static el_action_t	cv_paste(EditLine *, wint_t);
626dc2f1dbScgd 
636dc2f1dbScgd /* cv_action():
646dc2f1dbScgd  *	Handle vi actions.
656dc2f1dbScgd  */
66469d44f8Schristos static el_action_t
cv_action(EditLine * el,wint_t c)67f54e4f97Schristos cv_action(EditLine *el, wint_t c)
686dc2f1dbScgd {
696dc2f1dbScgd 
7039f224afSchristos 	if (el->el_chared.c_vcmd.action != NOP) {
7139f224afSchristos 		/* 'cc', 'dd' and (possibly) friends */
72f54e4f97Schristos 		if (c != (wint_t)el->el_chared.c_vcmd.action)
7339f224afSchristos 			return CC_ERROR;
7439f224afSchristos 
7539f224afSchristos 		if (!(c & YANK))
7639f224afSchristos 			cv_undo(el);
7739f224afSchristos 		cv_yank(el, el->el_line.buffer,
785c894153Schristos 		    (int)(el->el_line.lastchar - el->el_line.buffer));
796dc2f1dbScgd 		el->el_chared.c_vcmd.action = NOP;
806dc2f1dbScgd 		el->el_chared.c_vcmd.pos = 0;
81fda9b4f7Schristos 		if (!(c & YANK)) {
826dc2f1dbScgd 			el->el_line.lastchar = el->el_line.buffer;
836dc2f1dbScgd 			el->el_line.cursor = el->el_line.buffer;
84fda9b4f7Schristos 		}
856dc2f1dbScgd 		if (c & INSERT)
866dc2f1dbScgd 			el->el_map.current = el->el_map.key;
876dc2f1dbScgd 
88b71bed95Schristos 		return CC_REFRESH;
896dc2f1dbScgd 	}
906dc2f1dbScgd 	el->el_chared.c_vcmd.pos = el->el_line.cursor;
916dc2f1dbScgd 	el->el_chared.c_vcmd.action = c;
92b71bed95Schristos 	return CC_ARGHACK;
936dc2f1dbScgd }
946dc2f1dbScgd 
956dc2f1dbScgd /* cv_paste():
966dc2f1dbScgd  *	Paste previous deletion before or after the cursor
976dc2f1dbScgd  */
98469d44f8Schristos static el_action_t
cv_paste(EditLine * el,wint_t c)99f54e4f97Schristos cv_paste(EditLine *el, wint_t c)
1006dc2f1dbScgd {
10139f224afSchristos 	c_kill_t *k = &el->el_chared.c_kill;
102954af9bbSchristos 	size_t len = (size_t)(k->last - k->buf);
103d30d584aSlukem 
10439f224afSchristos 	if (k->buf == NULL || len == 0)
105b71bed95Schristos 		return CC_ERROR;
10639f224afSchristos #ifdef DEBUG_PASTE
107fcf85103Schristos 	(void) fprintf(el->el_errfile, "Paste: \"%.*ls\"\n", (int)len,
108d784c575Schristos 	    k->buf);
10939f224afSchristos #endif
1106dc2f1dbScgd 
11139f224afSchristos 	cv_undo(el);
112a17c7fe4Schristos 
1136dc2f1dbScgd 	if (!c && el->el_line.cursor < el->el_line.lastchar)
1146dc2f1dbScgd 		el->el_line.cursor++;
1156dc2f1dbScgd 
116954af9bbSchristos 	c_insert(el, (int)len);
11739f224afSchristos 	if (el->el_line.cursor + len > el->el_line.lastchar)
118b71bed95Schristos 		return CC_ERROR;
11934e53048Schristos 	(void) memcpy(el->el_line.cursor, k->buf, len *
12034e53048Schristos 	    sizeof(*el->el_line.cursor));
12155ca57f0Schristos 
122b71bed95Schristos 	return CC_REFRESH;
1236dc2f1dbScgd }
1246dc2f1dbScgd 
1256dc2f1dbScgd 
1266dc2f1dbScgd /* vi_paste_next():
1276dc2f1dbScgd  *	Vi paste previous deletion to the right of the cursor
1286dc2f1dbScgd  *	[p]
1296dc2f1dbScgd  */
130a2d6b270Schristos libedit_private el_action_t
1316dc2f1dbScgd /*ARGSUSED*/
vi_paste_next(EditLine * el,wint_t c)132f54e4f97Schristos vi_paste_next(EditLine *el, wint_t c __attribute__((__unused__)))
1336dc2f1dbScgd {
134d30d584aSlukem 
135b71bed95Schristos 	return cv_paste(el, 0);
1366dc2f1dbScgd }
1376dc2f1dbScgd 
1386dc2f1dbScgd 
1396dc2f1dbScgd /* vi_paste_prev():
1406dc2f1dbScgd  *	Vi paste previous deletion to the left of the cursor
1416dc2f1dbScgd  *	[P]
1426dc2f1dbScgd  */
143a2d6b270Schristos libedit_private el_action_t
1446dc2f1dbScgd /*ARGSUSED*/
vi_paste_prev(EditLine * el,wint_t c)145f54e4f97Schristos vi_paste_prev(EditLine *el, wint_t c __attribute__((__unused__)))
1466dc2f1dbScgd {
147d30d584aSlukem 
148b71bed95Schristos 	return cv_paste(el, 1);
1496dc2f1dbScgd }
1506dc2f1dbScgd 
1516dc2f1dbScgd 
152a17c7fe4Schristos /* vi_prev_big_word():
1536dc2f1dbScgd  *	Vi move to the previous space delimited word
1546dc2f1dbScgd  *	[B]
1556dc2f1dbScgd  */
156a2d6b270Schristos libedit_private el_action_t
1576dc2f1dbScgd /*ARGSUSED*/
vi_prev_big_word(EditLine * el,wint_t c)158f54e4f97Schristos vi_prev_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
1596dc2f1dbScgd {
160d30d584aSlukem 
1616dc2f1dbScgd 	if (el->el_line.cursor == el->el_line.buffer)
162b71bed95Schristos 		return CC_ERROR;
1636dc2f1dbScgd 
164a17c7fe4Schristos 	el->el_line.cursor = cv_prev_word(el->el_line.cursor,
1656dc2f1dbScgd 	    el->el_line.buffer,
1666dc2f1dbScgd 	    el->el_state.argument,
167a17c7fe4Schristos 	    cv__isWord);
1686dc2f1dbScgd 
16939f224afSchristos 	if (el->el_chared.c_vcmd.action != NOP) {
1706dc2f1dbScgd 		cv_delfini(el);
171b71bed95Schristos 		return CC_REFRESH;
1726dc2f1dbScgd 	}
173b71bed95Schristos 	return CC_CURSOR;
1746dc2f1dbScgd }
1756dc2f1dbScgd 
1766dc2f1dbScgd 
1776dc2f1dbScgd /* vi_prev_word():
1786dc2f1dbScgd  *	Vi move to the previous word
179a17c7fe4Schristos  *	[b]
1806dc2f1dbScgd  */
181a2d6b270Schristos libedit_private el_action_t
1826dc2f1dbScgd /*ARGSUSED*/
vi_prev_word(EditLine * el,wint_t c)183f54e4f97Schristos vi_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
1846dc2f1dbScgd {
185d30d584aSlukem 
1866dc2f1dbScgd 	if (el->el_line.cursor == el->el_line.buffer)
187b71bed95Schristos 		return CC_ERROR;
1886dc2f1dbScgd 
189a17c7fe4Schristos 	el->el_line.cursor = cv_prev_word(el->el_line.cursor,
1906dc2f1dbScgd 	    el->el_line.buffer,
1916dc2f1dbScgd 	    el->el_state.argument,
192a17c7fe4Schristos 	    cv__isword);
1936dc2f1dbScgd 
19439f224afSchristos 	if (el->el_chared.c_vcmd.action != NOP) {
1956dc2f1dbScgd 		cv_delfini(el);
196b71bed95Schristos 		return CC_REFRESH;
1976dc2f1dbScgd 	}
198b71bed95Schristos 	return CC_CURSOR;
1996dc2f1dbScgd }
2006dc2f1dbScgd 
2016dc2f1dbScgd 
202a17c7fe4Schristos /* vi_next_big_word():
2036dc2f1dbScgd  *	Vi move to the next space delimited word
2046dc2f1dbScgd  *	[W]
2056dc2f1dbScgd  */
206a2d6b270Schristos libedit_private el_action_t
2076dc2f1dbScgd /*ARGSUSED*/
vi_next_big_word(EditLine * el,wint_t c)208f54e4f97Schristos vi_next_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
2096dc2f1dbScgd {
210d30d584aSlukem 
21139f224afSchristos 	if (el->el_line.cursor >= el->el_line.lastchar - 1)
212b71bed95Schristos 		return CC_ERROR;
2136dc2f1dbScgd 
2146dc2f1dbScgd 	el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
21539f224afSchristos 	    el->el_line.lastchar, el->el_state.argument, cv__isWord);
2166dc2f1dbScgd 
2176dc2f1dbScgd 	if (el->el_map.type == MAP_VI)
21839f224afSchristos 		if (el->el_chared.c_vcmd.action != NOP) {
2196dc2f1dbScgd 			cv_delfini(el);
220b71bed95Schristos 			return CC_REFRESH;
221d30d584aSlukem 		}
222b71bed95Schristos 	return CC_CURSOR;
2236dc2f1dbScgd }
2246dc2f1dbScgd 
2256dc2f1dbScgd 
2266dc2f1dbScgd /* vi_next_word():
2276dc2f1dbScgd  *	Vi move to the next word
2286dc2f1dbScgd  *	[w]
2296dc2f1dbScgd  */
230a2d6b270Schristos libedit_private el_action_t
2316dc2f1dbScgd /*ARGSUSED*/
vi_next_word(EditLine * el,wint_t c)232f54e4f97Schristos vi_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
2336dc2f1dbScgd {
234d30d584aSlukem 
23539f224afSchristos 	if (el->el_line.cursor >= el->el_line.lastchar - 1)
236b71bed95Schristos 		return CC_ERROR;
2376dc2f1dbScgd 
2386dc2f1dbScgd 	el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
23939f224afSchristos 	    el->el_line.lastchar, el->el_state.argument, cv__isword);
2406dc2f1dbScgd 
2416dc2f1dbScgd 	if (el->el_map.type == MAP_VI)
24239f224afSchristos 		if (el->el_chared.c_vcmd.action != NOP) {
2436dc2f1dbScgd 			cv_delfini(el);
244b71bed95Schristos 			return CC_REFRESH;
2456dc2f1dbScgd 		}
246b71bed95Schristos 	return CC_CURSOR;
2476dc2f1dbScgd }
2486dc2f1dbScgd 
2496dc2f1dbScgd 
2506dc2f1dbScgd /* vi_change_case():
2516dc2f1dbScgd  *	Vi change case of character under the cursor and advance one character
2526dc2f1dbScgd  *	[~]
2536dc2f1dbScgd  */
254a2d6b270Schristos libedit_private el_action_t
vi_change_case(EditLine * el,wint_t c)255f54e4f97Schristos vi_change_case(EditLine *el, wint_t c)
2566dc2f1dbScgd {
257a17c7fe4Schristos 	int i;
258d30d584aSlukem 
259a17c7fe4Schristos 	if (el->el_line.cursor >= el->el_line.lastchar)
260b71bed95Schristos 		return CC_ERROR;
26139f224afSchristos 	cv_undo(el);
262a17c7fe4Schristos 	for (i = 0; i < el->el_state.argument; i++) {
263a17c7fe4Schristos 
26434e53048Schristos 		c = *el->el_line.cursor;
265fcf85103Schristos 		if (iswupper(c))
266fcf85103Schristos 			*el->el_line.cursor = towlower(c);
267fcf85103Schristos 		else if (iswlower(c))
268fcf85103Schristos 			*el->el_line.cursor = towupper(c);
26939f224afSchristos 
27039f224afSchristos 		if (++el->el_line.cursor >= el->el_line.lastchar) {
27139f224afSchristos 			el->el_line.cursor--;
27239f224afSchristos 			re_fastaddc(el);
27339f224afSchristos 			break;
27439f224afSchristos 		}
2756dc2f1dbScgd 		re_fastaddc(el);
2766dc2f1dbScgd 	}
27739f224afSchristos 	return CC_NORM;
2786dc2f1dbScgd }
2796dc2f1dbScgd 
2806dc2f1dbScgd 
2816dc2f1dbScgd /* vi_change_meta():
2826dc2f1dbScgd  *	Vi change prefix command
2836dc2f1dbScgd  *	[c]
2846dc2f1dbScgd  */
285a2d6b270Schristos libedit_private el_action_t
2866dc2f1dbScgd /*ARGSUSED*/
vi_change_meta(EditLine * el,wint_t c)287f54e4f97Schristos vi_change_meta(EditLine *el, wint_t c __attribute__((__unused__)))
2886dc2f1dbScgd {
289d30d584aSlukem 
2906dc2f1dbScgd 	/*
2916dc2f1dbScgd          * Delete with insert == change: first we delete and then we leave in
2926dc2f1dbScgd          * insert mode.
2936dc2f1dbScgd          */
294b71bed95Schristos 	return cv_action(el, DELETE | INSERT);
2956dc2f1dbScgd }
2966dc2f1dbScgd 
2976dc2f1dbScgd 
2986dc2f1dbScgd /* vi_insert_at_bol():
2996dc2f1dbScgd  *	Vi enter insert mode at the beginning of line
3006dc2f1dbScgd  *	[I]
3016dc2f1dbScgd  */
302a2d6b270Schristos libedit_private el_action_t
3036dc2f1dbScgd /*ARGSUSED*/
vi_insert_at_bol(EditLine * el,wint_t c)304f54e4f97Schristos vi_insert_at_bol(EditLine *el, wint_t c __attribute__((__unused__)))
3056dc2f1dbScgd {
306d30d584aSlukem 
3076dc2f1dbScgd 	el->el_line.cursor = el->el_line.buffer;
30839f224afSchristos 	cv_undo(el);
3096dc2f1dbScgd 	el->el_map.current = el->el_map.key;
310b71bed95Schristos 	return CC_CURSOR;
3116dc2f1dbScgd }
3126dc2f1dbScgd 
3136dc2f1dbScgd 
3146dc2f1dbScgd /* vi_replace_char():
3156dc2f1dbScgd  *	Vi replace character under the cursor with the next character typed
3166dc2f1dbScgd  *	[r]
3176dc2f1dbScgd  */
318a2d6b270Schristos libedit_private el_action_t
3196dc2f1dbScgd /*ARGSUSED*/
vi_replace_char(EditLine * el,wint_t c)320f54e4f97Schristos vi_replace_char(EditLine *el, wint_t c __attribute__((__unused__)))
3216dc2f1dbScgd {
322d30d584aSlukem 
32339f224afSchristos 	if (el->el_line.cursor >= el->el_line.lastchar)
324a17c7fe4Schristos 		return CC_ERROR;
325a17c7fe4Schristos 
3266dc2f1dbScgd 	el->el_map.current = el->el_map.key;
3276dc2f1dbScgd 	el->el_state.inputmode = MODE_REPLACE_1;
32839f224afSchristos 	cv_undo(el);
329b71bed95Schristos 	return CC_ARGHACK;
3306dc2f1dbScgd }
3316dc2f1dbScgd 
3326dc2f1dbScgd 
3336dc2f1dbScgd /* vi_replace_mode():
3346dc2f1dbScgd  *	Vi enter replace mode
3356dc2f1dbScgd  *	[R]
3366dc2f1dbScgd  */
337a2d6b270Schristos libedit_private el_action_t
3386dc2f1dbScgd /*ARGSUSED*/
vi_replace_mode(EditLine * el,wint_t c)339f54e4f97Schristos vi_replace_mode(EditLine *el, wint_t c __attribute__((__unused__)))
3406dc2f1dbScgd {
341d30d584aSlukem 
3426dc2f1dbScgd 	el->el_map.current = el->el_map.key;
3436dc2f1dbScgd 	el->el_state.inputmode = MODE_REPLACE;
34439f224afSchristos 	cv_undo(el);
345b71bed95Schristos 	return CC_NORM;
3466dc2f1dbScgd }
3476dc2f1dbScgd 
3486dc2f1dbScgd 
3496dc2f1dbScgd /* vi_substitute_char():
3506dc2f1dbScgd  *	Vi replace character under the cursor and enter insert mode
351a17c7fe4Schristos  *	[s]
3526dc2f1dbScgd  */
353a2d6b270Schristos libedit_private el_action_t
3546dc2f1dbScgd /*ARGSUSED*/
vi_substitute_char(EditLine * el,wint_t c)355f54e4f97Schristos vi_substitute_char(EditLine *el, wint_t c __attribute__((__unused__)))
3566dc2f1dbScgd {
357d30d584aSlukem 
3586dc2f1dbScgd 	c_delafter(el, el->el_state.argument);
3596dc2f1dbScgd 	el->el_map.current = el->el_map.key;
360b71bed95Schristos 	return CC_REFRESH;
3616dc2f1dbScgd }
3626dc2f1dbScgd 
3636dc2f1dbScgd 
3646dc2f1dbScgd /* vi_substitute_line():
3656dc2f1dbScgd  *	Vi substitute entire line
3666dc2f1dbScgd  *	[S]
3676dc2f1dbScgd  */
368a2d6b270Schristos libedit_private el_action_t
3696dc2f1dbScgd /*ARGSUSED*/
vi_substitute_line(EditLine * el,wint_t c)370f54e4f97Schristos vi_substitute_line(EditLine *el, wint_t c __attribute__((__unused__)))
3716dc2f1dbScgd {
372d30d584aSlukem 
37339f224afSchristos 	cv_undo(el);
37439f224afSchristos 	cv_yank(el, el->el_line.buffer,
3755c894153Schristos 	    (int)(el->el_line.lastchar - el->el_line.buffer));
3766dc2f1dbScgd 	(void) em_kill_line(el, 0);
3776dc2f1dbScgd 	el->el_map.current = el->el_map.key;
378b71bed95Schristos 	return CC_REFRESH;
3796dc2f1dbScgd }
3806dc2f1dbScgd 
3816dc2f1dbScgd 
3826dc2f1dbScgd /* vi_change_to_eol():
3836dc2f1dbScgd  *	Vi change to end of line
3846dc2f1dbScgd  *	[C]
3856dc2f1dbScgd  */
386a2d6b270Schristos libedit_private el_action_t
3876dc2f1dbScgd /*ARGSUSED*/
vi_change_to_eol(EditLine * el,wint_t c)388f54e4f97Schristos vi_change_to_eol(EditLine *el, wint_t c __attribute__((__unused__)))
3896dc2f1dbScgd {
390d30d584aSlukem 
39139f224afSchristos 	cv_undo(el);
39239f224afSchristos 	cv_yank(el, el->el_line.cursor,
3935c894153Schristos 	    (int)(el->el_line.lastchar - el->el_line.cursor));
3946dc2f1dbScgd 	(void) ed_kill_line(el, 0);
3956dc2f1dbScgd 	el->el_map.current = el->el_map.key;
396b71bed95Schristos 	return CC_REFRESH;
3976dc2f1dbScgd }
3986dc2f1dbScgd 
3996dc2f1dbScgd 
4006dc2f1dbScgd /* vi_insert():
4016dc2f1dbScgd  *	Vi enter insert mode
4026dc2f1dbScgd  *	[i]
4036dc2f1dbScgd  */
404a2d6b270Schristos libedit_private el_action_t
4056dc2f1dbScgd /*ARGSUSED*/
vi_insert(EditLine * el,wint_t c)406f54e4f97Schristos vi_insert(EditLine *el, wint_t c __attribute__((__unused__)))
4076dc2f1dbScgd {
408d30d584aSlukem 
4096dc2f1dbScgd 	el->el_map.current = el->el_map.key;
41039f224afSchristos 	cv_undo(el);
411b71bed95Schristos 	return CC_NORM;
4126dc2f1dbScgd }
4136dc2f1dbScgd 
4146dc2f1dbScgd 
4156dc2f1dbScgd /* vi_add():
4166dc2f1dbScgd  *	Vi enter insert mode after the cursor
4176dc2f1dbScgd  *	[a]
4186dc2f1dbScgd  */
419a2d6b270Schristos libedit_private el_action_t
4206dc2f1dbScgd /*ARGSUSED*/
vi_add(EditLine * el,wint_t c)421f54e4f97Schristos vi_add(EditLine *el, wint_t c __attribute__((__unused__)))
4226dc2f1dbScgd {
4236dc2f1dbScgd 	int ret;
424d30d584aSlukem 
4256dc2f1dbScgd 	el->el_map.current = el->el_map.key;
4266dc2f1dbScgd 	if (el->el_line.cursor < el->el_line.lastchar) {
4276dc2f1dbScgd 		el->el_line.cursor++;
4286dc2f1dbScgd 		if (el->el_line.cursor > el->el_line.lastchar)
4296dc2f1dbScgd 			el->el_line.cursor = el->el_line.lastchar;
4306dc2f1dbScgd 		ret = CC_CURSOR;
431d30d584aSlukem 	} else
4326dc2f1dbScgd 		ret = CC_NORM;
4336dc2f1dbScgd 
43439f224afSchristos 	cv_undo(el);
4356dc2f1dbScgd 
4363d802cf5Schristos 	return (el_action_t)ret;
4376dc2f1dbScgd }
4386dc2f1dbScgd 
4396dc2f1dbScgd 
4406dc2f1dbScgd /* vi_add_at_eol():
4416dc2f1dbScgd  *	Vi enter insert mode at end of line
4426dc2f1dbScgd  *	[A]
4436dc2f1dbScgd  */
444a2d6b270Schristos libedit_private el_action_t
4456dc2f1dbScgd /*ARGSUSED*/
vi_add_at_eol(EditLine * el,wint_t c)446f54e4f97Schristos vi_add_at_eol(EditLine *el, wint_t c __attribute__((__unused__)))
4476dc2f1dbScgd {
448d30d584aSlukem 
4496dc2f1dbScgd 	el->el_map.current = el->el_map.key;
4506dc2f1dbScgd 	el->el_line.cursor = el->el_line.lastchar;
45139f224afSchristos 	cv_undo(el);
452b71bed95Schristos 	return CC_CURSOR;
4536dc2f1dbScgd }
4546dc2f1dbScgd 
4556dc2f1dbScgd 
4566dc2f1dbScgd /* vi_delete_meta():
4576dc2f1dbScgd  *	Vi delete prefix command
4586dc2f1dbScgd  *	[d]
4596dc2f1dbScgd  */
460a2d6b270Schristos libedit_private el_action_t
4616dc2f1dbScgd /*ARGSUSED*/
vi_delete_meta(EditLine * el,wint_t c)462f54e4f97Schristos vi_delete_meta(EditLine *el, wint_t c __attribute__((__unused__)))
4636dc2f1dbScgd {
464d30d584aSlukem 
465b71bed95Schristos 	return cv_action(el, DELETE);
4666dc2f1dbScgd }
4676dc2f1dbScgd 
4686dc2f1dbScgd 
469a17c7fe4Schristos /* vi_end_big_word():
4706dc2f1dbScgd  *	Vi move to the end of the current space delimited word
4716dc2f1dbScgd  *	[E]
4726dc2f1dbScgd  */
473a2d6b270Schristos libedit_private el_action_t
4746dc2f1dbScgd /*ARGSUSED*/
vi_end_big_word(EditLine * el,wint_t c)475f54e4f97Schristos vi_end_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
4766dc2f1dbScgd {
4776dc2f1dbScgd 
478d30d584aSlukem 	if (el->el_line.cursor == el->el_line.lastchar)
479b71bed95Schristos 		return CC_ERROR;
480d30d584aSlukem 
481d30d584aSlukem 	el->el_line.cursor = cv__endword(el->el_line.cursor,
482a17c7fe4Schristos 	    el->el_line.lastchar, el->el_state.argument, cv__isWord);
4836dc2f1dbScgd 
48439f224afSchristos 	if (el->el_chared.c_vcmd.action != NOP) {
4856dc2f1dbScgd 		el->el_line.cursor++;
4866dc2f1dbScgd 		cv_delfini(el);
487b71bed95Schristos 		return CC_REFRESH;
4886dc2f1dbScgd 	}
489b71bed95Schristos 	return CC_CURSOR;
4906dc2f1dbScgd }
4916dc2f1dbScgd 
4926dc2f1dbScgd 
493a17c7fe4Schristos /* vi_end_word():
4946dc2f1dbScgd  *	Vi move to the end of the current word
4956dc2f1dbScgd  *	[e]
4966dc2f1dbScgd  */
497a2d6b270Schristos libedit_private el_action_t
4986dc2f1dbScgd /*ARGSUSED*/
vi_end_word(EditLine * el,wint_t c)499f54e4f97Schristos vi_end_word(EditLine *el, wint_t c __attribute__((__unused__)))
5006dc2f1dbScgd {
5016dc2f1dbScgd 
502d30d584aSlukem 	if (el->el_line.cursor == el->el_line.lastchar)
503b71bed95Schristos 		return CC_ERROR;
504d30d584aSlukem 
505d30d584aSlukem 	el->el_line.cursor = cv__endword(el->el_line.cursor,
506a17c7fe4Schristos 	    el->el_line.lastchar, el->el_state.argument, cv__isword);
5076dc2f1dbScgd 
50839f224afSchristos 	if (el->el_chared.c_vcmd.action != NOP) {
5096dc2f1dbScgd 		el->el_line.cursor++;
5106dc2f1dbScgd 		cv_delfini(el);
511b71bed95Schristos 		return CC_REFRESH;
5126dc2f1dbScgd 	}
513b71bed95Schristos 	return CC_CURSOR;
5146dc2f1dbScgd }
5156dc2f1dbScgd 
5166dc2f1dbScgd 
5176dc2f1dbScgd /* vi_undo():
5186dc2f1dbScgd  *	Vi undo last change
5196dc2f1dbScgd  *	[u]
5206dc2f1dbScgd  */
521a2d6b270Schristos libedit_private el_action_t
5226dc2f1dbScgd /*ARGSUSED*/
vi_undo(EditLine * el,wint_t c)523f54e4f97Schristos vi_undo(EditLine *el, wint_t c __attribute__((__unused__)))
5246dc2f1dbScgd {
525a17c7fe4Schristos 	c_undo_t un = el->el_chared.c_undo;
5266dc2f1dbScgd 
527a17c7fe4Schristos 	if (un.len == -1)
528a17c7fe4Schristos 		return CC_ERROR;
5296dc2f1dbScgd 
530a17c7fe4Schristos 	/* switch line buffer and undo buffer */
531a17c7fe4Schristos 	el->el_chared.c_undo.buf = el->el_line.buffer;
532a17c7fe4Schristos 	el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer;
5335c894153Schristos 	el->el_chared.c_undo.cursor =
5345c894153Schristos 	    (int)(el->el_line.cursor - el->el_line.buffer);
535a17c7fe4Schristos 	el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer);
536a17c7fe4Schristos 	el->el_line.buffer = un.buf;
537a17c7fe4Schristos 	el->el_line.cursor = un.buf + un.cursor;
538a17c7fe4Schristos 	el->el_line.lastchar = un.buf + un.len;
5396dc2f1dbScgd 
540b71bed95Schristos 	return CC_REFRESH;
5416dc2f1dbScgd }
5426dc2f1dbScgd 
5436dc2f1dbScgd 
5446dc2f1dbScgd /* vi_command_mode():
5456dc2f1dbScgd  *	Vi enter command mode (use alternative key bindings)
5466dc2f1dbScgd  *	[<ESC>]
5476dc2f1dbScgd  */
548a2d6b270Schristos libedit_private el_action_t
5496dc2f1dbScgd /*ARGSUSED*/
vi_command_mode(EditLine * el,wint_t c)550f54e4f97Schristos vi_command_mode(EditLine *el, wint_t c __attribute__((__unused__)))
5516dc2f1dbScgd {
552d30d584aSlukem 
5536dc2f1dbScgd 	/* [Esc] cancels pending action */
5546dc2f1dbScgd 	el->el_chared.c_vcmd.action = NOP;
5556dc2f1dbScgd 	el->el_chared.c_vcmd.pos = 0;
5566dc2f1dbScgd 
5576dc2f1dbScgd 	el->el_state.doingarg = 0;
5586dc2f1dbScgd 
5596dc2f1dbScgd 	el->el_state.inputmode = MODE_INSERT;
5606dc2f1dbScgd 	el->el_map.current = el->el_map.alt;
5616dc2f1dbScgd #ifdef VI_MOVE
5626dc2f1dbScgd 	if (el->el_line.cursor > el->el_line.buffer)
5636dc2f1dbScgd 		el->el_line.cursor--;
5646dc2f1dbScgd #endif
565b71bed95Schristos 	return CC_CURSOR;
5666dc2f1dbScgd }
5676dc2f1dbScgd 
568d30d584aSlukem 
5696dc2f1dbScgd /* vi_zero():
5706dc2f1dbScgd  *	Vi move to the beginning of line
5716dc2f1dbScgd  *	[0]
5726dc2f1dbScgd  */
573a2d6b270Schristos libedit_private el_action_t
vi_zero(EditLine * el,wint_t c)574f54e4f97Schristos vi_zero(EditLine *el, wint_t c)
5756dc2f1dbScgd {
576d30d584aSlukem 
57739f224afSchristos 	if (el->el_state.doingarg)
57839f224afSchristos 		return ed_argument_digit(el, c);
57939f224afSchristos 
5806dc2f1dbScgd 	el->el_line.cursor = el->el_line.buffer;
58139f224afSchristos 	if (el->el_chared.c_vcmd.action != NOP) {
5826dc2f1dbScgd 		cv_delfini(el);
583b71bed95Schristos 		return CC_REFRESH;
5846dc2f1dbScgd 	}
585b71bed95Schristos 	return CC_CURSOR;
5866dc2f1dbScgd }
5876dc2f1dbScgd 
5886dc2f1dbScgd 
5896dc2f1dbScgd /* vi_delete_prev_char():
5906dc2f1dbScgd  *	Vi move to previous character (backspace)
591a17c7fe4Schristos  *	[^H] in insert mode only
5926dc2f1dbScgd  */
593a2d6b270Schristos libedit_private el_action_t
5946dc2f1dbScgd /*ARGSUSED*/
vi_delete_prev_char(EditLine * el,wint_t c)595f54e4f97Schristos vi_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
5966dc2f1dbScgd {
597d30d584aSlukem 
5986360c4b0Smycroft 	if (el->el_line.cursor <= el->el_line.buffer)
599b71bed95Schristos 		return CC_ERROR;
6006dc2f1dbScgd 
6016360c4b0Smycroft 	c_delbefore1(el);
6026360c4b0Smycroft 	el->el_line.cursor--;
603b71bed95Schristos 	return CC_REFRESH;
604d30d584aSlukem }
6056dc2f1dbScgd 
6066dc2f1dbScgd 
6076dc2f1dbScgd /* vi_list_or_eof():
6086dc2f1dbScgd  *	Vi list choices for completion or indicate end of file if empty line
6096dc2f1dbScgd  *	[^D]
6106dc2f1dbScgd  */
611a2d6b270Schristos libedit_private el_action_t
6126dc2f1dbScgd /*ARGSUSED*/
vi_list_or_eof(EditLine * el,wint_t c)613f54e4f97Schristos vi_list_or_eof(EditLine *el, wint_t c)
6146dc2f1dbScgd {
615d30d584aSlukem 
616362ac611Smatt 	if (el->el_line.cursor == el->el_line.lastchar) {
617362ac611Smatt 		if (el->el_line.cursor == el->el_line.buffer) {
618c2c011fcSchristos 			terminal_writec(el, c);	/* then do a EOF */
619b71bed95Schristos 			return CC_EOF;
620d30d584aSlukem 		} else {
621362ac611Smatt 			/*
622362ac611Smatt 			 * Here we could list completions, but it is an
623362ac611Smatt 			 * error right now
624362ac611Smatt 			 */
625c2c011fcSchristos 			terminal_beep(el);
626b71bed95Schristos 			return CC_ERROR;
627362ac611Smatt 		}
628362ac611Smatt 	} else {
629362ac611Smatt #ifdef notyet
6306dc2f1dbScgd 		re_goto_bottom(el);
6316dc2f1dbScgd 		*el->el_line.lastchar = '\0';	/* just in case */
632b71bed95Schristos 		return CC_LIST_CHOICES;
633362ac611Smatt #else
634362ac611Smatt 		/*
635362ac611Smatt 		 * Just complain for now.
636362ac611Smatt 		 */
637c2c011fcSchristos 		terminal_beep(el);
638b71bed95Schristos 		return CC_ERROR;
6396dc2f1dbScgd #endif
6406dc2f1dbScgd 	}
641362ac611Smatt }
6426dc2f1dbScgd 
6436dc2f1dbScgd 
6446dc2f1dbScgd /* vi_kill_line_prev():
6456dc2f1dbScgd  *	Vi cut from beginning of line to cursor
6466dc2f1dbScgd  *	[^U]
6476dc2f1dbScgd  */
648a2d6b270Schristos libedit_private el_action_t
6496dc2f1dbScgd /*ARGSUSED*/
vi_kill_line_prev(EditLine * el,wint_t c)650f54e4f97Schristos vi_kill_line_prev(EditLine *el, wint_t c __attribute__((__unused__)))
6516dc2f1dbScgd {
6520594af80Schristos 	wchar_t *kp, *cp;
6536dc2f1dbScgd 
6546dc2f1dbScgd 	cp = el->el_line.buffer;
6556dc2f1dbScgd 	kp = el->el_chared.c_kill.buf;
6566dc2f1dbScgd 	while (cp < el->el_line.cursor)
6576dc2f1dbScgd 		*kp++ = *cp++;	/* copy it */
6586dc2f1dbScgd 	el->el_chared.c_kill.last = kp;
6595c894153Schristos 	c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer));
6606dc2f1dbScgd 	el->el_line.cursor = el->el_line.buffer;	/* zap! */
661b71bed95Schristos 	return CC_REFRESH;
6626dc2f1dbScgd }
6636dc2f1dbScgd 
6646dc2f1dbScgd 
6656dc2f1dbScgd /* vi_search_prev():
6666dc2f1dbScgd  *	Vi search history previous
6676dc2f1dbScgd  *	[?]
6686dc2f1dbScgd  */
669a2d6b270Schristos libedit_private el_action_t
6706dc2f1dbScgd /*ARGSUSED*/
vi_search_prev(EditLine * el,wint_t c)671f54e4f97Schristos vi_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
6726dc2f1dbScgd {
673d30d584aSlukem 
674b71bed95Schristos 	return cv_search(el, ED_SEARCH_PREV_HISTORY);
6756dc2f1dbScgd }
6766dc2f1dbScgd 
6776dc2f1dbScgd 
6786dc2f1dbScgd /* vi_search_next():
6796dc2f1dbScgd  *	Vi search history next
6806dc2f1dbScgd  *	[/]
6816dc2f1dbScgd  */
682a2d6b270Schristos libedit_private el_action_t
6836dc2f1dbScgd /*ARGSUSED*/
vi_search_next(EditLine * el,wint_t c)684f54e4f97Schristos vi_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
6856dc2f1dbScgd {
686d30d584aSlukem 
687b71bed95Schristos 	return cv_search(el, ED_SEARCH_NEXT_HISTORY);
6886dc2f1dbScgd }
6896dc2f1dbScgd 
6906dc2f1dbScgd 
6916dc2f1dbScgd /* vi_repeat_search_next():
6926dc2f1dbScgd  *	Vi repeat current search in the same search direction
6936dc2f1dbScgd  *	[n]
6946dc2f1dbScgd  */
695a2d6b270Schristos libedit_private el_action_t
6966dc2f1dbScgd /*ARGSUSED*/
vi_repeat_search_next(EditLine * el,wint_t c)697f54e4f97Schristos vi_repeat_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
6986dc2f1dbScgd {
699d30d584aSlukem 
7006dc2f1dbScgd 	if (el->el_search.patlen == 0)
701b71bed95Schristos 		return CC_ERROR;
7026dc2f1dbScgd 	else
703b71bed95Schristos 		return cv_repeat_srch(el, el->el_search.patdir);
7046dc2f1dbScgd }
7056dc2f1dbScgd 
7066dc2f1dbScgd 
7076dc2f1dbScgd /* vi_repeat_search_prev():
7086dc2f1dbScgd  *	Vi repeat current search in the opposite search direction
7096dc2f1dbScgd  *	[N]
7106dc2f1dbScgd  */
7116dc2f1dbScgd /*ARGSUSED*/
712a2d6b270Schristos libedit_private el_action_t
vi_repeat_search_prev(EditLine * el,wint_t c)713f54e4f97Schristos vi_repeat_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
7146dc2f1dbScgd {
715d30d584aSlukem 
7166dc2f1dbScgd 	if (el->el_search.patlen == 0)
717b71bed95Schristos 		return CC_ERROR;
7186dc2f1dbScgd 	else
719d30d584aSlukem 		return (cv_repeat_srch(el,
7206dc2f1dbScgd 		    el->el_search.patdir == ED_SEARCH_PREV_HISTORY ?
721d30d584aSlukem 		    ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY));
7226dc2f1dbScgd }
7236dc2f1dbScgd 
7246dc2f1dbScgd 
7256dc2f1dbScgd /* vi_next_char():
7266dc2f1dbScgd  *	Vi move to the character specified next
7276dc2f1dbScgd  *	[f]
7286dc2f1dbScgd  */
729a2d6b270Schristos libedit_private el_action_t
7306dc2f1dbScgd /*ARGSUSED*/
vi_next_char(EditLine * el,wint_t c)731f54e4f97Schristos vi_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
7326dc2f1dbScgd {
73339f224afSchristos 	return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0);
7346dc2f1dbScgd }
7356dc2f1dbScgd 
7366dc2f1dbScgd 
7376dc2f1dbScgd /* vi_prev_char():
7386dc2f1dbScgd  *	Vi move to the character specified previous
7396dc2f1dbScgd  *	[F]
7406dc2f1dbScgd  */
741a2d6b270Schristos libedit_private el_action_t
7426dc2f1dbScgd /*ARGSUSED*/
vi_prev_char(EditLine * el,wint_t c)743f54e4f97Schristos vi_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
7446dc2f1dbScgd {
74539f224afSchristos 	return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0);
7466dc2f1dbScgd }
7476dc2f1dbScgd 
7486dc2f1dbScgd 
7496dc2f1dbScgd /* vi_to_next_char():
7506dc2f1dbScgd  *	Vi move up to the character specified next
7516dc2f1dbScgd  *	[t]
7526dc2f1dbScgd  */
753a2d6b270Schristos libedit_private el_action_t
7546dc2f1dbScgd /*ARGSUSED*/
vi_to_next_char(EditLine * el,wint_t c)755f54e4f97Schristos vi_to_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
7566dc2f1dbScgd {
75739f224afSchristos 	return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1);
7586dc2f1dbScgd }
7596dc2f1dbScgd 
7606dc2f1dbScgd 
7616dc2f1dbScgd /* vi_to_prev_char():
7626dc2f1dbScgd  *	Vi move up to the character specified previous
7636dc2f1dbScgd  *	[T]
7646dc2f1dbScgd  */
765a2d6b270Schristos libedit_private el_action_t
7666dc2f1dbScgd /*ARGSUSED*/
vi_to_prev_char(EditLine * el,wint_t c)767f54e4f97Schristos vi_to_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
7686dc2f1dbScgd {
76939f224afSchristos 	return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1);
7706dc2f1dbScgd }
7716dc2f1dbScgd 
7726dc2f1dbScgd 
7736dc2f1dbScgd /* vi_repeat_next_char():
7746dc2f1dbScgd  *	Vi repeat current character search in the same search direction
7756dc2f1dbScgd  *	[;]
7766dc2f1dbScgd  */
777a2d6b270Schristos libedit_private el_action_t
7786dc2f1dbScgd /*ARGSUSED*/
vi_repeat_next_char(EditLine * el,wint_t c)779f54e4f97Schristos vi_repeat_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
7806dc2f1dbScgd {
7816dc2f1dbScgd 
78239f224afSchristos 	return cv_csearch(el, el->el_search.chadir, el->el_search.chacha,
78339f224afSchristos 		el->el_state.argument, el->el_search.chatflg);
7846dc2f1dbScgd }
7856dc2f1dbScgd 
7866dc2f1dbScgd 
7876dc2f1dbScgd /* vi_repeat_prev_char():
7886dc2f1dbScgd  *	Vi repeat current character search in the opposite search direction
7896dc2f1dbScgd  *	[,]
7906dc2f1dbScgd  */
791a2d6b270Schristos libedit_private el_action_t
7926dc2f1dbScgd /*ARGSUSED*/
vi_repeat_prev_char(EditLine * el,wint_t c)793f54e4f97Schristos vi_repeat_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
7946dc2f1dbScgd {
79539f224afSchristos 	el_action_t r;
79639f224afSchristos 	int dir = el->el_search.chadir;
797d30d584aSlukem 
79839f224afSchristos 	r = cv_csearch(el, -dir, el->el_search.chacha,
79939f224afSchristos 		el->el_state.argument, el->el_search.chatflg);
80039f224afSchristos 	el->el_search.chadir = dir;
80139f224afSchristos 	return r;
8026dc2f1dbScgd }
803905b699aSchristos 
804905b699aSchristos 
805905b699aSchristos /* vi_match():
806905b699aSchristos  *	Vi go to matching () {} or []
807905b699aSchristos  *	[%]
808905b699aSchristos  */
809a2d6b270Schristos libedit_private el_action_t
810905b699aSchristos /*ARGSUSED*/
vi_match(EditLine * el,wint_t c)811f54e4f97Schristos vi_match(EditLine *el, wint_t c __attribute__((__unused__)))
812905b699aSchristos {
8130594af80Schristos 	const wchar_t match_chars[] = L"()[]{}";
8140594af80Schristos 	wchar_t *cp;
8155c894153Schristos 	size_t delta, i, count;
8160594af80Schristos 	wchar_t o_ch, c_ch;
817905b699aSchristos 
818905b699aSchristos 	*el->el_line.lastchar = '\0';		/* just in case */
819905b699aSchristos 
820fcf85103Schristos 	i = wcscspn(el->el_line.cursor, match_chars);
821905b699aSchristos 	o_ch = el->el_line.cursor[i];
822905b699aSchristos 	if (o_ch == 0)
823905b699aSchristos 		return CC_ERROR;
8240aefc7f9Schristos 	delta = (size_t)(wcschr(match_chars, o_ch) - match_chars);
825905b699aSchristos 	c_ch = match_chars[delta ^ 1];
826905b699aSchristos 	count = 1;
827905b699aSchristos 	delta = 1 - (delta & 1) * 2;
828905b699aSchristos 
829905b699aSchristos 	for (cp = &el->el_line.cursor[i]; count; ) {
830905b699aSchristos 		cp += delta;
831905b699aSchristos 		if (cp < el->el_line.buffer || cp >= el->el_line.lastchar)
832905b699aSchristos 			return CC_ERROR;
833905b699aSchristos 		if (*cp == o_ch)
834905b699aSchristos 			count++;
835905b699aSchristos 		else if (*cp == c_ch)
836905b699aSchristos 			count--;
837905b699aSchristos 	}
838905b699aSchristos 
839905b699aSchristos 	el->el_line.cursor = cp;
840905b699aSchristos 
84139f224afSchristos 	if (el->el_chared.c_vcmd.action != NOP) {
84239f224afSchristos 		/* NB posix says char under cursor should NOT be deleted
84339f224afSchristos 		   for -ve delta - this is different to netbsd vi. */
844905b699aSchristos 		if (delta > 0)
845905b699aSchristos 			el->el_line.cursor++;
846905b699aSchristos 		cv_delfini(el);
847b71bed95Schristos 		return CC_REFRESH;
848905b699aSchristos 	}
849b71bed95Schristos 	return CC_CURSOR;
850905b699aSchristos }
85139f224afSchristos 
85239f224afSchristos /* vi_undo_line():
85339f224afSchristos  *	Vi undo all changes to line
85439f224afSchristos  *	[U]
85539f224afSchristos  */
856a2d6b270Schristos libedit_private el_action_t
85739f224afSchristos /*ARGSUSED*/
vi_undo_line(EditLine * el,wint_t c)858f54e4f97Schristos vi_undo_line(EditLine *el, wint_t c __attribute__((__unused__)))
85939f224afSchristos {
86039f224afSchristos 
86139f224afSchristos 	cv_undo(el);
86239f224afSchristos 	return hist_get(el);
86339f224afSchristos }
86439f224afSchristos 
86539f224afSchristos /* vi_to_column():
86639f224afSchristos  *	Vi go to specified column
86739f224afSchristos  *	[|]
86839f224afSchristos  * NB netbsd vi goes to screen column 'n', posix says nth character
86939f224afSchristos  */
870a2d6b270Schristos libedit_private el_action_t
87139f224afSchristos /*ARGSUSED*/
vi_to_column(EditLine * el,wint_t c)872f54e4f97Schristos vi_to_column(EditLine *el, wint_t c __attribute__((__unused__)))
87339f224afSchristos {
87439f224afSchristos 
87539f224afSchristos 	el->el_line.cursor = el->el_line.buffer;
87639f224afSchristos 	el->el_state.argument--;
87739f224afSchristos 	return ed_next_char(el, 0);
87839f224afSchristos }
87939f224afSchristos 
88039f224afSchristos /* vi_yank_end():
88139f224afSchristos  *	Vi yank to end of line
88239f224afSchristos  *	[Y]
88339f224afSchristos  */
884a2d6b270Schristos libedit_private el_action_t
88539f224afSchristos /*ARGSUSED*/
vi_yank_end(EditLine * el,wint_t c)886f54e4f97Schristos vi_yank_end(EditLine *el, wint_t c __attribute__((__unused__)))
88739f224afSchristos {
88839f224afSchristos 
88939f224afSchristos 	cv_yank(el, el->el_line.cursor,
8905c894153Schristos 	    (int)(el->el_line.lastchar - el->el_line.cursor));
89139f224afSchristos 	return CC_REFRESH;
89239f224afSchristos }
89339f224afSchristos 
89439f224afSchristos /* vi_yank():
89539f224afSchristos  *	Vi yank
89639f224afSchristos  *	[y]
89739f224afSchristos  */
898a2d6b270Schristos libedit_private el_action_t
89939f224afSchristos /*ARGSUSED*/
vi_yank(EditLine * el,wint_t c)900f54e4f97Schristos vi_yank(EditLine *el, wint_t c __attribute__((__unused__)))
90139f224afSchristos {
90239f224afSchristos 
90339f224afSchristos 	return cv_action(el, YANK);
90439f224afSchristos }
90539f224afSchristos 
90639f224afSchristos /* vi_comment_out():
90739f224afSchristos  *	Vi comment out current command
9082ecb0fb7Schristos  *	[#]
90939f224afSchristos  */
910a2d6b270Schristos libedit_private el_action_t
91139f224afSchristos /*ARGSUSED*/
vi_comment_out(EditLine * el,wint_t c)912f54e4f97Schristos vi_comment_out(EditLine *el, wint_t c __attribute__((__unused__)))
91339f224afSchristos {
91439f224afSchristos 
91539f224afSchristos 	el->el_line.cursor = el->el_line.buffer;
91639f224afSchristos 	c_insert(el, 1);
91739f224afSchristos 	*el->el_line.cursor = '#';
91839f224afSchristos 	re_refresh(el);
91939f224afSchristos 	return ed_newline(el, 0);
92039f224afSchristos }
92139f224afSchristos 
92239f224afSchristos /* vi_alias():
92339f224afSchristos  *	Vi include shell alias
92439f224afSchristos  *	[@]
9252ecb0fb7Schristos  * NB: posix implies that we should enter insert mode, however
92639f224afSchristos  * this is against historical precedent...
92739f224afSchristos  */
928a2d6b270Schristos libedit_private el_action_t
92939f224afSchristos /*ARGSUSED*/
vi_alias(EditLine * el,wint_t c)930f54e4f97Schristos vi_alias(EditLine *el, wint_t c __attribute__((__unused__)))
93139f224afSchristos {
93239f224afSchristos 	char alias_name[3];
933e06822a7Schristos 	const char *alias_text;
93439f224afSchristos 
935e06822a7Schristos 	if (el->el_chared.c_aliasfun == NULL)
9366f7bc0c1Sjoerg 		return CC_ERROR;
9372ffae645Schristos 
93839f224afSchristos 	alias_name[0] = '_';
93939f224afSchristos 	alias_name[2] = 0;
94039f224afSchristos 	if (el_getc(el, &alias_name[1]) != 1)
94139f224afSchristos 		return CC_ERROR;
94239f224afSchristos 
943e06822a7Schristos 	alias_text = (*el->el_chared.c_aliasfun)(el->el_chared.c_aliasarg,
944e06822a7Schristos 	    alias_name);
94539f224afSchristos 	if (alias_text != NULL)
9460aefc7f9Schristos 		el_wpush(el, ct_decode_string(alias_text, &el->el_scratch));
94739f224afSchristos 	return CC_NORM;
94839f224afSchristos }
94939f224afSchristos 
95039f224afSchristos /* vi_to_history_line():
95139f224afSchristos  *	Vi go to specified history file line.
95239f224afSchristos  *	[G]
95339f224afSchristos  */
954a2d6b270Schristos libedit_private el_action_t
95539f224afSchristos /*ARGSUSED*/
vi_to_history_line(EditLine * el,wint_t c)956f54e4f97Schristos vi_to_history_line(EditLine *el, wint_t c __attribute__((__unused__)))
95739f224afSchristos {
95839f224afSchristos 	int sv_event_no = el->el_history.eventno;
95939f224afSchristos 	el_action_t rval;
96039f224afSchristos 
96139f224afSchristos 
96239f224afSchristos 	if (el->el_history.eventno == 0) {
9630aefc7f9Schristos 		 (void) wcsncpy(el->el_history.buf, el->el_line.buffer,
96439f224afSchristos 		     EL_BUFSIZ);
96539f224afSchristos 		 el->el_history.last = el->el_history.buf +
96639f224afSchristos 			 (el->el_line.lastchar - el->el_line.buffer);
96739f224afSchristos 	}
96839f224afSchristos 
96939f224afSchristos 	/* Lack of a 'count' means oldest, not 1 */
97039f224afSchristos 	if (!el->el_state.doingarg) {
97139f224afSchristos 		el->el_history.eventno = 0x7fffffff;
97239f224afSchristos 		hist_get(el);
97339f224afSchristos 	} else {
97439f224afSchristos 		/* This is brain dead, all the rest of this code counts
97539f224afSchristos 		 * upwards going into the past.  Here we need count in the
97639f224afSchristos 		 * other direction (to match the output of fc -l).
97739f224afSchristos 		 * I could change the world, but this seems to suffice.
97839f224afSchristos 		 */
97939f224afSchristos 		el->el_history.eventno = 1;
98039f224afSchristos 		if (hist_get(el) == CC_ERROR)
98139f224afSchristos 			return CC_ERROR;
98239f224afSchristos 		el->el_history.eventno = 1 + el->el_history.ev.num
98339f224afSchristos 					- el->el_state.argument;
98439f224afSchristos 		if (el->el_history.eventno < 0) {
98539f224afSchristos 			el->el_history.eventno = sv_event_no;
98639f224afSchristos 			return CC_ERROR;
98739f224afSchristos 		}
98839f224afSchristos 	}
98939f224afSchristos 	rval = hist_get(el);
99039f224afSchristos 	if (rval == CC_ERROR)
99139f224afSchristos 		el->el_history.eventno = sv_event_no;
99239f224afSchristos 	return rval;
99339f224afSchristos }
99439f224afSchristos 
99539f224afSchristos /* vi_histedit():
99639f224afSchristos  *	Vi edit history line with vi
99739f224afSchristos  *	[v]
99839f224afSchristos  */
999a2d6b270Schristos libedit_private el_action_t
100039f224afSchristos /*ARGSUSED*/
vi_histedit(EditLine * el,wint_t c)1001f54e4f97Schristos vi_histedit(EditLine *el, wint_t c __attribute__((__unused__)))
100239f224afSchristos {
100339f224afSchristos 	int fd;
100439f224afSchristos 	pid_t pid;
10055c894153Schristos 	ssize_t st;
10065c894153Schristos 	int status;
100739f224afSchristos 	char tempfile[] = "/tmp/histedit.XXXXXXXXXX";
10083c15bad9Schristos 	char *cp = NULL;
100934e53048Schristos 	size_t len;
10100594af80Schristos 	wchar_t *line = NULL;
1011*6cac535eSchristos 	const char *editor;
101239f224afSchristos 
101339f224afSchristos 	if (el->el_state.doingarg) {
101439f224afSchristos 		if (vi_to_history_line(el, 0) == CC_ERROR)
101539f224afSchristos 			return CC_ERROR;
101639f224afSchristos 	}
101739f224afSchristos 
1018*6cac535eSchristos 	if ((editor = getenv("EDITOR")) == NULL)
1019*6cac535eSchristos 		editor = "vi";
102039f224afSchristos 	fd = mkstemp(tempfile);
102139f224afSchristos 	if (fd < 0)
102239f224afSchristos 		return CC_ERROR;
102334e53048Schristos 	len = (size_t)(el->el_line.lastchar - el->el_line.buffer);
102434e53048Schristos #define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX)
1025113f06a3Schristos 	cp = el_calloc(TMP_BUFSIZ, sizeof(*cp));
10263c15bad9Schristos 	if (cp == NULL)
10273c15bad9Schristos 		goto error;
1028113f06a3Schristos 	line = el_calloc(len + 1, sizeof(*line));
10293c15bad9Schristos 	if (line == NULL)
10303c15bad9Schristos 		goto error;
10310aefc7f9Schristos 	wcsncpy(line, el->el_line.buffer, len);
103234e53048Schristos 	line[len] = '\0';
1033fcf85103Schristos 	wcstombs(cp, line, TMP_BUFSIZ - 1);
103434e53048Schristos 	cp[TMP_BUFSIZ - 1] = '\0';
103534e53048Schristos 	len = strlen(cp);
103634e53048Schristos 	write(fd, cp, len);
1037c11bd863Schristos 	write(fd, "\n", (size_t)1);
103839f224afSchristos 	pid = fork();
103939f224afSchristos 	switch (pid) {
104039f224afSchristos 	case -1:
10413c15bad9Schristos 		goto error;
104239f224afSchristos 	case 0:
104339f224afSchristos 		close(fd);
1044*6cac535eSchristos 		execlp(editor, editor, tempfile, (char *)NULL);
104539f224afSchristos 		exit(0);
104639f224afSchristos 		/*NOTREACHED*/
104739f224afSchristos 	default:
10485c894153Schristos 		while (waitpid(pid, &status, 0) != pid)
104939f224afSchristos 			continue;
10505c894153Schristos 		lseek(fd, (off_t)0, SEEK_SET);
1051234792daSchristos 		st = read(fd, cp, TMP_BUFSIZ - 1);
105234e53048Schristos 		if (st > 0) {
1053234792daSchristos 			cp[st] = '\0';
10540fe5419eSchristos 			len = (size_t)(el->el_line.limit - el->el_line.buffer);
1055fcf85103Schristos 			len = mbstowcs(el->el_line.buffer, cp, len);
105634e53048Schristos 			if (len > 0 && el->el_line.buffer[len - 1] == '\n')
105734e53048Schristos 				--len;
105834e53048Schristos 		}
105934e53048Schristos 		else
106034e53048Schristos 			len = 0;
106134e53048Schristos                 el->el_line.cursor = el->el_line.buffer;
106234e53048Schristos                 el->el_line.lastchar = el->el_line.buffer + len;
106334e53048Schristos 		el_free(cp);
106434e53048Schristos                 el_free(line);
106539f224afSchristos 		break;
106639f224afSchristos 	}
106739f224afSchristos 
106839f224afSchristos 	close(fd);
106939f224afSchristos 	unlink(tempfile);
107039f224afSchristos 	/* return CC_REFRESH; */
107139f224afSchristos 	return ed_newline(el, 0);
10723c15bad9Schristos error:
10733c15bad9Schristos 	el_free(line);
10743c15bad9Schristos 	el_free(cp);
10753c15bad9Schristos 	close(fd);
10763c15bad9Schristos 	unlink(tempfile);
10773c15bad9Schristos 	return CC_ERROR;
107839f224afSchristos }
107939f224afSchristos 
108039f224afSchristos /* vi_history_word():
108139f224afSchristos  *	Vi append word from previous input line
108239f224afSchristos  *	[_]
108339f224afSchristos  * Who knows where this one came from!
108439f224afSchristos  * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_'
108539f224afSchristos  */
1086a2d6b270Schristos libedit_private el_action_t
108739f224afSchristos /*ARGSUSED*/
vi_history_word(EditLine * el,wint_t c)1088f54e4f97Schristos vi_history_word(EditLine *el, wint_t c __attribute__((__unused__)))
108939f224afSchristos {
10900594af80Schristos 	const wchar_t *wp = HIST_FIRST(el);
10910594af80Schristos 	const wchar_t *wep, *wsp;
109239f224afSchristos 	int len;
10930594af80Schristos 	wchar_t *cp;
10940594af80Schristos 	const wchar_t *lim;
109539f224afSchristos 
109639f224afSchristos 	if (wp == NULL)
109739f224afSchristos 		return CC_ERROR;
109839f224afSchristos 
10992dd09931Schristos 	wep = wsp = NULL;
110039f224afSchristos 	do {
1101fcf85103Schristos 		while (iswspace(*wp))
110239f224afSchristos 			wp++;
110339f224afSchristos 		if (*wp == 0)
110439f224afSchristos 			break;
110539f224afSchristos 		wsp = wp;
1106fcf85103Schristos 		while (*wp && !iswspace(*wp))
110739f224afSchristos 			wp++;
110839f224afSchristos 		wep = wp;
110934e53048Schristos 	} while ((!el->el_state.doingarg || --el->el_state.argument > 0)
111034e53048Schristos 	    && *wp != 0);
111139f224afSchristos 
11122dd09931Schristos 	if (wsp == NULL || (el->el_state.doingarg && el->el_state.argument != 0))
111339f224afSchristos 		return CC_ERROR;
111439f224afSchristos 
111539f224afSchristos 	cv_undo(el);
11165c894153Schristos 	len = (int)(wep - wsp);
111739f224afSchristos 	if (el->el_line.cursor < el->el_line.lastchar)
111839f224afSchristos 		el->el_line.cursor++;
111939f224afSchristos 	c_insert(el, len + 1);
112039f224afSchristos 	cp = el->el_line.cursor;
112139f224afSchristos 	lim = el->el_line.limit;
112239f224afSchristos 	if (cp < lim)
112339f224afSchristos 		*cp++ = ' ';
112439f224afSchristos 	while (wsp < wep && cp < lim)
112539f224afSchristos 		*cp++ = *wsp++;
112639f224afSchristos 	el->el_line.cursor = cp;
112739f224afSchristos 
112839f224afSchristos 	el->el_map.current = el->el_map.key;
112939f224afSchristos 	return CC_REFRESH;
113039f224afSchristos }
113139f224afSchristos 
113239f224afSchristos /* vi_redo():
113339f224afSchristos  *	Vi redo last non-motion command
113439f224afSchristos  *	[.]
113539f224afSchristos  */
1136a2d6b270Schristos libedit_private el_action_t
113739f224afSchristos /*ARGSUSED*/
vi_redo(EditLine * el,wint_t c)1138f54e4f97Schristos vi_redo(EditLine *el, wint_t c __attribute__((__unused__)))
113939f224afSchristos {
114039f224afSchristos 	c_redo_t *r = &el->el_chared.c_redo;
114139f224afSchristos 
114239f224afSchristos 	if (!el->el_state.doingarg && r->count) {
114339f224afSchristos 		el->el_state.doingarg = 1;
114439f224afSchristos 		el->el_state.argument = r->count;
114539f224afSchristos 	}
114639f224afSchristos 
114739f224afSchristos 	el->el_chared.c_vcmd.pos = el->el_line.cursor;
114839f224afSchristos 	el->el_chared.c_vcmd.action = r->action;
114939f224afSchristos 	if (r->pos != r->buf) {
115039f224afSchristos 		if (r->pos + 1 > r->lim)
115139f224afSchristos 			/* sanity */
115239f224afSchristos 			r->pos = r->lim - 1;
115339f224afSchristos 		r->pos[0] = 0;
11540aefc7f9Schristos 		el_wpush(el, r->buf);
115539f224afSchristos 	}
115639f224afSchristos 
115739f224afSchristos 	el->el_state.thiscmd = r->cmd;
115839f224afSchristos 	el->el_state.thisch = r->ch;
115939f224afSchristos 	return (*el->el_map.func[r->cmd])(el, r->ch);
116039f224afSchristos }
1161