1313981Spfg/*	$NetBSD: vi.c,v 1.55 2016/03/02 19:24:20 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"
361573Srgrimes#if !defined(lint) && !defined(SCCSID)
37276881Sbapt#if 0
381573Srgrimesstatic char sccsid[] = "@(#)vi.c	8.1 (Berkeley) 6/4/93";
39276881Sbapt#else
40313981Spfg__RCSID("$NetBSD: vi.c,v 1.55 2016/03/02 19:24:20 christos Exp $");
41276881Sbapt#endif
421573Srgrimes#endif /* not lint && not SCCSID */
4384260Sobrien#include <sys/cdefs.h>
4484260Sobrien__FBSDID("$FreeBSD: stable/11/lib/libedit/vi.c 313981 2017-02-20 03:33:59Z pfg $");
451573Srgrimes
461573Srgrimes/*
471573Srgrimes * vi.c: Vi mode commands.
481573Srgrimes */
49313981Spfg#include <sys/wait.h>
50313981Spfg#include <ctype.h>
51313981Spfg#include <limits.h>
52313981Spfg#include <stdlib.h>
53313981Spfg#include <string.h>
54313981Spfg#include <unistd.h>
55313981Spfg
561573Srgrimes#include "el.h"
57313981Spfg#include "common.h"
58313981Spfg#include "emacs.h"
59313981Spfg#include "vi.h"
601573Srgrimes
61313981Spfgprivate el_action_t	cv_action(EditLine *, wint_t);
62313981Spfgprivate el_action_t	cv_paste(EditLine *, wint_t);
631573Srgrimes
641573Srgrimes/* cv_action():
651573Srgrimes *	Handle vi actions.
661573Srgrimes */
671573Srgrimesprivate el_action_t
68313981Spfgcv_action(EditLine *el, wint_t c)
691573Srgrimes{
701573Srgrimes
71148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
72148834Sstefanf		/* 'cc', 'dd' and (possibly) friends */
73313981Spfg		if (c != (wint_t)el->el_chared.c_vcmd.action)
74148834Sstefanf			return CC_ERROR;
75148834Sstefanf
76148834Sstefanf		if (!(c & YANK))
77148834Sstefanf			cv_undo(el);
78148834Sstefanf		cv_yank(el, el->el_line.buffer,
79237448Spfg		    (int)(el->el_line.lastchar - el->el_line.buffer));
8084260Sobrien		el->el_chared.c_vcmd.action = NOP;
8184260Sobrien		el->el_chared.c_vcmd.pos = 0;
82148923Sstefanf		if (!(c & YANK)) {
83148923Sstefanf			el->el_line.lastchar = el->el_line.buffer;
84148923Sstefanf			el->el_line.cursor = el->el_line.buffer;
85148923Sstefanf		}
8684260Sobrien		if (c & INSERT)
8784260Sobrien			el->el_map.current = el->el_map.key;
888870Srgrimes
89276881Sbapt		return CC_REFRESH;
9084260Sobrien	}
9184260Sobrien	el->el_chared.c_vcmd.pos = el->el_line.cursor;
9284260Sobrien	el->el_chared.c_vcmd.action = c;
93276881Sbapt	return CC_ARGHACK;
941573Srgrimes}
951573Srgrimes
961573Srgrimes/* cv_paste():
971573Srgrimes *	Paste previous deletion before or after the cursor
981573Srgrimes */
9984260Sobrienprivate el_action_t
100313981Spfgcv_paste(EditLine *el, wint_t c)
1011573Srgrimes{
102148834Sstefanf	c_kill_t *k = &el->el_chared.c_kill;
103237448Spfg	size_t len = (size_t)(k->last - k->buf);
10484260Sobrien
105148834Sstefanf	if (k->buf == NULL || len == 0)
106276881Sbapt		return CC_ERROR;
1071573Srgrimes#ifdef DEBUG_PASTE
108313981Spfg	(void) fprintf(el->el_errfile, "Paste: \"" FSTARSTR "\"\n", (int)len,
109313981Spfg	    k->buf);
1101573Srgrimes#endif
1111573Srgrimes
112148834Sstefanf	cv_undo(el);
113148834Sstefanf
11484260Sobrien	if (!c && el->el_line.cursor < el->el_line.lastchar)
11584260Sobrien		el->el_line.cursor++;
1168870Srgrimes
117237448Spfg	c_insert(el, (int)len);
118148834Sstefanf	if (el->el_line.cursor + len > el->el_line.lastchar)
119276881Sbapt		return CC_ERROR;
120276881Sbapt	(void) memcpy(el->el_line.cursor, k->buf, len *
121276881Sbapt	    sizeof(*el->el_line.cursor));
122148923Sstefanf
123276881Sbapt	return CC_REFRESH;
1241573Srgrimes}
1251573Srgrimes
1261573Srgrimes
1278870Srgrimes/* vi_paste_next():
1281573Srgrimes *	Vi paste previous deletion to the right of the cursor
1291573Srgrimes *	[p]
1301573Srgrimes */
1311573Srgrimesprotected el_action_t
1321573Srgrimes/*ARGSUSED*/
133313981Spfgvi_paste_next(EditLine *el, wint_t c __attribute__((__unused__)))
1341573Srgrimes{
13584260Sobrien
136276881Sbapt	return cv_paste(el, 0);
1371573Srgrimes}
1381573Srgrimes
1391573Srgrimes
1408870Srgrimes/* vi_paste_prev():
1411573Srgrimes *	Vi paste previous deletion to the left of the cursor
1421573Srgrimes *	[P]
1431573Srgrimes */
1441573Srgrimesprotected el_action_t
1451573Srgrimes/*ARGSUSED*/
146313981Spfgvi_paste_prev(EditLine *el, wint_t c __attribute__((__unused__)))
1471573Srgrimes{
14884260Sobrien
149276881Sbapt	return cv_paste(el, 1);
1501573Srgrimes}
1511573Srgrimes
1521573Srgrimes
153148834Sstefanf/* vi_prev_big_word():
1541573Srgrimes *	Vi move to the previous space delimited word
1551573Srgrimes *	[B]
1561573Srgrimes */
1571573Srgrimesprotected el_action_t
1581573Srgrimes/*ARGSUSED*/
159313981Spfgvi_prev_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
1601573Srgrimes{
1611573Srgrimes
16284260Sobrien	if (el->el_line.cursor == el->el_line.buffer)
163276881Sbapt		return CC_ERROR;
1641573Srgrimes
165148834Sstefanf	el->el_line.cursor = cv_prev_word(el->el_line.cursor,
16684260Sobrien	    el->el_line.buffer,
16784260Sobrien	    el->el_state.argument,
168148834Sstefanf	    cv__isWord);
1691573Srgrimes
170148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
17184260Sobrien		cv_delfini(el);
172276881Sbapt		return CC_REFRESH;
17384260Sobrien	}
174276881Sbapt	return CC_CURSOR;
1751573Srgrimes}
1761573Srgrimes
1771573Srgrimes
1788870Srgrimes/* vi_prev_word():
1791573Srgrimes *	Vi move to the previous word
18037199Sbrian *	[b]
1811573Srgrimes */
1821573Srgrimesprotected el_action_t
1831573Srgrimes/*ARGSUSED*/
184313981Spfgvi_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
1851573Srgrimes{
1861573Srgrimes
18784260Sobrien	if (el->el_line.cursor == el->el_line.buffer)
188276881Sbapt		return CC_ERROR;
1891573Srgrimes
190148834Sstefanf	el->el_line.cursor = cv_prev_word(el->el_line.cursor,
19184260Sobrien	    el->el_line.buffer,
19284260Sobrien	    el->el_state.argument,
19384260Sobrien	    cv__isword);
1941573Srgrimes
195148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
19684260Sobrien		cv_delfini(el);
197276881Sbapt		return CC_REFRESH;
19884260Sobrien	}
199276881Sbapt	return CC_CURSOR;
2001573Srgrimes}
2011573Srgrimes
2021573Srgrimes
203148834Sstefanf/* vi_next_big_word():
2041573Srgrimes *	Vi move to the next space delimited word
2051573Srgrimes *	[W]
2061573Srgrimes */
2071573Srgrimesprotected el_action_t
2081573Srgrimes/*ARGSUSED*/
209313981Spfgvi_next_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
2101573Srgrimes{
2111573Srgrimes
212148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar - 1)
213276881Sbapt		return CC_ERROR;
2141573Srgrimes
21584260Sobrien	el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
216148834Sstefanf	    el->el_line.lastchar, el->el_state.argument, cv__isWord);
2171573Srgrimes
21884260Sobrien	if (el->el_map.type == MAP_VI)
219148834Sstefanf		if (el->el_chared.c_vcmd.action != NOP) {
22084260Sobrien			cv_delfini(el);
221276881Sbapt			return CC_REFRESH;
22284260Sobrien		}
223276881Sbapt	return CC_CURSOR;
2241573Srgrimes}
2251573Srgrimes
22684260Sobrien
2278870Srgrimes/* vi_next_word():
2281573Srgrimes *	Vi move to the next word
2291573Srgrimes *	[w]
2301573Srgrimes */
2311573Srgrimesprotected el_action_t
2321573Srgrimes/*ARGSUSED*/
233313981Spfgvi_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
2341573Srgrimes{
2351573Srgrimes
236148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar - 1)
237276881Sbapt		return CC_ERROR;
2381573Srgrimes
23984260Sobrien	el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
240148834Sstefanf	    el->el_line.lastchar, el->el_state.argument, cv__isword);
2411573Srgrimes
24284260Sobrien	if (el->el_map.type == MAP_VI)
243148834Sstefanf		if (el->el_chared.c_vcmd.action != NOP) {
24484260Sobrien			cv_delfini(el);
245276881Sbapt			return CC_REFRESH;
24684260Sobrien		}
247276881Sbapt	return CC_CURSOR;
2481573Srgrimes}
2491573Srgrimes
2501573Srgrimes
2518870Srgrimes/* vi_change_case():
2521573Srgrimes *	Vi change case of character under the cursor and advance one character
2531573Srgrimes *	[~]
2541573Srgrimes */
2551573Srgrimesprotected el_action_t
256313981Spfgvi_change_case(EditLine *el, wint_t c)
2571573Srgrimes{
258148834Sstefanf	int i;
25984260Sobrien
260148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar)
261276881Sbapt		return CC_ERROR;
262148834Sstefanf	cv_undo(el);
263148834Sstefanf	for (i = 0; i < el->el_state.argument; i++) {
264148834Sstefanf
265276881Sbapt		c = *el->el_line.cursor;
266276881Sbapt		if (Isupper(c))
267276881Sbapt			*el->el_line.cursor = Tolower(c);
268276881Sbapt		else if (Islower(c))
269276881Sbapt			*el->el_line.cursor = Toupper(c);
270148834Sstefanf
271148834Sstefanf		if (++el->el_line.cursor >= el->el_line.lastchar) {
272148834Sstefanf			el->el_line.cursor--;
273148834Sstefanf			re_fastaddc(el);
274148834Sstefanf			break;
275148834Sstefanf		}
27684260Sobrien		re_fastaddc(el);
27784260Sobrien	}
278148834Sstefanf	return CC_NORM;
2791573Srgrimes}
2801573Srgrimes
2811573Srgrimes
2828870Srgrimes/* vi_change_meta():
2831573Srgrimes *	Vi change prefix command
2841573Srgrimes *	[c]
2851573Srgrimes */
2861573Srgrimesprotected el_action_t
2871573Srgrimes/*ARGSUSED*/
288313981Spfgvi_change_meta(EditLine *el, wint_t c __attribute__((__unused__)))
2891573Srgrimes{
29084260Sobrien
29184260Sobrien	/*
29284260Sobrien         * Delete with insert == change: first we delete and then we leave in
29384260Sobrien         * insert mode.
29484260Sobrien         */
295276881Sbapt	return cv_action(el, DELETE | INSERT);
2961573Srgrimes}
2971573Srgrimes
2981573Srgrimes
2998870Srgrimes/* vi_insert_at_bol():
3001573Srgrimes *	Vi enter insert mode at the beginning of line
3011573Srgrimes *	[I]
3021573Srgrimes */
3031573Srgrimesprotected el_action_t
3041573Srgrimes/*ARGSUSED*/
305313981Spfgvi_insert_at_bol(EditLine *el, wint_t c __attribute__((__unused__)))
3061573Srgrimes{
3071573Srgrimes
30884260Sobrien	el->el_line.cursor = el->el_line.buffer;
309148834Sstefanf	cv_undo(el);
31084260Sobrien	el->el_map.current = el->el_map.key;
311276881Sbapt	return CC_CURSOR;
3121573Srgrimes}
3131573Srgrimes
3141573Srgrimes
3158870Srgrimes/* vi_replace_char():
3161573Srgrimes *	Vi replace character under the cursor with the next character typed
3171573Srgrimes *	[r]
3181573Srgrimes */
3191573Srgrimesprotected el_action_t
3201573Srgrimes/*ARGSUSED*/
321313981Spfgvi_replace_char(EditLine *el, wint_t c __attribute__((__unused__)))
3221573Srgrimes{
32384260Sobrien
324148834Sstefanf	if (el->el_line.cursor >= el->el_line.lastchar)
325148834Sstefanf		return CC_ERROR;
326148834Sstefanf
32784260Sobrien	el->el_map.current = el->el_map.key;
32884260Sobrien	el->el_state.inputmode = MODE_REPLACE_1;
329148834Sstefanf	cv_undo(el);
330276881Sbapt	return CC_ARGHACK;
3311573Srgrimes}
3321573Srgrimes
3331573Srgrimes
3348870Srgrimes/* vi_replace_mode():
3351573Srgrimes *	Vi enter replace mode
3361573Srgrimes *	[R]
3371573Srgrimes */
3381573Srgrimesprotected el_action_t
3391573Srgrimes/*ARGSUSED*/
340313981Spfgvi_replace_mode(EditLine *el, wint_t c __attribute__((__unused__)))
3411573Srgrimes{
34284260Sobrien
34384260Sobrien	el->el_map.current = el->el_map.key;
34484260Sobrien	el->el_state.inputmode = MODE_REPLACE;
345148834Sstefanf	cv_undo(el);
346276881Sbapt	return CC_NORM;
3471573Srgrimes}
3481573Srgrimes
3491573Srgrimes
3508870Srgrimes/* vi_substitute_char():
3511573Srgrimes *	Vi replace character under the cursor and enter insert mode
35237199Sbrian *	[s]
3531573Srgrimes */
3541573Srgrimesprotected el_action_t
3551573Srgrimes/*ARGSUSED*/
356313981Spfgvi_substitute_char(EditLine *el, wint_t c __attribute__((__unused__)))
3571573Srgrimes{
35884260Sobrien
35984260Sobrien	c_delafter(el, el->el_state.argument);
36084260Sobrien	el->el_map.current = el->el_map.key;
361276881Sbapt	return CC_REFRESH;
3621573Srgrimes}
3631573Srgrimes
3641573Srgrimes
3658870Srgrimes/* vi_substitute_line():
3661573Srgrimes *	Vi substitute entire line
3671573Srgrimes *	[S]
3681573Srgrimes */
3691573Srgrimesprotected el_action_t
3701573Srgrimes/*ARGSUSED*/
371313981Spfgvi_substitute_line(EditLine *el, wint_t c __attribute__((__unused__)))
3721573Srgrimes{
37384260Sobrien
374148834Sstefanf	cv_undo(el);
375148834Sstefanf	cv_yank(el, el->el_line.buffer,
376237448Spfg	    (int)(el->el_line.lastchar - el->el_line.buffer));
37784260Sobrien	(void) em_kill_line(el, 0);
37884260Sobrien	el->el_map.current = el->el_map.key;
379276881Sbapt	return CC_REFRESH;
3801573Srgrimes}
3811573Srgrimes
3821573Srgrimes
3838870Srgrimes/* vi_change_to_eol():
3841573Srgrimes *	Vi change to end of line
3851573Srgrimes *	[C]
3861573Srgrimes */
3871573Srgrimesprotected el_action_t
3881573Srgrimes/*ARGSUSED*/
389313981Spfgvi_change_to_eol(EditLine *el, wint_t c __attribute__((__unused__)))
3901573Srgrimes{
39184260Sobrien
392148834Sstefanf	cv_undo(el);
393148834Sstefanf	cv_yank(el, el->el_line.cursor,
394237448Spfg	    (int)(el->el_line.lastchar - el->el_line.cursor));
39584260Sobrien	(void) ed_kill_line(el, 0);
39684260Sobrien	el->el_map.current = el->el_map.key;
397276881Sbapt	return CC_REFRESH;
3981573Srgrimes}
3991573Srgrimes
4001573Srgrimes
4011573Srgrimes/* vi_insert():
4021573Srgrimes *	Vi enter insert mode
4031573Srgrimes *	[i]
4041573Srgrimes */
4051573Srgrimesprotected el_action_t
4061573Srgrimes/*ARGSUSED*/
407313981Spfgvi_insert(EditLine *el, wint_t c __attribute__((__unused__)))
4081573Srgrimes{
4091573Srgrimes
41084260Sobrien	el->el_map.current = el->el_map.key;
411148834Sstefanf	cv_undo(el);
412276881Sbapt	return CC_NORM;
4131573Srgrimes}
4141573Srgrimes
4151573Srgrimes
4161573Srgrimes/* vi_add():
4178870Srgrimes *	Vi enter insert mode after the cursor
4181573Srgrimes *	[a]
4191573Srgrimes */
4201573Srgrimesprotected el_action_t
4211573Srgrimes/*ARGSUSED*/
422313981Spfgvi_add(EditLine *el, wint_t c __attribute__((__unused__)))
4231573Srgrimes{
424148834Sstefanf	int ret;
42537199Sbrian
42684260Sobrien	el->el_map.current = el->el_map.key;
42784260Sobrien	if (el->el_line.cursor < el->el_line.lastchar) {
42884260Sobrien		el->el_line.cursor++;
42984260Sobrien		if (el->el_line.cursor > el->el_line.lastchar)
43084260Sobrien			el->el_line.cursor = el->el_line.lastchar;
43184260Sobrien		ret = CC_CURSOR;
43284260Sobrien	} else
43384260Sobrien		ret = CC_NORM;
4341573Srgrimes
435148834Sstefanf	cv_undo(el);
4361573Srgrimes
437276881Sbapt	return (el_action_t)ret;
4381573Srgrimes}
4391573Srgrimes
4401573Srgrimes
4411573Srgrimes/* vi_add_at_eol():
4421573Srgrimes *	Vi enter insert mode at end of line
4431573Srgrimes *	[A]
4441573Srgrimes */
4451573Srgrimesprotected el_action_t
4461573Srgrimes/*ARGSUSED*/
447313981Spfgvi_add_at_eol(EditLine *el, wint_t c __attribute__((__unused__)))
4481573Srgrimes{
4491573Srgrimes
45084260Sobrien	el->el_map.current = el->el_map.key;
45184260Sobrien	el->el_line.cursor = el->el_line.lastchar;
452148834Sstefanf	cv_undo(el);
453276881Sbapt	return CC_CURSOR;
4541573Srgrimes}
4551573Srgrimes
4561573Srgrimes
4571573Srgrimes/* vi_delete_meta():
4588870Srgrimes *	Vi delete prefix command
4591573Srgrimes *	[d]
4601573Srgrimes */
4611573Srgrimesprotected el_action_t
4621573Srgrimes/*ARGSUSED*/
463313981Spfgvi_delete_meta(EditLine *el, wint_t c __attribute__((__unused__)))
4641573Srgrimes{
46584260Sobrien
466276881Sbapt	return cv_action(el, DELETE);
4671573Srgrimes}
4681573Srgrimes
4691573Srgrimes
470148834Sstefanf/* vi_end_big_word():
4718870Srgrimes *	Vi move to the end of the current space delimited word
4728870Srgrimes *	[E]
4731573Srgrimes */
4741573Srgrimesprotected el_action_t
4751573Srgrimes/*ARGSUSED*/
476313981Spfgvi_end_big_word(EditLine *el, wint_t c __attribute__((__unused__)))
4771573Srgrimes{
4781573Srgrimes
47984260Sobrien	if (el->el_line.cursor == el->el_line.lastchar)
480276881Sbapt		return CC_ERROR;
4811573Srgrimes
48284260Sobrien	el->el_line.cursor = cv__endword(el->el_line.cursor,
483148834Sstefanf	    el->el_line.lastchar, el->el_state.argument, cv__isWord);
4841573Srgrimes
485148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
48684260Sobrien		el->el_line.cursor++;
48784260Sobrien		cv_delfini(el);
488276881Sbapt		return CC_REFRESH;
48984260Sobrien	}
490276881Sbapt	return CC_CURSOR;
4911573Srgrimes}
4921573Srgrimes
4931573Srgrimes
494148834Sstefanf/* vi_end_word():
4951573Srgrimes *	Vi move to the end of the current word
4961573Srgrimes *	[e]
4971573Srgrimes */
4981573Srgrimesprotected el_action_t
4991573Srgrimes/*ARGSUSED*/
500313981Spfgvi_end_word(EditLine *el, wint_t c __attribute__((__unused__)))
5011573Srgrimes{
5021573Srgrimes
50384260Sobrien	if (el->el_line.cursor == el->el_line.lastchar)
504276881Sbapt		return CC_ERROR;
5051573Srgrimes
50684260Sobrien	el->el_line.cursor = cv__endword(el->el_line.cursor,
507148834Sstefanf	    el->el_line.lastchar, el->el_state.argument, cv__isword);
5081573Srgrimes
509148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
51084260Sobrien		el->el_line.cursor++;
51184260Sobrien		cv_delfini(el);
512276881Sbapt		return CC_REFRESH;
51384260Sobrien	}
514276881Sbapt	return CC_CURSOR;
5151573Srgrimes}
5161573Srgrimes
5171573Srgrimes
5181573Srgrimes/* vi_undo():
5191573Srgrimes *	Vi undo last change
5201573Srgrimes *	[u]
5211573Srgrimes */
5221573Srgrimesprotected el_action_t
5231573Srgrimes/*ARGSUSED*/
524313981Spfgvi_undo(EditLine *el, wint_t c __attribute__((__unused__)))
5251573Srgrimes{
526148834Sstefanf	c_undo_t un = el->el_chared.c_undo;
5271573Srgrimes
528148834Sstefanf	if (un.len == -1)
529148834Sstefanf		return CC_ERROR;
5301573Srgrimes
531148834Sstefanf	/* switch line buffer and undo buffer */
532148834Sstefanf	el->el_chared.c_undo.buf = el->el_line.buffer;
533148834Sstefanf	el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer;
534237448Spfg	el->el_chared.c_undo.cursor =
535237448Spfg	    (int)(el->el_line.cursor - el->el_line.buffer);
536148834Sstefanf	el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer);
537148834Sstefanf	el->el_line.buffer = un.buf;
538148834Sstefanf	el->el_line.cursor = un.buf + un.cursor;
539148834Sstefanf	el->el_line.lastchar = un.buf + un.len;
5401573Srgrimes
541276881Sbapt	return CC_REFRESH;
5421573Srgrimes}
5431573Srgrimes
5441573Srgrimes
5451573Srgrimes/* vi_command_mode():
5461573Srgrimes *	Vi enter command mode (use alternative key bindings)
5471573Srgrimes *	[<ESC>]
5481573Srgrimes */
5491573Srgrimesprotected el_action_t
5501573Srgrimes/*ARGSUSED*/
551313981Spfgvi_command_mode(EditLine *el, wint_t c __attribute__((__unused__)))
5521573Srgrimes{
5531573Srgrimes
55484260Sobrien	/* [Esc] cancels pending action */
55584260Sobrien	el->el_chared.c_vcmd.action = NOP;
55684260Sobrien	el->el_chared.c_vcmd.pos = 0;
5571573Srgrimes
55884260Sobrien	el->el_state.doingarg = 0;
55984260Sobrien
56084260Sobrien	el->el_state.inputmode = MODE_INSERT;
56184260Sobrien	el->el_map.current = el->el_map.alt;
5621573Srgrimes#ifdef VI_MOVE
56384260Sobrien	if (el->el_line.cursor > el->el_line.buffer)
56484260Sobrien		el->el_line.cursor--;
5651573Srgrimes#endif
566276881Sbapt	return CC_CURSOR;
5671573Srgrimes}
5681573Srgrimes
56984260Sobrien
5701573Srgrimes/* vi_zero():
5718870Srgrimes *	Vi move to the beginning of line
5721573Srgrimes *	[0]
5731573Srgrimes */
5741573Srgrimesprotected el_action_t
575313981Spfgvi_zero(EditLine *el, wint_t c)
5761573Srgrimes{
57784260Sobrien
578148834Sstefanf	if (el->el_state.doingarg)
579148834Sstefanf		return ed_argument_digit(el, c);
580148834Sstefanf
581148834Sstefanf	el->el_line.cursor = el->el_line.buffer;
582148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
583148834Sstefanf		cv_delfini(el);
584276881Sbapt		return CC_REFRESH;
58584260Sobrien	}
586276881Sbapt	return CC_CURSOR;
5871573Srgrimes}
5881573Srgrimes
5891573Srgrimes
5901573Srgrimes/* vi_delete_prev_char():
591313981Spfg *	Vi move to previous character (backspace)
592148834Sstefanf *	[^H] in insert mode only
5938870Srgrimes */
5941573Srgrimesprotected el_action_t
5951573Srgrimes/*ARGSUSED*/
596313981Spfgvi_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
5971573Srgrimes{
5981573Srgrimes
599148834Sstefanf	if (el->el_line.cursor <= el->el_line.buffer)
600276881Sbapt		return CC_ERROR;
6011573Srgrimes
602148834Sstefanf	c_delbefore1(el);
603148834Sstefanf	el->el_line.cursor--;
604276881Sbapt	return CC_REFRESH;
60584260Sobrien}
6061573Srgrimes
60784260Sobrien
6081573Srgrimes/* vi_list_or_eof():
6091573Srgrimes *	Vi list choices for completion or indicate end of file if empty line
6101573Srgrimes *	[^D]
6111573Srgrimes */
6121573Srgrimesprotected el_action_t
6131573Srgrimes/*ARGSUSED*/
614313981Spfgvi_list_or_eof(EditLine *el, wint_t c)
6151573Srgrimes{
61684260Sobrien
617148834Sstefanf	if (el->el_line.cursor == el->el_line.lastchar) {
618148834Sstefanf		if (el->el_line.cursor == el->el_line.buffer) {
619276881Sbapt			terminal_writec(el, c);	/* then do a EOF */
620276881Sbapt			return CC_EOF;
621148834Sstefanf		} else {
622148834Sstefanf			/*
623148834Sstefanf			 * Here we could list completions, but it is an
624148834Sstefanf			 * error right now
625148834Sstefanf			 */
626276881Sbapt			terminal_beep(el);
627276881Sbapt			return CC_ERROR;
628148834Sstefanf		}
629148834Sstefanf	} else {
6301573Srgrimes#ifdef notyet
63184260Sobrien		re_goto_bottom(el);
63284260Sobrien		*el->el_line.lastchar = '\0';	/* just in case */
633276881Sbapt		return CC_LIST_CHOICES;
634148834Sstefanf#else
635148834Sstefanf		/*
636148834Sstefanf		 * Just complain for now.
637148834Sstefanf		 */
638276881Sbapt		terminal_beep(el);
639276881Sbapt		return CC_ERROR;
640148834Sstefanf#endif
64184260Sobrien	}
6421573Srgrimes}
6431573Srgrimes
6441573Srgrimes
6451573Srgrimes/* vi_kill_line_prev():
6468870Srgrimes *	Vi cut from beginning of line to cursor
6471573Srgrimes *	[^U]
6481573Srgrimes */
6491573Srgrimesprotected el_action_t
6501573Srgrimes/*ARGSUSED*/
651313981Spfgvi_kill_line_prev(EditLine *el, wint_t c __attribute__((__unused__)))
6521573Srgrimes{
653276881Sbapt	Char *kp, *cp;
6541573Srgrimes
65584260Sobrien	cp = el->el_line.buffer;
65684260Sobrien	kp = el->el_chared.c_kill.buf;
65784260Sobrien	while (cp < el->el_line.cursor)
65884260Sobrien		*kp++ = *cp++;	/* copy it */
65984260Sobrien	el->el_chared.c_kill.last = kp;
660237448Spfg	c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer));
66184260Sobrien	el->el_line.cursor = el->el_line.buffer;	/* zap! */
662276881Sbapt	return CC_REFRESH;
6631573Srgrimes}
6641573Srgrimes
6651573Srgrimes
6661573Srgrimes/* vi_search_prev():
6671573Srgrimes *	Vi search history previous
6681573Srgrimes *	[?]
6691573Srgrimes */
6701573Srgrimesprotected el_action_t
6711573Srgrimes/*ARGSUSED*/
672313981Spfgvi_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
6731573Srgrimes{
67484260Sobrien
675276881Sbapt	return cv_search(el, ED_SEARCH_PREV_HISTORY);
6761573Srgrimes}
6771573Srgrimes
6781573Srgrimes
6791573Srgrimes/* vi_search_next():
6801573Srgrimes *	Vi search history next
6811573Srgrimes *	[/]
6821573Srgrimes */
6831573Srgrimesprotected el_action_t
6841573Srgrimes/*ARGSUSED*/
685313981Spfgvi_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
6861573Srgrimes{
68784260Sobrien
688276881Sbapt	return cv_search(el, ED_SEARCH_NEXT_HISTORY);
6891573Srgrimes}
6901573Srgrimes
6911573Srgrimes
6921573Srgrimes/* vi_repeat_search_next():
6931573Srgrimes *	Vi repeat current search in the same search direction
6941573Srgrimes *	[n]
6951573Srgrimes */
6961573Srgrimesprotected el_action_t
6971573Srgrimes/*ARGSUSED*/
698313981Spfgvi_repeat_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
6991573Srgrimes{
70084260Sobrien
70184260Sobrien	if (el->el_search.patlen == 0)
702276881Sbapt		return CC_ERROR;
70384260Sobrien	else
704276881Sbapt		return cv_repeat_srch(el, el->el_search.patdir);
7051573Srgrimes}
7061573Srgrimes
7071573Srgrimes
7081573Srgrimes/* vi_repeat_search_prev():
7091573Srgrimes *	Vi repeat current search in the opposite search direction
7101573Srgrimes *	[N]
7111573Srgrimes */
7121573Srgrimes/*ARGSUSED*/
7131573Srgrimesprotected el_action_t
714313981Spfgvi_repeat_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
7151573Srgrimes{
71684260Sobrien
71784260Sobrien	if (el->el_search.patlen == 0)
718276881Sbapt		return CC_ERROR;
71984260Sobrien	else
72084260Sobrien		return (cv_repeat_srch(el,
72184260Sobrien		    el->el_search.patdir == ED_SEARCH_PREV_HISTORY ?
72284260Sobrien		    ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY));
7231573Srgrimes}
7241573Srgrimes
7251573Srgrimes
7261573Srgrimes/* vi_next_char():
7271573Srgrimes *	Vi move to the character specified next
7281573Srgrimes *	[f]
7291573Srgrimes */
7301573Srgrimesprotected el_action_t
7311573Srgrimes/*ARGSUSED*/
732313981Spfgvi_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
7331573Srgrimes{
734148834Sstefanf	return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0);
7351573Srgrimes}
7361573Srgrimes
7371573Srgrimes
7381573Srgrimes/* vi_prev_char():
7391573Srgrimes *	Vi move to the character specified previous
7401573Srgrimes *	[F]
7411573Srgrimes */
7421573Srgrimesprotected el_action_t
7431573Srgrimes/*ARGSUSED*/
744313981Spfgvi_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
7451573Srgrimes{
746148834Sstefanf	return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0);
7471573Srgrimes}
7481573Srgrimes
7491573Srgrimes
7501573Srgrimes/* vi_to_next_char():
7511573Srgrimes *	Vi move up to the character specified next
7521573Srgrimes *	[t]
7531573Srgrimes */
7541573Srgrimesprotected el_action_t
7551573Srgrimes/*ARGSUSED*/
756313981Spfgvi_to_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
7571573Srgrimes{
758148834Sstefanf	return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1);
7591573Srgrimes}
7601573Srgrimes
7611573Srgrimes
7621573Srgrimes/* vi_to_prev_char():
7631573Srgrimes *	Vi move up to the character specified previous
7641573Srgrimes *	[T]
7651573Srgrimes */
7661573Srgrimesprotected el_action_t
7671573Srgrimes/*ARGSUSED*/
768313981Spfgvi_to_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
7691573Srgrimes{
770148834Sstefanf	return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1);
7711573Srgrimes}
7721573Srgrimes
7731573Srgrimes
7741573Srgrimes/* vi_repeat_next_char():
7751573Srgrimes *	Vi repeat current character search in the same search direction
7761573Srgrimes *	[;]
7771573Srgrimes */
7781573Srgrimesprotected el_action_t
7791573Srgrimes/*ARGSUSED*/
780313981Spfgvi_repeat_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
7811573Srgrimes{
7821573Srgrimes
783148834Sstefanf	return cv_csearch(el, el->el_search.chadir, el->el_search.chacha,
784148834Sstefanf		el->el_state.argument, el->el_search.chatflg);
7851573Srgrimes}
7861573Srgrimes
7871573Srgrimes
7881573Srgrimes/* vi_repeat_prev_char():
7891573Srgrimes *	Vi repeat current character search in the opposite search direction
7901573Srgrimes *	[,]
7911573Srgrimes */
7921573Srgrimesprotected el_action_t
7931573Srgrimes/*ARGSUSED*/
794313981Spfgvi_repeat_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
7951573Srgrimes{
796148834Sstefanf	el_action_t r;
797148834Sstefanf	int dir = el->el_search.chadir;
7981573Srgrimes
799148834Sstefanf	r = cv_csearch(el, -dir, el->el_search.chacha,
800148834Sstefanf		el->el_state.argument, el->el_search.chatflg);
801148834Sstefanf	el->el_search.chadir = dir;
802148834Sstefanf	return r;
803148834Sstefanf}
80484260Sobrien
805148834Sstefanf
806148834Sstefanf/* vi_match():
807148834Sstefanf *	Vi go to matching () {} or []
808148834Sstefanf *	[%]
809148834Sstefanf */
810148834Sstefanfprotected el_action_t
811148834Sstefanf/*ARGSUSED*/
812313981Spfgvi_match(EditLine *el, wint_t c __attribute__((__unused__)))
813148834Sstefanf{
814276881Sbapt	const Char match_chars[] = STR("()[]{}");
815276881Sbapt	Char *cp;
816237448Spfg	size_t delta, i, count;
817276881Sbapt	Char o_ch, c_ch;
818148834Sstefanf
819148834Sstefanf	*el->el_line.lastchar = '\0';		/* just in case */
820148834Sstefanf
821276881Sbapt	i = Strcspn(el->el_line.cursor, match_chars);
822148834Sstefanf	o_ch = el->el_line.cursor[i];
823148834Sstefanf	if (o_ch == 0)
824148834Sstefanf		return CC_ERROR;
825276881Sbapt	delta = (size_t)(Strchr(match_chars, o_ch) - match_chars);
826148834Sstefanf	c_ch = match_chars[delta ^ 1];
827148834Sstefanf	count = 1;
828148834Sstefanf	delta = 1 - (delta & 1) * 2;
829148834Sstefanf
830148834Sstefanf	for (cp = &el->el_line.cursor[i]; count; ) {
831148834Sstefanf		cp += delta;
832148834Sstefanf		if (cp < el->el_line.buffer || cp >= el->el_line.lastchar)
833148834Sstefanf			return CC_ERROR;
834148834Sstefanf		if (*cp == o_ch)
835148834Sstefanf			count++;
836148834Sstefanf		else if (*cp == c_ch)
837148834Sstefanf			count--;
838148834Sstefanf	}
839148834Sstefanf
840148834Sstefanf	el->el_line.cursor = cp;
841148834Sstefanf
842148834Sstefanf	if (el->el_chared.c_vcmd.action != NOP) {
843148834Sstefanf		/* NB posix says char under cursor should NOT be deleted
844148834Sstefanf		   for -ve delta - this is different to netbsd vi. */
845148834Sstefanf		if (delta > 0)
846148834Sstefanf			el->el_line.cursor++;
847148834Sstefanf		cv_delfini(el);
848276881Sbapt		return CC_REFRESH;
849148834Sstefanf	}
850276881Sbapt	return CC_CURSOR;
8511573Srgrimes}
852148834Sstefanf
853148834Sstefanf/* vi_undo_line():
854148834Sstefanf *	Vi undo all changes to line
855148834Sstefanf *	[U]
856148834Sstefanf */
857148834Sstefanfprotected el_action_t
858148834Sstefanf/*ARGSUSED*/
859313981Spfgvi_undo_line(EditLine *el, wint_t c __attribute__((__unused__)))
860148834Sstefanf{
861148834Sstefanf
862148834Sstefanf	cv_undo(el);
863148834Sstefanf	return hist_get(el);
864148834Sstefanf}
865148834Sstefanf
866148834Sstefanf/* vi_to_column():
867148834Sstefanf *	Vi go to specified column
868148834Sstefanf *	[|]
869148834Sstefanf * NB netbsd vi goes to screen column 'n', posix says nth character
870148834Sstefanf */
871148834Sstefanfprotected el_action_t
872148834Sstefanf/*ARGSUSED*/
873313981Spfgvi_to_column(EditLine *el, wint_t c __attribute__((__unused__)))
874148834Sstefanf{
875148834Sstefanf
876148834Sstefanf	el->el_line.cursor = el->el_line.buffer;
877148834Sstefanf	el->el_state.argument--;
878148834Sstefanf	return ed_next_char(el, 0);
879148834Sstefanf}
880148834Sstefanf
881148834Sstefanf/* vi_yank_end():
882148834Sstefanf *	Vi yank to end of line
883148834Sstefanf *	[Y]
884148834Sstefanf */
885148834Sstefanfprotected el_action_t
886148834Sstefanf/*ARGSUSED*/
887313981Spfgvi_yank_end(EditLine *el, wint_t c __attribute__((__unused__)))
888148834Sstefanf{
889148834Sstefanf
890148834Sstefanf	cv_yank(el, el->el_line.cursor,
891237448Spfg	    (int)(el->el_line.lastchar - el->el_line.cursor));
892148834Sstefanf	return CC_REFRESH;
893148834Sstefanf}
894148834Sstefanf
895148834Sstefanf/* vi_yank():
896148834Sstefanf *	Vi yank
897148834Sstefanf *	[y]
898148834Sstefanf */
899148834Sstefanfprotected el_action_t
900148834Sstefanf/*ARGSUSED*/
901313981Spfgvi_yank(EditLine *el, wint_t c __attribute__((__unused__)))
902148834Sstefanf{
903148834Sstefanf
904148834Sstefanf	return cv_action(el, YANK);
905148834Sstefanf}
906148834Sstefanf
907148834Sstefanf/* vi_comment_out():
908148834Sstefanf *	Vi comment out current command
909148848Sstefanf *	[#]
910148834Sstefanf */
911148834Sstefanfprotected el_action_t
912148834Sstefanf/*ARGSUSED*/
913313981Spfgvi_comment_out(EditLine *el, wint_t c __attribute__((__unused__)))
914148834Sstefanf{
915148834Sstefanf
916148834Sstefanf	el->el_line.cursor = el->el_line.buffer;
917148834Sstefanf	c_insert(el, 1);
918148834Sstefanf	*el->el_line.cursor = '#';
919148834Sstefanf	re_refresh(el);
920148834Sstefanf	return ed_newline(el, 0);
921148834Sstefanf}
922148834Sstefanf
923148834Sstefanf/* vi_alias():
924148834Sstefanf *	Vi include shell alias
925148834Sstefanf *	[@]
926148848Sstefanf * NB: posix implies that we should enter insert mode, however
927148834Sstefanf * this is against historical precedent...
928148834Sstefanf */
929148834Sstefanfprotected el_action_t
930148834Sstefanf/*ARGSUSED*/
931313981Spfgvi_alias(EditLine *el, wint_t c __attribute__((__unused__)))
932148834Sstefanf{
933148834Sstefanf	char alias_name[3];
934276881Sbapt	const char *alias_text;
935148834Sstefanf
936276881Sbapt	if (el->el_chared.c_aliasfun == NULL)
937148834Sstefanf		return CC_ERROR;
938148834Sstefanf
939148834Sstefanf	alias_name[0] = '_';
940148834Sstefanf	alias_name[2] = 0;
941148834Sstefanf	if (el_getc(el, &alias_name[1]) != 1)
942148834Sstefanf		return CC_ERROR;
943148834Sstefanf
944276881Sbapt	alias_text = (*el->el_chared.c_aliasfun)(el->el_chared.c_aliasarg,
945276881Sbapt	    alias_name);
946148834Sstefanf	if (alias_text != NULL)
947276881Sbapt		FUN(el,push)(el, ct_decode_string(alias_text, &el->el_scratch));
948148834Sstefanf	return CC_NORM;
949148834Sstefanf}
950148834Sstefanf
951148834Sstefanf/* vi_to_history_line():
952148834Sstefanf *	Vi go to specified history file line.
953148834Sstefanf *	[G]
954148834Sstefanf */
955148834Sstefanfprotected el_action_t
956148834Sstefanf/*ARGSUSED*/
957313981Spfgvi_to_history_line(EditLine *el, wint_t c __attribute__((__unused__)))
958148834Sstefanf{
959148834Sstefanf	int sv_event_no = el->el_history.eventno;
960148834Sstefanf	el_action_t rval;
961148834Sstefanf
962148834Sstefanf
963148834Sstefanf	if (el->el_history.eventno == 0) {
964276881Sbapt		 (void) Strncpy(el->el_history.buf, el->el_line.buffer,
965148834Sstefanf		     EL_BUFSIZ);
966148834Sstefanf		 el->el_history.last = el->el_history.buf +
967148834Sstefanf			 (el->el_line.lastchar - el->el_line.buffer);
968148834Sstefanf	}
969148834Sstefanf
970148834Sstefanf	/* Lack of a 'count' means oldest, not 1 */
971148834Sstefanf	if (!el->el_state.doingarg) {
972148834Sstefanf		el->el_history.eventno = 0x7fffffff;
973148834Sstefanf		hist_get(el);
974148834Sstefanf	} else {
975148834Sstefanf		/* This is brain dead, all the rest of this code counts
976148834Sstefanf		 * upwards going into the past.  Here we need count in the
977148834Sstefanf		 * other direction (to match the output of fc -l).
978148834Sstefanf		 * I could change the world, but this seems to suffice.
979148834Sstefanf		 */
980148834Sstefanf		el->el_history.eventno = 1;
981148834Sstefanf		if (hist_get(el) == CC_ERROR)
982148834Sstefanf			return CC_ERROR;
983313981Spfg		el->el_history.eventno = 1 + el->el_history.ev.num
984148834Sstefanf					- el->el_state.argument;
985148834Sstefanf		if (el->el_history.eventno < 0) {
986148834Sstefanf			el->el_history.eventno = sv_event_no;
987148834Sstefanf			return CC_ERROR;
988148834Sstefanf		}
989148834Sstefanf	}
990148834Sstefanf	rval = hist_get(el);
991148834Sstefanf	if (rval == CC_ERROR)
992148834Sstefanf		el->el_history.eventno = sv_event_no;
993148834Sstefanf	return rval;
994148834Sstefanf}
995148834Sstefanf
996148834Sstefanf/* vi_histedit():
997148834Sstefanf *	Vi edit history line with vi
998148834Sstefanf *	[v]
999148834Sstefanf */
1000148834Sstefanfprotected el_action_t
1001148834Sstefanf/*ARGSUSED*/
1002313981Spfgvi_histedit(EditLine *el, wint_t c __attribute__((__unused__)))
1003148834Sstefanf{
1004148834Sstefanf	int fd;
1005148834Sstefanf	pid_t pid;
1006237448Spfg	ssize_t st;
1007237448Spfg	int status;
1008148834Sstefanf	char tempfile[] = "/tmp/histedit.XXXXXXXXXX";
1009276881Sbapt	char *cp = NULL;
1010276881Sbapt	size_t len;
1011276881Sbapt	Char *line = NULL;
1012148834Sstefanf
1013148834Sstefanf	if (el->el_state.doingarg) {
1014148834Sstefanf		if (vi_to_history_line(el, 0) == CC_ERROR)
1015148834Sstefanf			return CC_ERROR;
1016148834Sstefanf	}
1017148834Sstefanf
1018148834Sstefanf	fd = mkstemp(tempfile);
1019148834Sstefanf	if (fd < 0)
1020148834Sstefanf		return CC_ERROR;
1021276881Sbapt	len = (size_t)(el->el_line.lastchar - el->el_line.buffer);
1022276881Sbapt#define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX)
1023276881Sbapt	cp = el_malloc(TMP_BUFSIZ * sizeof(*cp));
1024276881Sbapt	if (cp == NULL)
1025276881Sbapt		goto error;
1026276881Sbapt	line = el_malloc(len * sizeof(*line) + 1);
1027276881Sbapt	if (line == NULL)
1028276881Sbapt		goto error;
1029276881Sbapt	Strncpy(line, el->el_line.buffer, len);
1030276881Sbapt	line[len] = '\0';
1031276881Sbapt	ct_wcstombs(cp, line, TMP_BUFSIZ - 1);
1032276881Sbapt	cp[TMP_BUFSIZ - 1] = '\0';
1033276881Sbapt	len = strlen(cp);
1034276881Sbapt	write(fd, cp, len);
1035276881Sbapt	write(fd, "\n", (size_t)1);
1036148834Sstefanf	pid = fork();
1037148834Sstefanf	switch (pid) {
1038148834Sstefanf	case -1:
1039276881Sbapt		goto error;
1040148834Sstefanf	case 0:
1041148834Sstefanf		close(fd);
1042237448Spfg		execlp("vi", "vi", tempfile, (char *)NULL);
1043148834Sstefanf		exit(0);
1044148834Sstefanf		/*NOTREACHED*/
1045148834Sstefanf	default:
1046237448Spfg		while (waitpid(pid, &status, 0) != pid)
1047148834Sstefanf			continue;
1048237448Spfg		lseek(fd, (off_t)0, SEEK_SET);
1049290065Sjilles		st = read(fd, cp, TMP_BUFSIZ - 1);
1050276881Sbapt		if (st > 0) {
1051290065Sjilles			cp[st] = '\0';
1052290065Sjilles			len = (size_t)(el->el_line.limit - el->el_line.buffer);
1053276881Sbapt			len = ct_mbstowcs(el->el_line.buffer, cp, len);
1054290065Sjilles			if (len > 0 && el->el_line.buffer[len - 1] == '\n')
1055276881Sbapt				--len;
1056276881Sbapt		}
1057276881Sbapt		else
1058276881Sbapt			len = 0;
1059276881Sbapt                el->el_line.cursor = el->el_line.buffer;
1060276881Sbapt                el->el_line.lastchar = el->el_line.buffer + len;
1061276881Sbapt		el_free(cp);
1062276881Sbapt                el_free(line);
1063148834Sstefanf		break;
1064148834Sstefanf	}
1065148834Sstefanf
1066148834Sstefanf	close(fd);
1067148834Sstefanf	unlink(tempfile);
1068148834Sstefanf	/* return CC_REFRESH; */
1069148834Sstefanf	return ed_newline(el, 0);
1070276881Sbapterror:
1071276881Sbapt	el_free(line);
1072276881Sbapt	el_free(cp);
1073276881Sbapt	close(fd);
1074276881Sbapt	unlink(tempfile);
1075276881Sbapt	return CC_ERROR;
1076148834Sstefanf}
1077148834Sstefanf
1078148834Sstefanf/* vi_history_word():
1079148834Sstefanf *	Vi append word from previous input line
1080148834Sstefanf *	[_]
1081148834Sstefanf * Who knows where this one came from!
1082148834Sstefanf * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_'
1083148834Sstefanf */
1084148834Sstefanfprotected el_action_t
1085148834Sstefanf/*ARGSUSED*/
1086313981Spfgvi_history_word(EditLine *el, wint_t c __attribute__((__unused__)))
1087148834Sstefanf{
1088276881Sbapt	const Char *wp = HIST_FIRST(el);
1089276881Sbapt	const Char *wep, *wsp;
1090148834Sstefanf	int len;
1091276881Sbapt	Char *cp;
1092276881Sbapt	const Char *lim;
1093148834Sstefanf
1094148834Sstefanf	if (wp == NULL)
1095148834Sstefanf		return CC_ERROR;
1096148834Sstefanf
1097297757Spfg	wep = wsp = NULL;
1098148834Sstefanf	do {
1099276881Sbapt		while (Isspace(*wp))
1100148834Sstefanf			wp++;
1101148834Sstefanf		if (*wp == 0)
1102148834Sstefanf			break;
1103148834Sstefanf		wsp = wp;
1104276881Sbapt		while (*wp && !Isspace(*wp))
1105148834Sstefanf			wp++;
1106148834Sstefanf		wep = wp;
1107276881Sbapt	} while ((!el->el_state.doingarg || --el->el_state.argument > 0)
1108276881Sbapt	    && *wp != 0);
1109148834Sstefanf
1110297757Spfg	if (wsp == NULL || (el->el_state.doingarg && el->el_state.argument != 0))
1111148834Sstefanf		return CC_ERROR;
1112148834Sstefanf
1113148834Sstefanf	cv_undo(el);
1114237448Spfg	len = (int)(wep - wsp);
1115148834Sstefanf	if (el->el_line.cursor < el->el_line.lastchar)
1116148834Sstefanf		el->el_line.cursor++;
1117148834Sstefanf	c_insert(el, len + 1);
1118148834Sstefanf	cp = el->el_line.cursor;
1119148834Sstefanf	lim = el->el_line.limit;
1120148834Sstefanf	if (cp < lim)
1121148834Sstefanf		*cp++ = ' ';
1122148834Sstefanf	while (wsp < wep && cp < lim)
1123148834Sstefanf		*cp++ = *wsp++;
1124148834Sstefanf	el->el_line.cursor = cp;
1125148834Sstefanf
1126148834Sstefanf	el->el_map.current = el->el_map.key;
1127148834Sstefanf	return CC_REFRESH;
1128148834Sstefanf}
1129148834Sstefanf
1130148834Sstefanf/* vi_redo():
1131148834Sstefanf *	Vi redo last non-motion command
1132148834Sstefanf *	[.]
1133148834Sstefanf */
1134148834Sstefanfprotected el_action_t
1135148834Sstefanf/*ARGSUSED*/
1136313981Spfgvi_redo(EditLine *el, wint_t c __attribute__((__unused__)))
1137148834Sstefanf{
1138148834Sstefanf	c_redo_t *r = &el->el_chared.c_redo;
1139148834Sstefanf
1140148834Sstefanf	if (!el->el_state.doingarg && r->count) {
1141148834Sstefanf		el->el_state.doingarg = 1;
1142148834Sstefanf		el->el_state.argument = r->count;
1143148834Sstefanf	}
1144148834Sstefanf
1145148834Sstefanf	el->el_chared.c_vcmd.pos = el->el_line.cursor;
1146148834Sstefanf	el->el_chared.c_vcmd.action = r->action;
1147148834Sstefanf	if (r->pos != r->buf) {
1148148834Sstefanf		if (r->pos + 1 > r->lim)
1149148834Sstefanf			/* sanity */
1150148834Sstefanf			r->pos = r->lim - 1;
1151148834Sstefanf		r->pos[0] = 0;
1152276881Sbapt		FUN(el,push)(el, r->buf);
1153148834Sstefanf	}
1154148834Sstefanf
1155148834Sstefanf	el->el_state.thiscmd = r->cmd;
1156148834Sstefanf	el->el_state.thisch = r->ch;
1157276881Sbapt	return (*el->el_map.func[r->cmd])(el, r->ch);
1158148834Sstefanf}
1159