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