vi.c revision 290065
1290065Sjilles/*	$NetBSD: vi.c,v 1.47 2015/10/21 21:45:30 christos Exp $	*/
2276881Sbapt
31573Srgrimes/*-
41573Srgrimes * Copyright (c) 1992, 1993
51573Srgrimes *	The Regents of the University of California.  All rights reserved.
61573Srgrimes *
71573Srgrimes * This code is derived from software contributed to Berkeley by
81573Srgrimes * Christos Zoulas of Cornell University.
91573Srgrimes *
101573Srgrimes * Redistribution and use in source and binary forms, with or without
111573Srgrimes * modification, are permitted provided that the following conditions
121573Srgrimes * are met:
131573Srgrimes * 1. Redistributions of source code must retain the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer.
151573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161573Srgrimes *    notice, this list of conditions and the following disclaimer in the
171573Srgrimes *    documentation and/or other materials provided with the distribution.
18148834Sstefanf * 3. Neither the name of the University nor the names of its contributors
191573Srgrimes *    may be used to endorse or promote products derived from this software
201573Srgrimes *    without specific prior written permission.
211573Srgrimes *
221573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321573Srgrimes * SUCH DAMAGE.
331573Srgrimes */
341573Srgrimes
35276881Sbapt#include "config.h"
36276881Sbapt#include <stdlib.h>
37276881Sbapt#include <unistd.h>
38276881Sbapt#include <limits.h>
39276881Sbapt#include <sys/wait.h>
40276881Sbapt
411573Srgrimes#if !defined(lint) && !defined(SCCSID)
42276881Sbapt#if 0
431573Srgrimesstatic char sccsid[] = "@(#)vi.c	8.1 (Berkeley) 6/4/93";
44276881Sbapt#else
45290065Sjilles__RCSID("$NetBSD: vi.c,v 1.47 2015/10/21 21:45:30 christos Exp $");
46276881Sbapt#endif
471573Srgrimes#endif /* not lint && not SCCSID */
4884260Sobrien#include <sys/cdefs.h>
4984260Sobrien__FBSDID("$FreeBSD: head/lib/libedit/vi.c 290065 2015-10-27 21:16:29Z jilles $");
501573Srgrimes
511573Srgrimes/*
521573Srgrimes * vi.c: Vi mode commands.
531573Srgrimes */
541573Srgrimes#include "el.h"
551573Srgrimes
56276881Sbaptprivate el_action_t	cv_action(EditLine *, Int);
57276881Sbaptprivate el_action_t	cv_paste(EditLine *, Int);
581573Srgrimes
591573Srgrimes/* cv_action():
601573Srgrimes *	Handle vi actions.
611573Srgrimes */
621573Srgrimesprivate el_action_t
63276881Sbaptcv_action(EditLine *el, Int c)
641573Srgrimes{
651573Srgrimes
66148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
67148834Sstefanf		/* 'cc', 'dd' and (possibly) friends */
68276881Sbapt		if (c != (Int)el->el_chared.c_vcmd.action)
69148834Sstefanf			return CC_ERROR;
70148834Sstefanf
71148834Sstefanf		if (!(c & YANK))
72148834Sstefanf			cv_undo(el);
73148834Sstefanf		cv_yank(el, el->el_line.buffer,
74237448Spfg		    (int)(el->el_line.lastchar - el->el_line.buffer));
7584260Sobrien		el->el_chared.c_vcmd.action = NOP;
7684260Sobrien		el->el_chared.c_vcmd.pos = 0;
77148923Sstefanf		if (!(c & YANK)) {
78148923Sstefanf			el->el_line.lastchar = el->el_line.buffer;
79148923Sstefanf			el->el_line.cursor = el->el_line.buffer;
80148923Sstefanf		}
8184260Sobrien		if (c & INSERT)
8284260Sobrien			el->el_map.current = el->el_map.key;
838870Srgrimes
84276881Sbapt		return CC_REFRESH;
8584260Sobrien	}
8684260Sobrien	el->el_chared.c_vcmd.pos = el->el_line.cursor;
8784260Sobrien	el->el_chared.c_vcmd.action = c;
88276881Sbapt	return CC_ARGHACK;
891573Srgrimes}
901573Srgrimes
911573Srgrimes/* cv_paste():
921573Srgrimes *	Paste previous deletion before or after the cursor
931573Srgrimes */
9484260Sobrienprivate el_action_t
95276881Sbaptcv_paste(EditLine *el, Int c)
961573Srgrimes{
97148834Sstefanf	c_kill_t *k = &el->el_chared.c_kill;
98237448Spfg	size_t len = (size_t)(k->last - k->buf);
9984260Sobrien
100148834Sstefanf	if (k->buf == NULL || len == 0)
101276881Sbapt		return CC_ERROR;
1021573Srgrimes#ifdef DEBUG_PASTE
103237448Spfg	(void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", (int)len, k->buf);
1041573Srgrimes#endif
1051573Srgrimes
106148834Sstefanf	cv_undo(el);
107148834Sstefanf
10884260Sobrien	if (!c && el->el_line.cursor < el->el_line.lastchar)
10984260Sobrien		el->el_line.cursor++;
1108870Srgrimes
111237448Spfg	c_insert(el, (int)len);
112148834Sstefanf	if (el->el_line.cursor + len > el->el_line.lastchar)
113276881Sbapt		return CC_ERROR;
114276881Sbapt	(void) memcpy(el->el_line.cursor, k->buf, len *
115276881Sbapt	    sizeof(*el->el_line.cursor));
116148923Sstefanf
117276881Sbapt	return CC_REFRESH;
1181573Srgrimes}
1191573Srgrimes
1201573Srgrimes
1218870Srgrimes/* vi_paste_next():
1221573Srgrimes *	Vi paste previous deletion to the right of the cursor
1231573Srgrimes *	[p]
1241573Srgrimes */
1251573Srgrimesprotected el_action_t
1261573Srgrimes/*ARGSUSED*/
127276881Sbaptvi_paste_next(EditLine *el, Int c __attribute__((__unused__)))
1281573Srgrimes{
12984260Sobrien
130276881Sbapt	return cv_paste(el, 0);
1311573Srgrimes}
1321573Srgrimes
1331573Srgrimes
1348870Srgrimes/* vi_paste_prev():
1351573Srgrimes *	Vi paste previous deletion to the left of the cursor
1361573Srgrimes *	[P]
1371573Srgrimes */
1381573Srgrimesprotected el_action_t
1391573Srgrimes/*ARGSUSED*/
140276881Sbaptvi_paste_prev(EditLine *el, Int c __attribute__((__unused__)))
1411573Srgrimes{
14284260Sobrien
143276881Sbapt	return cv_paste(el, 1);
1441573Srgrimes}
1451573Srgrimes
1461573Srgrimes
147148834Sstefanf/* vi_prev_big_word():
1481573Srgrimes *	Vi move to the previous space delimited word
1491573Srgrimes *	[B]
1501573Srgrimes */
1511573Srgrimesprotected el_action_t
1521573Srgrimes/*ARGSUSED*/
153276881Sbaptvi_prev_big_word(EditLine *el, Int c __attribute__((__unused__)))
1541573Srgrimes{
1551573Srgrimes
15684260Sobrien	if (el->el_line.cursor == el->el_line.buffer)
157276881Sbapt		return CC_ERROR;
1581573Srgrimes
159148834Sstefanf	el->el_line.cursor = cv_prev_word(el->el_line.cursor,
16084260Sobrien	    el->el_line.buffer,
16184260Sobrien	    el->el_state.argument,
162148834Sstefanf	    cv__isWord);
1631573Srgrimes
164148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
16584260Sobrien		cv_delfini(el);
166276881Sbapt		return CC_REFRESH;
16784260Sobrien	}
168276881Sbapt	return CC_CURSOR;
1691573Srgrimes}
1701573Srgrimes
1711573Srgrimes
1728870Srgrimes/* vi_prev_word():
1731573Srgrimes *	Vi move to the previous word
17437199Sbrian *	[b]
1751573Srgrimes */
1761573Srgrimesprotected el_action_t
1771573Srgrimes/*ARGSUSED*/
178276881Sbaptvi_prev_word(EditLine *el, Int c __attribute__((__unused__)))
1791573Srgrimes{
1801573Srgrimes
18184260Sobrien	if (el->el_line.cursor == el->el_line.buffer)
182276881Sbapt		return CC_ERROR;
1831573Srgrimes
184148834Sstefanf	el->el_line.cursor = cv_prev_word(el->el_line.cursor,
18584260Sobrien	    el->el_line.buffer,
18684260Sobrien	    el->el_state.argument,
18784260Sobrien	    cv__isword);
1881573Srgrimes
189148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
19084260Sobrien		cv_delfini(el);
191276881Sbapt		return CC_REFRESH;
19284260Sobrien	}
193276881Sbapt	return CC_CURSOR;
1941573Srgrimes}
1951573Srgrimes
1961573Srgrimes
197148834Sstefanf/* vi_next_big_word():
1981573Srgrimes *	Vi move to the next space delimited word
1991573Srgrimes *	[W]
2001573Srgrimes */
2011573Srgrimesprotected el_action_t
2021573Srgrimes/*ARGSUSED*/
203276881Sbaptvi_next_big_word(EditLine *el, Int c __attribute__((__unused__)))
2041573Srgrimes{
2051573Srgrimes
206148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar - 1)
207276881Sbapt		return CC_ERROR;
2081573Srgrimes
20984260Sobrien	el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
210148834Sstefanf	    el->el_line.lastchar, el->el_state.argument, cv__isWord);
2111573Srgrimes
21284260Sobrien	if (el->el_map.type == MAP_VI)
213148834Sstefanf		if (el->el_chared.c_vcmd.action != NOP) {
21484260Sobrien			cv_delfini(el);
215276881Sbapt			return CC_REFRESH;
21684260Sobrien		}
217276881Sbapt	return CC_CURSOR;
2181573Srgrimes}
2191573Srgrimes
22084260Sobrien
2218870Srgrimes/* vi_next_word():
2221573Srgrimes *	Vi move to the next word
2231573Srgrimes *	[w]
2241573Srgrimes */
2251573Srgrimesprotected el_action_t
2261573Srgrimes/*ARGSUSED*/
227276881Sbaptvi_next_word(EditLine *el, Int c __attribute__((__unused__)))
2281573Srgrimes{
2291573Srgrimes
230148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar - 1)
231276881Sbapt		return CC_ERROR;
2321573Srgrimes
23384260Sobrien	el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
234148834Sstefanf	    el->el_line.lastchar, el->el_state.argument, cv__isword);
2351573Srgrimes
23684260Sobrien	if (el->el_map.type == MAP_VI)
237148834Sstefanf		if (el->el_chared.c_vcmd.action != NOP) {
23884260Sobrien			cv_delfini(el);
239276881Sbapt			return CC_REFRESH;
24084260Sobrien		}
241276881Sbapt	return CC_CURSOR;
2421573Srgrimes}
2431573Srgrimes
2441573Srgrimes
2458870Srgrimes/* vi_change_case():
2461573Srgrimes *	Vi change case of character under the cursor and advance one character
2471573Srgrimes *	[~]
2481573Srgrimes */
2491573Srgrimesprotected el_action_t
250276881Sbaptvi_change_case(EditLine *el, Int c)
2511573Srgrimes{
252148834Sstefanf	int i;
25384260Sobrien
254148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar)
255276881Sbapt		return CC_ERROR;
256148834Sstefanf	cv_undo(el);
257148834Sstefanf	for (i = 0; i < el->el_state.argument; i++) {
258148834Sstefanf
259276881Sbapt		c = *el->el_line.cursor;
260276881Sbapt		if (Isupper(c))
261276881Sbapt			*el->el_line.cursor = Tolower(c);
262276881Sbapt		else if (Islower(c))
263276881Sbapt			*el->el_line.cursor = Toupper(c);
264148834Sstefanf
265148834Sstefanf		if (++el->el_line.cursor >= el->el_line.lastchar) {
266148834Sstefanf			el->el_line.cursor--;
267148834Sstefanf			re_fastaddc(el);
268148834Sstefanf			break;
269148834Sstefanf		}
27084260Sobrien		re_fastaddc(el);
27184260Sobrien	}
272148834Sstefanf	return CC_NORM;
2731573Srgrimes}
2741573Srgrimes
2751573Srgrimes
2768870Srgrimes/* vi_change_meta():
2771573Srgrimes *	Vi change prefix command
2781573Srgrimes *	[c]
2791573Srgrimes */
2801573Srgrimesprotected el_action_t
2811573Srgrimes/*ARGSUSED*/
282276881Sbaptvi_change_meta(EditLine *el, Int c __attribute__((__unused__)))
2831573Srgrimes{
28484260Sobrien
28584260Sobrien	/*
28684260Sobrien         * Delete with insert == change: first we delete and then we leave in
28784260Sobrien         * insert mode.
28884260Sobrien         */
289276881Sbapt	return cv_action(el, DELETE | INSERT);
2901573Srgrimes}
2911573Srgrimes
2921573Srgrimes
2938870Srgrimes/* vi_insert_at_bol():
2941573Srgrimes *	Vi enter insert mode at the beginning of line
2951573Srgrimes *	[I]
2961573Srgrimes */
2971573Srgrimesprotected el_action_t
2981573Srgrimes/*ARGSUSED*/
299276881Sbaptvi_insert_at_bol(EditLine *el, Int c __attribute__((__unused__)))
3001573Srgrimes{
3011573Srgrimes
30284260Sobrien	el->el_line.cursor = el->el_line.buffer;
303148834Sstefanf	cv_undo(el);
30484260Sobrien	el->el_map.current = el->el_map.key;
305276881Sbapt	return CC_CURSOR;
3061573Srgrimes}
3071573Srgrimes
3081573Srgrimes
3098870Srgrimes/* vi_replace_char():
3101573Srgrimes *	Vi replace character under the cursor with the next character typed
3111573Srgrimes *	[r]
3121573Srgrimes */
3131573Srgrimesprotected el_action_t
3141573Srgrimes/*ARGSUSED*/
315276881Sbaptvi_replace_char(EditLine *el, Int c __attribute__((__unused__)))
3161573Srgrimes{
31784260Sobrien
318148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar)
319148834Sstefanf		return CC_ERROR;
320148834Sstefanf
32184260Sobrien	el->el_map.current = el->el_map.key;
32284260Sobrien	el->el_state.inputmode = MODE_REPLACE_1;
323148834Sstefanf	cv_undo(el);
324276881Sbapt	return CC_ARGHACK;
3251573Srgrimes}
3261573Srgrimes
3271573Srgrimes
3288870Srgrimes/* vi_replace_mode():
3291573Srgrimes *	Vi enter replace mode
3301573Srgrimes *	[R]
3311573Srgrimes */
3321573Srgrimesprotected el_action_t
3331573Srgrimes/*ARGSUSED*/
334276881Sbaptvi_replace_mode(EditLine *el, Int c __attribute__((__unused__)))
3351573Srgrimes{
33684260Sobrien
33784260Sobrien	el->el_map.current = el->el_map.key;
33884260Sobrien	el->el_state.inputmode = MODE_REPLACE;
339148834Sstefanf	cv_undo(el);
340276881Sbapt	return CC_NORM;
3411573Srgrimes}
3421573Srgrimes
3431573Srgrimes
3448870Srgrimes/* vi_substitute_char():
3451573Srgrimes *	Vi replace character under the cursor and enter insert mode
34637199Sbrian *	[s]
3471573Srgrimes */
3481573Srgrimesprotected el_action_t
3491573Srgrimes/*ARGSUSED*/
350276881Sbaptvi_substitute_char(EditLine *el, Int c __attribute__((__unused__)))
3511573Srgrimes{
35284260Sobrien
35384260Sobrien	c_delafter(el, el->el_state.argument);
35484260Sobrien	el->el_map.current = el->el_map.key;
355276881Sbapt	return CC_REFRESH;
3561573Srgrimes}
3571573Srgrimes
3581573Srgrimes
3598870Srgrimes/* vi_substitute_line():
3601573Srgrimes *	Vi substitute entire line
3611573Srgrimes *	[S]
3621573Srgrimes */
3631573Srgrimesprotected el_action_t
3641573Srgrimes/*ARGSUSED*/
365276881Sbaptvi_substitute_line(EditLine *el, Int c __attribute__((__unused__)))
3661573Srgrimes{
36784260Sobrien
368148834Sstefanf	cv_undo(el);
369148834Sstefanf	cv_yank(el, el->el_line.buffer,
370237448Spfg	    (int)(el->el_line.lastchar - el->el_line.buffer));
37184260Sobrien	(void) em_kill_line(el, 0);
37284260Sobrien	el->el_map.current = el->el_map.key;
373276881Sbapt	return CC_REFRESH;
3741573Srgrimes}
3751573Srgrimes
3761573Srgrimes
3778870Srgrimes/* vi_change_to_eol():
3781573Srgrimes *	Vi change to end of line
3791573Srgrimes *	[C]
3801573Srgrimes */
3811573Srgrimesprotected el_action_t
3821573Srgrimes/*ARGSUSED*/
383276881Sbaptvi_change_to_eol(EditLine *el, Int c __attribute__((__unused__)))
3841573Srgrimes{
38584260Sobrien
386148834Sstefanf	cv_undo(el);
387148834Sstefanf	cv_yank(el, el->el_line.cursor,
388237448Spfg	    (int)(el->el_line.lastchar - el->el_line.cursor));
38984260Sobrien	(void) ed_kill_line(el, 0);
39084260Sobrien	el->el_map.current = el->el_map.key;
391276881Sbapt	return CC_REFRESH;
3921573Srgrimes}
3931573Srgrimes
3941573Srgrimes
3951573Srgrimes/* vi_insert():
3961573Srgrimes *	Vi enter insert mode
3971573Srgrimes *	[i]
3981573Srgrimes */
3991573Srgrimesprotected el_action_t
4001573Srgrimes/*ARGSUSED*/
401276881Sbaptvi_insert(EditLine *el, Int c __attribute__((__unused__)))
4021573Srgrimes{
4031573Srgrimes
40484260Sobrien	el->el_map.current = el->el_map.key;
405148834Sstefanf	cv_undo(el);
406276881Sbapt	return CC_NORM;
4071573Srgrimes}
4081573Srgrimes
4091573Srgrimes
4101573Srgrimes/* vi_add():
4118870Srgrimes *	Vi enter insert mode after the cursor
4121573Srgrimes *	[a]
4131573Srgrimes */
4141573Srgrimesprotected el_action_t
4151573Srgrimes/*ARGSUSED*/
416276881Sbaptvi_add(EditLine *el, Int c __attribute__((__unused__)))
4171573Srgrimes{
418148834Sstefanf	int ret;
41937199Sbrian
42084260Sobrien	el->el_map.current = el->el_map.key;
42184260Sobrien	if (el->el_line.cursor < el->el_line.lastchar) {
42284260Sobrien		el->el_line.cursor++;
42384260Sobrien		if (el->el_line.cursor > el->el_line.lastchar)
42484260Sobrien			el->el_line.cursor = el->el_line.lastchar;
42584260Sobrien		ret = CC_CURSOR;
42684260Sobrien	} else
42784260Sobrien		ret = CC_NORM;
4281573Srgrimes
429148834Sstefanf	cv_undo(el);
4301573Srgrimes
431276881Sbapt	return (el_action_t)ret;
4321573Srgrimes}
4331573Srgrimes
4341573Srgrimes
4351573Srgrimes/* vi_add_at_eol():
4361573Srgrimes *	Vi enter insert mode at end of line
4371573Srgrimes *	[A]
4381573Srgrimes */
4391573Srgrimesprotected el_action_t
4401573Srgrimes/*ARGSUSED*/
441276881Sbaptvi_add_at_eol(EditLine *el, Int c __attribute__((__unused__)))
4421573Srgrimes{
4431573Srgrimes
44484260Sobrien	el->el_map.current = el->el_map.key;
44584260Sobrien	el->el_line.cursor = el->el_line.lastchar;
446148834Sstefanf	cv_undo(el);
447276881Sbapt	return CC_CURSOR;
4481573Srgrimes}
4491573Srgrimes
4501573Srgrimes
4511573Srgrimes/* vi_delete_meta():
4528870Srgrimes *	Vi delete prefix command
4531573Srgrimes *	[d]
4541573Srgrimes */
4551573Srgrimesprotected el_action_t
4561573Srgrimes/*ARGSUSED*/
457276881Sbaptvi_delete_meta(EditLine *el, Int c __attribute__((__unused__)))
4581573Srgrimes{
45984260Sobrien
460276881Sbapt	return cv_action(el, DELETE);
4611573Srgrimes}
4621573Srgrimes
4631573Srgrimes
464148834Sstefanf/* vi_end_big_word():
4658870Srgrimes *	Vi move to the end of the current space delimited word
4668870Srgrimes *	[E]
4671573Srgrimes */
4681573Srgrimesprotected el_action_t
4691573Srgrimes/*ARGSUSED*/
470276881Sbaptvi_end_big_word(EditLine *el, Int c __attribute__((__unused__)))
4711573Srgrimes{
4721573Srgrimes
47384260Sobrien	if (el->el_line.cursor == el->el_line.lastchar)
474276881Sbapt		return CC_ERROR;
4751573Srgrimes
47684260Sobrien	el->el_line.cursor = cv__endword(el->el_line.cursor,
477148834Sstefanf	    el->el_line.lastchar, el->el_state.argument, cv__isWord);
4781573Srgrimes
479148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
48084260Sobrien		el->el_line.cursor++;
48184260Sobrien		cv_delfini(el);
482276881Sbapt		return CC_REFRESH;
48384260Sobrien	}
484276881Sbapt	return CC_CURSOR;
4851573Srgrimes}
4861573Srgrimes
4871573Srgrimes
488148834Sstefanf/* vi_end_word():
4891573Srgrimes *	Vi move to the end of the current word
4901573Srgrimes *	[e]
4911573Srgrimes */
4921573Srgrimesprotected el_action_t
4931573Srgrimes/*ARGSUSED*/
494276881Sbaptvi_end_word(EditLine *el, Int c __attribute__((__unused__)))
4951573Srgrimes{
4961573Srgrimes
49784260Sobrien	if (el->el_line.cursor == el->el_line.lastchar)
498276881Sbapt		return CC_ERROR;
4991573Srgrimes
50084260Sobrien	el->el_line.cursor = cv__endword(el->el_line.cursor,
501148834Sstefanf	    el->el_line.lastchar, el->el_state.argument, cv__isword);
5021573Srgrimes
503148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
50484260Sobrien		el->el_line.cursor++;
50584260Sobrien		cv_delfini(el);
506276881Sbapt		return CC_REFRESH;
50784260Sobrien	}
508276881Sbapt	return CC_CURSOR;
5091573Srgrimes}
5101573Srgrimes
5111573Srgrimes
5121573Srgrimes/* vi_undo():
5131573Srgrimes *	Vi undo last change
5141573Srgrimes *	[u]
5151573Srgrimes */
5161573Srgrimesprotected el_action_t
5171573Srgrimes/*ARGSUSED*/
518276881Sbaptvi_undo(EditLine *el, Int c __attribute__((__unused__)))
5191573Srgrimes{
520148834Sstefanf	c_undo_t un = el->el_chared.c_undo;
5211573Srgrimes
522148834Sstefanf	if (un.len == -1)
523148834Sstefanf		return CC_ERROR;
5241573Srgrimes
525148834Sstefanf	/* switch line buffer and undo buffer */
526148834Sstefanf	el->el_chared.c_undo.buf = el->el_line.buffer;
527148834Sstefanf	el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer;
528237448Spfg	el->el_chared.c_undo.cursor =
529237448Spfg	    (int)(el->el_line.cursor - el->el_line.buffer);
530148834Sstefanf	el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer);
531148834Sstefanf	el->el_line.buffer = un.buf;
532148834Sstefanf	el->el_line.cursor = un.buf + un.cursor;
533148834Sstefanf	el->el_line.lastchar = un.buf + un.len;
5341573Srgrimes
535276881Sbapt	return CC_REFRESH;
5361573Srgrimes}
5371573Srgrimes
5381573Srgrimes
5391573Srgrimes/* vi_command_mode():
5401573Srgrimes *	Vi enter command mode (use alternative key bindings)
5411573Srgrimes *	[<ESC>]
5421573Srgrimes */
5431573Srgrimesprotected el_action_t
5441573Srgrimes/*ARGSUSED*/
545276881Sbaptvi_command_mode(EditLine *el, Int c __attribute__((__unused__)))
5461573Srgrimes{
5471573Srgrimes
54884260Sobrien	/* [Esc] cancels pending action */
54984260Sobrien	el->el_chared.c_vcmd.action = NOP;
55084260Sobrien	el->el_chared.c_vcmd.pos = 0;
5511573Srgrimes
55284260Sobrien	el->el_state.doingarg = 0;
55384260Sobrien
55484260Sobrien	el->el_state.inputmode = MODE_INSERT;
55584260Sobrien	el->el_map.current = el->el_map.alt;
5561573Srgrimes#ifdef VI_MOVE
55784260Sobrien	if (el->el_line.cursor > el->el_line.buffer)
55884260Sobrien		el->el_line.cursor--;
5591573Srgrimes#endif
560276881Sbapt	return CC_CURSOR;
5611573Srgrimes}
5621573Srgrimes
56384260Sobrien
5641573Srgrimes/* vi_zero():
5658870Srgrimes *	Vi move to the beginning of line
5661573Srgrimes *	[0]
5671573Srgrimes */
5681573Srgrimesprotected el_action_t
569276881Sbaptvi_zero(EditLine *el, Int c)
5701573Srgrimes{
57184260Sobrien
572148834Sstefanf	if (el->el_state.doingarg)
573148834Sstefanf		return ed_argument_digit(el, c);
574148834Sstefanf
575148834Sstefanf	el->el_line.cursor = el->el_line.buffer;
576148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
577148834Sstefanf		cv_delfini(el);
578276881Sbapt		return CC_REFRESH;
57984260Sobrien	}
580276881Sbapt	return CC_CURSOR;
5811573Srgrimes}
5821573Srgrimes
5831573Srgrimes
5841573Srgrimes/* vi_delete_prev_char():
5858870Srgrimes * 	Vi move to previous character (backspace)
586148834Sstefanf *	[^H] in insert mode only
5878870Srgrimes */
5881573Srgrimesprotected el_action_t
5891573Srgrimes/*ARGSUSED*/
590276881Sbaptvi_delete_prev_char(EditLine *el, Int c __attribute__((__unused__)))
5911573Srgrimes{
5921573Srgrimes
593148834Sstefanf	if (el->el_line.cursor <= el->el_line.buffer)
594276881Sbapt		return CC_ERROR;
5951573Srgrimes
596148834Sstefanf	c_delbefore1(el);
597148834Sstefanf	el->el_line.cursor--;
598276881Sbapt	return CC_REFRESH;
59984260Sobrien}
6001573Srgrimes
60184260Sobrien
6021573Srgrimes/* vi_list_or_eof():
6031573Srgrimes *	Vi list choices for completion or indicate end of file if empty line
6041573Srgrimes *	[^D]
6051573Srgrimes */
6061573Srgrimesprotected el_action_t
6071573Srgrimes/*ARGSUSED*/
608276881Sbaptvi_list_or_eof(EditLine *el, Int c)
6091573Srgrimes{
61084260Sobrien
611148834Sstefanf	if (el->el_line.cursor == el->el_line.lastchar) {
612148834Sstefanf		if (el->el_line.cursor == el->el_line.buffer) {
613276881Sbapt			terminal_writec(el, c);	/* then do a EOF */
614276881Sbapt			return CC_EOF;
615148834Sstefanf		} else {
616148834Sstefanf			/*
617148834Sstefanf			 * Here we could list completions, but it is an
618148834Sstefanf			 * error right now
619148834Sstefanf			 */
620276881Sbapt			terminal_beep(el);
621276881Sbapt			return CC_ERROR;
622148834Sstefanf		}
623148834Sstefanf	} else {
6241573Srgrimes#ifdef notyet
62584260Sobrien		re_goto_bottom(el);
62684260Sobrien		*el->el_line.lastchar = '\0';	/* just in case */
627276881Sbapt		return CC_LIST_CHOICES;
628148834Sstefanf#else
629148834Sstefanf		/*
630148834Sstefanf		 * Just complain for now.
631148834Sstefanf		 */
632276881Sbapt		terminal_beep(el);
633276881Sbapt		return CC_ERROR;
634148834Sstefanf#endif
63584260Sobrien	}
6361573Srgrimes}
6371573Srgrimes
6381573Srgrimes
6391573Srgrimes/* vi_kill_line_prev():
6408870Srgrimes *	Vi cut from beginning of line to cursor
6411573Srgrimes *	[^U]
6421573Srgrimes */
6431573Srgrimesprotected el_action_t
6441573Srgrimes/*ARGSUSED*/
645276881Sbaptvi_kill_line_prev(EditLine *el, Int c __attribute__((__unused__)))
6461573Srgrimes{
647276881Sbapt	Char *kp, *cp;
6481573Srgrimes
64984260Sobrien	cp = el->el_line.buffer;
65084260Sobrien	kp = el->el_chared.c_kill.buf;
65184260Sobrien	while (cp < el->el_line.cursor)
65284260Sobrien		*kp++ = *cp++;	/* copy it */
65384260Sobrien	el->el_chared.c_kill.last = kp;
654237448Spfg	c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer));
65584260Sobrien	el->el_line.cursor = el->el_line.buffer;	/* zap! */
656276881Sbapt	return CC_REFRESH;
6571573Srgrimes}
6581573Srgrimes
6591573Srgrimes
6601573Srgrimes/* vi_search_prev():
6611573Srgrimes *	Vi search history previous
6621573Srgrimes *	[?]
6631573Srgrimes */
6641573Srgrimesprotected el_action_t
6651573Srgrimes/*ARGSUSED*/
666276881Sbaptvi_search_prev(EditLine *el, Int c __attribute__((__unused__)))
6671573Srgrimes{
66884260Sobrien
669276881Sbapt	return cv_search(el, ED_SEARCH_PREV_HISTORY);
6701573Srgrimes}
6711573Srgrimes
6721573Srgrimes
6731573Srgrimes/* vi_search_next():
6741573Srgrimes *	Vi search history next
6751573Srgrimes *	[/]
6761573Srgrimes */
6771573Srgrimesprotected el_action_t
6781573Srgrimes/*ARGSUSED*/
679276881Sbaptvi_search_next(EditLine *el, Int c __attribute__((__unused__)))
6801573Srgrimes{
68184260Sobrien
682276881Sbapt	return cv_search(el, ED_SEARCH_NEXT_HISTORY);
6831573Srgrimes}
6841573Srgrimes
6851573Srgrimes
6861573Srgrimes/* vi_repeat_search_next():
6871573Srgrimes *	Vi repeat current search in the same search direction
6881573Srgrimes *	[n]
6891573Srgrimes */
6901573Srgrimesprotected el_action_t
6911573Srgrimes/*ARGSUSED*/
692276881Sbaptvi_repeat_search_next(EditLine *el, Int c __attribute__((__unused__)))
6931573Srgrimes{
69484260Sobrien
69584260Sobrien	if (el->el_search.patlen == 0)
696276881Sbapt		return CC_ERROR;
69784260Sobrien	else
698276881Sbapt		return cv_repeat_srch(el, el->el_search.patdir);
6991573Srgrimes}
7001573Srgrimes
7011573Srgrimes
7021573Srgrimes/* vi_repeat_search_prev():
7031573Srgrimes *	Vi repeat current search in the opposite search direction
7041573Srgrimes *	[N]
7051573Srgrimes */
7061573Srgrimes/*ARGSUSED*/
7071573Srgrimesprotected el_action_t
708276881Sbaptvi_repeat_search_prev(EditLine *el, Int c __attribute__((__unused__)))
7091573Srgrimes{
71084260Sobrien
71184260Sobrien	if (el->el_search.patlen == 0)
712276881Sbapt		return CC_ERROR;
71384260Sobrien	else
71484260Sobrien		return (cv_repeat_srch(el,
71584260Sobrien		    el->el_search.patdir == ED_SEARCH_PREV_HISTORY ?
71684260Sobrien		    ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY));
7171573Srgrimes}
7181573Srgrimes
7191573Srgrimes
7201573Srgrimes/* vi_next_char():
7211573Srgrimes *	Vi move to the character specified next
7221573Srgrimes *	[f]
7231573Srgrimes */
7241573Srgrimesprotected el_action_t
7251573Srgrimes/*ARGSUSED*/
726276881Sbaptvi_next_char(EditLine *el, Int c __attribute__((__unused__)))
7271573Srgrimes{
728148834Sstefanf	return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0);
7291573Srgrimes}
7301573Srgrimes
7311573Srgrimes
7321573Srgrimes/* vi_prev_char():
7331573Srgrimes *	Vi move to the character specified previous
7341573Srgrimes *	[F]
7351573Srgrimes */
7361573Srgrimesprotected el_action_t
7371573Srgrimes/*ARGSUSED*/
738276881Sbaptvi_prev_char(EditLine *el, Int c __attribute__((__unused__)))
7391573Srgrimes{
740148834Sstefanf	return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0);
7411573Srgrimes}
7421573Srgrimes
7431573Srgrimes
7441573Srgrimes/* vi_to_next_char():
7451573Srgrimes *	Vi move up to the character specified next
7461573Srgrimes *	[t]
7471573Srgrimes */
7481573Srgrimesprotected el_action_t
7491573Srgrimes/*ARGSUSED*/
750276881Sbaptvi_to_next_char(EditLine *el, Int c __attribute__((__unused__)))
7511573Srgrimes{
752148834Sstefanf	return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1);
7531573Srgrimes}
7541573Srgrimes
7551573Srgrimes
7561573Srgrimes/* vi_to_prev_char():
7571573Srgrimes *	Vi move up to the character specified previous
7581573Srgrimes *	[T]
7591573Srgrimes */
7601573Srgrimesprotected el_action_t
7611573Srgrimes/*ARGSUSED*/
762276881Sbaptvi_to_prev_char(EditLine *el, Int c __attribute__((__unused__)))
7631573Srgrimes{
764148834Sstefanf	return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1);
7651573Srgrimes}
7661573Srgrimes
7671573Srgrimes
7681573Srgrimes/* vi_repeat_next_char():
7691573Srgrimes *	Vi repeat current character search in the same search direction
7701573Srgrimes *	[;]
7711573Srgrimes */
7721573Srgrimesprotected el_action_t
7731573Srgrimes/*ARGSUSED*/
774276881Sbaptvi_repeat_next_char(EditLine *el, Int c __attribute__((__unused__)))
7751573Srgrimes{
7761573Srgrimes
777148834Sstefanf	return cv_csearch(el, el->el_search.chadir, el->el_search.chacha,
778148834Sstefanf		el->el_state.argument, el->el_search.chatflg);
7791573Srgrimes}
7801573Srgrimes
7811573Srgrimes
7821573Srgrimes/* vi_repeat_prev_char():
7831573Srgrimes *	Vi repeat current character search in the opposite search direction
7841573Srgrimes *	[,]
7851573Srgrimes */
7861573Srgrimesprotected el_action_t
7871573Srgrimes/*ARGSUSED*/
788276881Sbaptvi_repeat_prev_char(EditLine *el, Int c __attribute__((__unused__)))
7891573Srgrimes{
790148834Sstefanf	el_action_t r;
791148834Sstefanf	int dir = el->el_search.chadir;
7921573Srgrimes
793148834Sstefanf	r = cv_csearch(el, -dir, el->el_search.chacha,
794148834Sstefanf		el->el_state.argument, el->el_search.chatflg);
795148834Sstefanf	el->el_search.chadir = dir;
796148834Sstefanf	return r;
797148834Sstefanf}
79884260Sobrien
799148834Sstefanf
800148834Sstefanf/* vi_match():
801148834Sstefanf *	Vi go to matching () {} or []
802148834Sstefanf *	[%]
803148834Sstefanf */
804148834Sstefanfprotected el_action_t
805148834Sstefanf/*ARGSUSED*/
806276881Sbaptvi_match(EditLine *el, Int c __attribute__((__unused__)))
807148834Sstefanf{
808276881Sbapt	const Char match_chars[] = STR("()[]{}");
809276881Sbapt	Char *cp;
810237448Spfg	size_t delta, i, count;
811276881Sbapt	Char o_ch, c_ch;
812148834Sstefanf
813148834Sstefanf	*el->el_line.lastchar = '\0';		/* just in case */
814148834Sstefanf
815276881Sbapt	i = Strcspn(el->el_line.cursor, match_chars);
816148834Sstefanf	o_ch = el->el_line.cursor[i];
817148834Sstefanf	if (o_ch == 0)
818148834Sstefanf		return CC_ERROR;
819276881Sbapt	delta = (size_t)(Strchr(match_chars, o_ch) - match_chars);
820148834Sstefanf	c_ch = match_chars[delta ^ 1];
821148834Sstefanf	count = 1;
822148834Sstefanf	delta = 1 - (delta & 1) * 2;
823148834Sstefanf
824148834Sstefanf	for (cp = &el->el_line.cursor[i]; count; ) {
825148834Sstefanf		cp += delta;
826148834Sstefanf		if (cp < el->el_line.buffer || cp >= el->el_line.lastchar)
827148834Sstefanf			return CC_ERROR;
828148834Sstefanf		if (*cp == o_ch)
829148834Sstefanf			count++;
830148834Sstefanf		else if (*cp == c_ch)
831148834Sstefanf			count--;
832148834Sstefanf	}
833148834Sstefanf
834148834Sstefanf	el->el_line.cursor = cp;
835148834Sstefanf
836148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
837148834Sstefanf		/* NB posix says char under cursor should NOT be deleted
838148834Sstefanf		   for -ve delta - this is different to netbsd vi. */
839148834Sstefanf		if (delta > 0)
840148834Sstefanf			el->el_line.cursor++;
841148834Sstefanf		cv_delfini(el);
842276881Sbapt		return CC_REFRESH;
843148834Sstefanf	}
844276881Sbapt	return CC_CURSOR;
8451573Srgrimes}
846148834Sstefanf
847148834Sstefanf/* vi_undo_line():
848148834Sstefanf *	Vi undo all changes to line
849148834Sstefanf *	[U]
850148834Sstefanf */
851148834Sstefanfprotected el_action_t
852148834Sstefanf/*ARGSUSED*/
853276881Sbaptvi_undo_line(EditLine *el, Int c __attribute__((__unused__)))
854148834Sstefanf{
855148834Sstefanf
856148834Sstefanf	cv_undo(el);
857148834Sstefanf	return hist_get(el);
858148834Sstefanf}
859148834Sstefanf
860148834Sstefanf/* vi_to_column():
861148834Sstefanf *	Vi go to specified column
862148834Sstefanf *	[|]
863148834Sstefanf * NB netbsd vi goes to screen column 'n', posix says nth character
864148834Sstefanf */
865148834Sstefanfprotected el_action_t
866148834Sstefanf/*ARGSUSED*/
867276881Sbaptvi_to_column(EditLine *el, Int c __attribute__((__unused__)))
868148834Sstefanf{
869148834Sstefanf
870148834Sstefanf	el->el_line.cursor = el->el_line.buffer;
871148834Sstefanf	el->el_state.argument--;
872148834Sstefanf	return ed_next_char(el, 0);
873148834Sstefanf}
874148834Sstefanf
875148834Sstefanf/* vi_yank_end():
876148834Sstefanf *	Vi yank to end of line
877148834Sstefanf *	[Y]
878148834Sstefanf */
879148834Sstefanfprotected el_action_t
880148834Sstefanf/*ARGSUSED*/
881276881Sbaptvi_yank_end(EditLine *el, Int c __attribute__((__unused__)))
882148834Sstefanf{
883148834Sstefanf
884148834Sstefanf	cv_yank(el, el->el_line.cursor,
885237448Spfg	    (int)(el->el_line.lastchar - el->el_line.cursor));
886148834Sstefanf	return CC_REFRESH;
887148834Sstefanf}
888148834Sstefanf
889148834Sstefanf/* vi_yank():
890148834Sstefanf *	Vi yank
891148834Sstefanf *	[y]
892148834Sstefanf */
893148834Sstefanfprotected el_action_t
894148834Sstefanf/*ARGSUSED*/
895276881Sbaptvi_yank(EditLine *el, Int c __attribute__((__unused__)))
896148834Sstefanf{
897148834Sstefanf
898148834Sstefanf	return cv_action(el, YANK);
899148834Sstefanf}
900148834Sstefanf
901148834Sstefanf/* vi_comment_out():
902148834Sstefanf *	Vi comment out current command
903148848Sstefanf *	[#]
904148834Sstefanf */
905148834Sstefanfprotected el_action_t
906148834Sstefanf/*ARGSUSED*/
907276881Sbaptvi_comment_out(EditLine *el, Int c __attribute__((__unused__)))
908148834Sstefanf{
909148834Sstefanf
910148834Sstefanf	el->el_line.cursor = el->el_line.buffer;
911148834Sstefanf	c_insert(el, 1);
912148834Sstefanf	*el->el_line.cursor = '#';
913148834Sstefanf	re_refresh(el);
914148834Sstefanf	return ed_newline(el, 0);
915148834Sstefanf}
916148834Sstefanf
917148834Sstefanf/* vi_alias():
918148834Sstefanf *	Vi include shell alias
919148834Sstefanf *	[@]
920148848Sstefanf * NB: posix implies that we should enter insert mode, however
921148834Sstefanf * this is against historical precedent...
922148834Sstefanf */
923148834Sstefanfprotected el_action_t
924148834Sstefanf/*ARGSUSED*/
925276881Sbaptvi_alias(EditLine *el, Int c __attribute__((__unused__)))
926148834Sstefanf{
927148834Sstefanf	char alias_name[3];
928276881Sbapt	const char *alias_text;
929148834Sstefanf
930276881Sbapt	if (el->el_chared.c_aliasfun == NULL)
931148834Sstefanf		return CC_ERROR;
932148834Sstefanf
933148834Sstefanf	alias_name[0] = '_';
934148834Sstefanf	alias_name[2] = 0;
935148834Sstefanf	if (el_getc(el, &alias_name[1]) != 1)
936148834Sstefanf		return CC_ERROR;
937148834Sstefanf
938276881Sbapt	alias_text = (*el->el_chared.c_aliasfun)(el->el_chared.c_aliasarg,
939276881Sbapt	    alias_name);
940148834Sstefanf	if (alias_text != NULL)
941276881Sbapt		FUN(el,push)(el, ct_decode_string(alias_text, &el->el_scratch));
942148834Sstefanf	return CC_NORM;
943148834Sstefanf}
944148834Sstefanf
945148834Sstefanf/* vi_to_history_line():
946148834Sstefanf *	Vi go to specified history file line.
947148834Sstefanf *	[G]
948148834Sstefanf */
949148834Sstefanfprotected el_action_t
950148834Sstefanf/*ARGSUSED*/
951276881Sbaptvi_to_history_line(EditLine *el, Int c __attribute__((__unused__)))
952148834Sstefanf{
953148834Sstefanf	int sv_event_no = el->el_history.eventno;
954148834Sstefanf	el_action_t rval;
955148834Sstefanf
956148834Sstefanf
957148834Sstefanf	if (el->el_history.eventno == 0) {
958276881Sbapt		 (void) Strncpy(el->el_history.buf, el->el_line.buffer,
959148834Sstefanf		     EL_BUFSIZ);
960148834Sstefanf		 el->el_history.last = el->el_history.buf +
961148834Sstefanf			 (el->el_line.lastchar - el->el_line.buffer);
962148834Sstefanf	}
963148834Sstefanf
964148834Sstefanf	/* Lack of a 'count' means oldest, not 1 */
965148834Sstefanf	if (!el->el_state.doingarg) {
966148834Sstefanf		el->el_history.eventno = 0x7fffffff;
967148834Sstefanf		hist_get(el);
968148834Sstefanf	} else {
969148834Sstefanf		/* This is brain dead, all the rest of this code counts
970148834Sstefanf		 * upwards going into the past.  Here we need count in the
971148834Sstefanf		 * other direction (to match the output of fc -l).
972148834Sstefanf		 * I could change the world, but this seems to suffice.
973148834Sstefanf		 */
974148834Sstefanf		el->el_history.eventno = 1;
975148834Sstefanf		if (hist_get(el) == CC_ERROR)
976148834Sstefanf			return CC_ERROR;
977148834Sstefanf		el->el_history.eventno = 1 + el->el_history.ev.num
978148834Sstefanf					- el->el_state.argument;
979148834Sstefanf		if (el->el_history.eventno < 0) {
980148834Sstefanf			el->el_history.eventno = sv_event_no;
981148834Sstefanf			return CC_ERROR;
982148834Sstefanf		}
983148834Sstefanf	}
984148834Sstefanf	rval = hist_get(el);
985148834Sstefanf	if (rval == CC_ERROR)
986148834Sstefanf		el->el_history.eventno = sv_event_no;
987148834Sstefanf	return rval;
988148834Sstefanf}
989148834Sstefanf
990148834Sstefanf/* vi_histedit():
991148834Sstefanf *	Vi edit history line with vi
992148834Sstefanf *	[v]
993148834Sstefanf */
994148834Sstefanfprotected el_action_t
995148834Sstefanf/*ARGSUSED*/
996276881Sbaptvi_histedit(EditLine *el, Int c __attribute__((__unused__)))
997148834Sstefanf{
998148834Sstefanf	int fd;
999148834Sstefanf	pid_t pid;
1000237448Spfg	ssize_t st;
1001237448Spfg	int status;
1002148834Sstefanf	char tempfile[] = "/tmp/histedit.XXXXXXXXXX";
1003276881Sbapt	char *cp = NULL;
1004276881Sbapt	size_t len;
1005276881Sbapt	Char *line = NULL;
1006148834Sstefanf
1007148834Sstefanf	if (el->el_state.doingarg) {
1008148834Sstefanf		if (vi_to_history_line(el, 0) == CC_ERROR)
1009148834Sstefanf			return CC_ERROR;
1010148834Sstefanf	}
1011148834Sstefanf
1012148834Sstefanf	fd = mkstemp(tempfile);
1013148834Sstefanf	if (fd < 0)
1014148834Sstefanf		return CC_ERROR;
1015276881Sbapt	len = (size_t)(el->el_line.lastchar - el->el_line.buffer);
1016276881Sbapt#define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX)
1017276881Sbapt	cp = el_malloc(TMP_BUFSIZ * sizeof(*cp));
1018276881Sbapt	if (cp == NULL)
1019276881Sbapt		goto error;
1020276881Sbapt	line = el_malloc(len * sizeof(*line) + 1);
1021276881Sbapt	if (line == NULL)
1022276881Sbapt		goto error;
1023276881Sbapt	Strncpy(line, el->el_line.buffer, len);
1024276881Sbapt	line[len] = '\0';
1025276881Sbapt	ct_wcstombs(cp, line, TMP_BUFSIZ - 1);
1026276881Sbapt	cp[TMP_BUFSIZ - 1] = '\0';
1027276881Sbapt	len = strlen(cp);
1028276881Sbapt	write(fd, cp, len);
1029276881Sbapt	write(fd, "\n", (size_t)1);
1030148834Sstefanf	pid = fork();
1031148834Sstefanf	switch (pid) {
1032148834Sstefanf	case -1:
1033276881Sbapt		goto error;
1034148834Sstefanf	case 0:
1035148834Sstefanf		close(fd);
1036237448Spfg		execlp("vi", "vi", tempfile, (char *)NULL);
1037148834Sstefanf		exit(0);
1038148834Sstefanf		/*NOTREACHED*/
1039148834Sstefanf	default:
1040237448Spfg		while (waitpid(pid, &status, 0) != pid)
1041148834Sstefanf			continue;
1042237448Spfg		lseek(fd, (off_t)0, SEEK_SET);
1043290065Sjilles		st = read(fd, cp, TMP_BUFSIZ - 1);
1044276881Sbapt		if (st > 0) {
1045290065Sjilles			cp[st] = '\0';
1046290065Sjilles			len = (size_t)(el->el_line.limit - el->el_line.buffer);
1047276881Sbapt			len = ct_mbstowcs(el->el_line.buffer, cp, len);
1048290065Sjilles			if (len > 0 && el->el_line.buffer[len - 1] == '\n')
1049276881Sbapt				--len;
1050276881Sbapt		}
1051276881Sbapt		else
1052276881Sbapt			len = 0;
1053276881Sbapt                el->el_line.cursor = el->el_line.buffer;
1054276881Sbapt                el->el_line.lastchar = el->el_line.buffer + len;
1055276881Sbapt		el_free(cp);
1056276881Sbapt                el_free(line);
1057148834Sstefanf		break;
1058148834Sstefanf	}
1059148834Sstefanf
1060148834Sstefanf	close(fd);
1061148834Sstefanf	unlink(tempfile);
1062148834Sstefanf	/* return CC_REFRESH; */
1063148834Sstefanf	return ed_newline(el, 0);
1064276881Sbapterror:
1065276881Sbapt	el_free(line);
1066276881Sbapt	el_free(cp);
1067276881Sbapt	close(fd);
1068276881Sbapt	unlink(tempfile);
1069276881Sbapt	return CC_ERROR;
1070148834Sstefanf}
1071148834Sstefanf
1072148834Sstefanf/* vi_history_word():
1073148834Sstefanf *	Vi append word from previous input line
1074148834Sstefanf *	[_]
1075148834Sstefanf * Who knows where this one came from!
1076148834Sstefanf * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_'
1077148834Sstefanf */
1078148834Sstefanfprotected el_action_t
1079148834Sstefanf/*ARGSUSED*/
1080276881Sbaptvi_history_word(EditLine *el, Int c __attribute__((__unused__)))
1081148834Sstefanf{
1082276881Sbapt	const Char *wp = HIST_FIRST(el);
1083276881Sbapt	const Char *wep, *wsp;
1084148834Sstefanf	int len;
1085276881Sbapt	Char *cp;
1086276881Sbapt	const Char *lim;
1087148834Sstefanf
1088148834Sstefanf	if (wp == NULL)
1089148834Sstefanf		return CC_ERROR;
1090148834Sstefanf
1091148834Sstefanf	wep = wsp = 0;
1092148834Sstefanf	do {
1093276881Sbapt		while (Isspace(*wp))
1094148834Sstefanf			wp++;
1095148834Sstefanf		if (*wp == 0)
1096148834Sstefanf			break;
1097148834Sstefanf		wsp = wp;
1098276881Sbapt		while (*wp && !Isspace(*wp))
1099148834Sstefanf			wp++;
1100148834Sstefanf		wep = wp;
1101276881Sbapt	} while ((!el->el_state.doingarg || --el->el_state.argument > 0)
1102276881Sbapt	    && *wp != 0);
1103148834Sstefanf
1104148834Sstefanf	if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0))
1105148834Sstefanf		return CC_ERROR;
1106148834Sstefanf
1107148834Sstefanf	cv_undo(el);
1108237448Spfg	len = (int)(wep - wsp);
1109148834Sstefanf	if (el->el_line.cursor < el->el_line.lastchar)
1110148834Sstefanf		el->el_line.cursor++;
1111148834Sstefanf	c_insert(el, len + 1);
1112148834Sstefanf	cp = el->el_line.cursor;
1113148834Sstefanf	lim = el->el_line.limit;
1114148834Sstefanf	if (cp < lim)
1115148834Sstefanf		*cp++ = ' ';
1116148834Sstefanf	while (wsp < wep && cp < lim)
1117148834Sstefanf		*cp++ = *wsp++;
1118148834Sstefanf	el->el_line.cursor = cp;
1119148834Sstefanf
1120148834Sstefanf	el->el_map.current = el->el_map.key;
1121148834Sstefanf	return CC_REFRESH;
1122148834Sstefanf}
1123148834Sstefanf
1124148834Sstefanf/* vi_redo():
1125148834Sstefanf *	Vi redo last non-motion command
1126148834Sstefanf *	[.]
1127148834Sstefanf */
1128148834Sstefanfprotected el_action_t
1129148834Sstefanf/*ARGSUSED*/
1130276881Sbaptvi_redo(EditLine *el, Int c __attribute__((__unused__)))
1131148834Sstefanf{
1132148834Sstefanf	c_redo_t *r = &el->el_chared.c_redo;
1133148834Sstefanf
1134148834Sstefanf	if (!el->el_state.doingarg && r->count) {
1135148834Sstefanf		el->el_state.doingarg = 1;
1136148834Sstefanf		el->el_state.argument = r->count;
1137148834Sstefanf	}
1138148834Sstefanf
1139148834Sstefanf	el->el_chared.c_vcmd.pos = el->el_line.cursor;
1140148834Sstefanf	el->el_chared.c_vcmd.action = r->action;
1141148834Sstefanf	if (r->pos != r->buf) {
1142148834Sstefanf		if (r->pos + 1 > r->lim)
1143148834Sstefanf			/* sanity */
1144148834Sstefanf			r->pos = r->lim - 1;
1145148834Sstefanf		r->pos[0] = 0;
1146276881Sbapt		FUN(el,push)(el, r->buf);
1147148834Sstefanf	}
1148148834Sstefanf
1149148834Sstefanf	el->el_state.thiscmd = r->cmd;
1150148834Sstefanf	el->el_state.thisch = r->ch;
1151276881Sbapt	return (*el->el_map.func[r->cmd])(el, r->ch);
1152148834Sstefanf}
1153