Home | History | Annotate | Line # | Download | only in libedit
vi.c revision 1.28.2.1
      1  1.28.2.1       jym /*	$NetBSD: vi.c,v 1.28.2.1 2009/05/13 19:18:29 jym Exp $	*/
      2       1.2     lukem 
      3       1.1       cgd /*-
      4       1.1       cgd  * Copyright (c) 1992, 1993
      5       1.1       cgd  *	The Regents of the University of California.  All rights reserved.
      6       1.1       cgd  *
      7       1.1       cgd  * This code is derived from software contributed to Berkeley by
      8       1.1       cgd  * Christos Zoulas of Cornell University.
      9       1.1       cgd  *
     10       1.1       cgd  * Redistribution and use in source and binary forms, with or without
     11       1.1       cgd  * modification, are permitted provided that the following conditions
     12       1.1       cgd  * are met:
     13       1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     14       1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     15       1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     17       1.1       cgd  *    documentation and/or other materials provided with the distribution.
     18      1.19       agc  * 3. Neither the name of the University nor the names of its contributors
     19       1.1       cgd  *    may be used to endorse or promote products derived from this software
     20       1.1       cgd  *    without specific prior written permission.
     21       1.1       cgd  *
     22       1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23       1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24       1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25       1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26       1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27       1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28       1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29       1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30       1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31       1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32       1.1       cgd  * SUCH DAMAGE.
     33       1.1       cgd  */
     34       1.1       cgd 
     35       1.9  christos #include "config.h"
     36      1.12  christos #include <stdlib.h>
     37      1.12  christos #include <unistd.h>
     38      1.12  christos #include <sys/wait.h>
     39      1.12  christos 
     40       1.1       cgd #if !defined(lint) && !defined(SCCSID)
     41       1.2     lukem #if 0
     42       1.1       cgd static char sccsid[] = "@(#)vi.c	8.1 (Berkeley) 6/4/93";
     43       1.2     lukem #else
     44  1.28.2.1       jym __RCSID("$NetBSD: vi.c,v 1.28.2.1 2009/05/13 19:18:29 jym Exp $");
     45       1.2     lukem #endif
     46       1.1       cgd #endif /* not lint && not SCCSID */
     47       1.1       cgd 
     48       1.1       cgd /*
     49       1.1       cgd  * vi.c: Vi mode commands.
     50       1.1       cgd  */
     51       1.1       cgd #include "el.h"
     52       1.1       cgd 
     53       1.8     lukem private el_action_t	cv_action(EditLine *, int);
     54       1.8     lukem private el_action_t	cv_paste(EditLine *, int);
     55       1.1       cgd 
     56       1.1       cgd /* cv_action():
     57       1.1       cgd  *	Handle vi actions.
     58       1.1       cgd  */
     59       1.1       cgd private el_action_t
     60       1.8     lukem cv_action(EditLine *el, int c)
     61       1.1       cgd {
     62       1.1       cgd 
     63      1.12  christos 	if (el->el_chared.c_vcmd.action != NOP) {
     64      1.12  christos 		/* 'cc', 'dd' and (possibly) friends */
     65      1.12  christos 		if (c != el->el_chared.c_vcmd.action)
     66      1.12  christos 			return CC_ERROR;
     67      1.12  christos 
     68      1.12  christos 		if (!(c & YANK))
     69      1.12  christos 			cv_undo(el);
     70      1.12  christos 		cv_yank(el, el->el_line.buffer,
     71  1.28.2.1       jym 		    (int)(el->el_line.lastchar - el->el_line.buffer));
     72       1.8     lukem 		el->el_chared.c_vcmd.action = NOP;
     73       1.8     lukem 		el->el_chared.c_vcmd.pos = 0;
     74      1.23  christos 		if (!(c & YANK)) {
     75      1.23  christos 			el->el_line.lastchar = el->el_line.buffer;
     76      1.23  christos 			el->el_line.cursor = el->el_line.buffer;
     77      1.23  christos 		}
     78       1.8     lukem 		if (c & INSERT)
     79       1.8     lukem 			el->el_map.current = el->el_map.key;
     80       1.7    simonb 
     81       1.8     lukem 		return (CC_REFRESH);
     82       1.1       cgd 	}
     83       1.8     lukem 	el->el_chared.c_vcmd.pos = el->el_line.cursor;
     84       1.8     lukem 	el->el_chared.c_vcmd.action = c;
     85       1.8     lukem 	return (CC_ARGHACK);
     86       1.1       cgd }
     87       1.1       cgd 
     88       1.1       cgd /* cv_paste():
     89       1.1       cgd  *	Paste previous deletion before or after the cursor
     90       1.1       cgd  */
     91       1.3  christos private el_action_t
     92       1.8     lukem cv_paste(EditLine *el, int c)
     93       1.1       cgd {
     94      1.12  christos 	c_kill_t *k = &el->el_chared.c_kill;
     95  1.28.2.1       jym 	size_t len = (size_t)(k->last - k->buf);
     96       1.8     lukem 
     97      1.12  christos 	if (k->buf == NULL || len == 0)
     98      1.12  christos 		return (CC_ERROR);
     99       1.1       cgd #ifdef DEBUG_PASTE
    100  1.28.2.1       jym 	(void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", (int)len, k->buf);
    101       1.1       cgd #endif
    102       1.1       cgd 
    103      1.12  christos 	cv_undo(el);
    104      1.10  christos 
    105       1.8     lukem 	if (!c && el->el_line.cursor < el->el_line.lastchar)
    106       1.8     lukem 		el->el_line.cursor++;
    107       1.8     lukem 
    108  1.28.2.1       jym 	c_insert(el, (int)len);
    109      1.12  christos 	if (el->el_line.cursor + len > el->el_line.lastchar)
    110       1.8     lukem 		return (CC_ERROR);
    111  1.28.2.1       jym 	(void) memcpy(el->el_line.cursor, k->buf, len);
    112      1.24  christos 
    113       1.8     lukem 	return (CC_REFRESH);
    114       1.1       cgd }
    115       1.1       cgd 
    116       1.1       cgd 
    117       1.7    simonb /* vi_paste_next():
    118       1.1       cgd  *	Vi paste previous deletion to the right of the cursor
    119       1.1       cgd  *	[p]
    120       1.1       cgd  */
    121       1.1       cgd protected el_action_t
    122       1.1       cgd /*ARGSUSED*/
    123      1.18  christos vi_paste_next(EditLine *el, int c __attribute__((__unused__)))
    124       1.1       cgd {
    125       1.8     lukem 
    126       1.8     lukem 	return (cv_paste(el, 0));
    127       1.1       cgd }
    128       1.1       cgd 
    129       1.1       cgd 
    130       1.7    simonb /* vi_paste_prev():
    131       1.1       cgd  *	Vi paste previous deletion to the left of the cursor
    132       1.1       cgd  *	[P]
    133       1.1       cgd  */
    134       1.1       cgd protected el_action_t
    135       1.1       cgd /*ARGSUSED*/
    136      1.18  christos vi_paste_prev(EditLine *el, int c __attribute__((__unused__)))
    137       1.1       cgd {
    138       1.8     lukem 
    139       1.8     lukem 	return (cv_paste(el, 1));
    140       1.1       cgd }
    141       1.1       cgd 
    142       1.1       cgd 
    143      1.10  christos /* vi_prev_big_word():
    144       1.1       cgd  *	Vi move to the previous space delimited word
    145       1.1       cgd  *	[B]
    146       1.1       cgd  */
    147       1.1       cgd protected el_action_t
    148       1.1       cgd /*ARGSUSED*/
    149      1.10  christos vi_prev_big_word(EditLine *el, int c)
    150       1.8     lukem {
    151       1.8     lukem 
    152       1.8     lukem 	if (el->el_line.cursor == el->el_line.buffer)
    153       1.8     lukem 		return (CC_ERROR);
    154       1.1       cgd 
    155      1.10  christos 	el->el_line.cursor = cv_prev_word(el->el_line.cursor,
    156       1.8     lukem 	    el->el_line.buffer,
    157       1.8     lukem 	    el->el_state.argument,
    158      1.10  christos 	    cv__isWord);
    159       1.8     lukem 
    160      1.12  christos 	if (el->el_chared.c_vcmd.action != NOP) {
    161       1.8     lukem 		cv_delfini(el);
    162       1.8     lukem 		return (CC_REFRESH);
    163       1.8     lukem 	}
    164       1.8     lukem 	return (CC_CURSOR);
    165       1.1       cgd }
    166       1.1       cgd 
    167       1.1       cgd 
    168       1.7    simonb /* vi_prev_word():
    169       1.1       cgd  *	Vi move to the previous word
    170      1.10  christos  *	[b]
    171       1.1       cgd  */
    172       1.1       cgd protected el_action_t
    173       1.1       cgd /*ARGSUSED*/
    174      1.18  christos vi_prev_word(EditLine *el, int c __attribute__((__unused__)))
    175       1.8     lukem {
    176       1.1       cgd 
    177       1.8     lukem 	if (el->el_line.cursor == el->el_line.buffer)
    178       1.8     lukem 		return (CC_ERROR);
    179       1.8     lukem 
    180      1.10  christos 	el->el_line.cursor = cv_prev_word(el->el_line.cursor,
    181       1.8     lukem 	    el->el_line.buffer,
    182       1.8     lukem 	    el->el_state.argument,
    183      1.10  christos 	    cv__isword);
    184       1.8     lukem 
    185      1.12  christos 	if (el->el_chared.c_vcmd.action != NOP) {
    186       1.8     lukem 		cv_delfini(el);
    187       1.8     lukem 		return (CC_REFRESH);
    188       1.8     lukem 	}
    189       1.8     lukem 	return (CC_CURSOR);
    190       1.1       cgd }
    191       1.1       cgd 
    192       1.1       cgd 
    193      1.10  christos /* vi_next_big_word():
    194       1.1       cgd  *	Vi move to the next space delimited word
    195       1.1       cgd  *	[W]
    196       1.1       cgd  */
    197       1.1       cgd protected el_action_t
    198       1.1       cgd /*ARGSUSED*/
    199      1.10  christos vi_next_big_word(EditLine *el, int c)
    200       1.8     lukem {
    201       1.1       cgd 
    202      1.12  christos 	if (el->el_line.cursor >= el->el_line.lastchar - 1)
    203       1.8     lukem 		return (CC_ERROR);
    204       1.1       cgd 
    205       1.8     lukem 	el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
    206      1.12  christos 	    el->el_line.lastchar, el->el_state.argument, cv__isWord);
    207       1.8     lukem 
    208       1.8     lukem 	if (el->el_map.type == MAP_VI)
    209      1.12  christos 		if (el->el_chared.c_vcmd.action != NOP) {
    210       1.8     lukem 			cv_delfini(el);
    211       1.8     lukem 			return (CC_REFRESH);
    212       1.8     lukem 		}
    213       1.8     lukem 	return (CC_CURSOR);
    214       1.1       cgd }
    215       1.1       cgd 
    216       1.8     lukem 
    217       1.7    simonb /* vi_next_word():
    218       1.1       cgd  *	Vi move to the next word
    219       1.1       cgd  *	[w]
    220       1.1       cgd  */
    221       1.1       cgd protected el_action_t
    222       1.1       cgd /*ARGSUSED*/
    223      1.18  christos vi_next_word(EditLine *el, int c __attribute__((__unused__)))
    224       1.8     lukem {
    225       1.1       cgd 
    226      1.12  christos 	if (el->el_line.cursor >= el->el_line.lastchar - 1)
    227       1.8     lukem 		return (CC_ERROR);
    228       1.1       cgd 
    229       1.8     lukem 	el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
    230      1.12  christos 	    el->el_line.lastchar, el->el_state.argument, cv__isword);
    231       1.8     lukem 
    232       1.8     lukem 	if (el->el_map.type == MAP_VI)
    233      1.12  christos 		if (el->el_chared.c_vcmd.action != NOP) {
    234       1.8     lukem 			cv_delfini(el);
    235       1.8     lukem 			return (CC_REFRESH);
    236       1.8     lukem 		}
    237       1.8     lukem 	return (CC_CURSOR);
    238       1.1       cgd }
    239       1.1       cgd 
    240       1.1       cgd 
    241       1.7    simonb /* vi_change_case():
    242       1.1       cgd  *	Vi change case of character under the cursor and advance one character
    243       1.1       cgd  *	[~]
    244       1.1       cgd  */
    245       1.1       cgd protected el_action_t
    246       1.8     lukem vi_change_case(EditLine *el, int c)
    247       1.8     lukem {
    248      1.10  christos 	int i;
    249      1.10  christos 
    250      1.10  christos 	if (el->el_line.cursor >= el->el_line.lastchar)
    251      1.10  christos 		return (CC_ERROR);
    252      1.12  christos 	cv_undo(el);
    253      1.10  christos 	for (i = 0; i < el->el_state.argument; i++) {
    254       1.8     lukem 
    255      1.12  christos 		c = *(unsigned char *)el->el_line.cursor;
    256       1.8     lukem 		if (isupper(c))
    257      1.12  christos 			*el->el_line.cursor = tolower(c);
    258       1.8     lukem 		else if (islower(c))
    259      1.12  christos 			*el->el_line.cursor = toupper(c);
    260      1.12  christos 
    261      1.12  christos 		if (++el->el_line.cursor >= el->el_line.lastchar) {
    262      1.12  christos 			el->el_line.cursor--;
    263      1.12  christos 			re_fastaddc(el);
    264      1.12  christos 			break;
    265      1.12  christos 		}
    266       1.8     lukem 		re_fastaddc(el);
    267       1.8     lukem 	}
    268      1.12  christos 	return CC_NORM;
    269       1.1       cgd }
    270       1.1       cgd 
    271       1.1       cgd 
    272       1.7    simonb /* vi_change_meta():
    273       1.1       cgd  *	Vi change prefix command
    274       1.1       cgd  *	[c]
    275       1.1       cgd  */
    276       1.1       cgd protected el_action_t
    277       1.1       cgd /*ARGSUSED*/
    278      1.18  christos vi_change_meta(EditLine *el, int c __attribute__((__unused__)))
    279       1.8     lukem {
    280       1.8     lukem 
    281       1.8     lukem 	/*
    282       1.8     lukem          * Delete with insert == change: first we delete and then we leave in
    283       1.8     lukem          * insert mode.
    284       1.8     lukem          */
    285       1.8     lukem 	return (cv_action(el, DELETE | INSERT));
    286       1.1       cgd }
    287       1.1       cgd 
    288       1.1       cgd 
    289       1.7    simonb /* vi_insert_at_bol():
    290       1.1       cgd  *	Vi enter insert mode at the beginning of line
    291       1.1       cgd  *	[I]
    292       1.1       cgd  */
    293       1.1       cgd protected el_action_t
    294       1.1       cgd /*ARGSUSED*/
    295      1.18  christos vi_insert_at_bol(EditLine *el, int c __attribute__((__unused__)))
    296       1.1       cgd {
    297       1.1       cgd 
    298       1.8     lukem 	el->el_line.cursor = el->el_line.buffer;
    299      1.12  christos 	cv_undo(el);
    300       1.8     lukem 	el->el_map.current = el->el_map.key;
    301       1.8     lukem 	return (CC_CURSOR);
    302       1.1       cgd }
    303       1.1       cgd 
    304       1.1       cgd 
    305       1.7    simonb /* vi_replace_char():
    306       1.1       cgd  *	Vi replace character under the cursor with the next character typed
    307       1.1       cgd  *	[r]
    308       1.1       cgd  */
    309       1.1       cgd protected el_action_t
    310       1.1       cgd /*ARGSUSED*/
    311      1.18  christos vi_replace_char(EditLine *el, int c __attribute__((__unused__)))
    312       1.8     lukem {
    313       1.8     lukem 
    314      1.12  christos 	if (el->el_line.cursor >= el->el_line.lastchar)
    315      1.10  christos 		return CC_ERROR;
    316      1.10  christos 
    317       1.8     lukem 	el->el_map.current = el->el_map.key;
    318       1.8     lukem 	el->el_state.inputmode = MODE_REPLACE_1;
    319      1.12  christos 	cv_undo(el);
    320      1.10  christos 	return (CC_ARGHACK);
    321       1.1       cgd }
    322       1.1       cgd 
    323       1.1       cgd 
    324       1.7    simonb /* vi_replace_mode():
    325       1.1       cgd  *	Vi enter replace mode
    326       1.1       cgd  *	[R]
    327       1.1       cgd  */
    328       1.1       cgd protected el_action_t
    329       1.1       cgd /*ARGSUSED*/
    330      1.18  christos vi_replace_mode(EditLine *el, int c __attribute__((__unused__)))
    331       1.8     lukem {
    332       1.8     lukem 
    333       1.8     lukem 	el->el_map.current = el->el_map.key;
    334       1.8     lukem 	el->el_state.inputmode = MODE_REPLACE;
    335      1.12  christos 	cv_undo(el);
    336       1.8     lukem 	return (CC_NORM);
    337       1.1       cgd }
    338       1.1       cgd 
    339       1.1       cgd 
    340       1.7    simonb /* vi_substitute_char():
    341       1.1       cgd  *	Vi replace character under the cursor and enter insert mode
    342      1.10  christos  *	[s]
    343       1.1       cgd  */
    344       1.1       cgd protected el_action_t
    345       1.1       cgd /*ARGSUSED*/
    346      1.18  christos vi_substitute_char(EditLine *el, int c __attribute__((__unused__)))
    347       1.8     lukem {
    348       1.8     lukem 
    349       1.8     lukem 	c_delafter(el, el->el_state.argument);
    350       1.8     lukem 	el->el_map.current = el->el_map.key;
    351       1.8     lukem 	return (CC_REFRESH);
    352       1.1       cgd }
    353       1.1       cgd 
    354       1.1       cgd 
    355       1.7    simonb /* vi_substitute_line():
    356       1.1       cgd  *	Vi substitute entire line
    357       1.1       cgd  *	[S]
    358       1.1       cgd  */
    359       1.1       cgd protected el_action_t
    360       1.1       cgd /*ARGSUSED*/
    361      1.18  christos vi_substitute_line(EditLine *el, int c __attribute__((__unused__)))
    362       1.8     lukem {
    363       1.8     lukem 
    364      1.12  christos 	cv_undo(el);
    365      1.12  christos 	cv_yank(el, el->el_line.buffer,
    366  1.28.2.1       jym 	    (int)(el->el_line.lastchar - el->el_line.buffer));
    367       1.8     lukem 	(void) em_kill_line(el, 0);
    368       1.8     lukem 	el->el_map.current = el->el_map.key;
    369       1.8     lukem 	return (CC_REFRESH);
    370       1.1       cgd }
    371       1.1       cgd 
    372       1.1       cgd 
    373       1.7    simonb /* vi_change_to_eol():
    374       1.1       cgd  *	Vi change to end of line
    375       1.1       cgd  *	[C]
    376       1.1       cgd  */
    377       1.1       cgd protected el_action_t
    378       1.1       cgd /*ARGSUSED*/
    379      1.18  christos vi_change_to_eol(EditLine *el, int c __attribute__((__unused__)))
    380       1.8     lukem {
    381       1.8     lukem 
    382      1.12  christos 	cv_undo(el);
    383      1.12  christos 	cv_yank(el, el->el_line.cursor,
    384  1.28.2.1       jym 	    (int)(el->el_line.lastchar - el->el_line.cursor));
    385       1.8     lukem 	(void) ed_kill_line(el, 0);
    386       1.8     lukem 	el->el_map.current = el->el_map.key;
    387       1.8     lukem 	return (CC_REFRESH);
    388       1.1       cgd }
    389       1.1       cgd 
    390       1.1       cgd 
    391       1.1       cgd /* vi_insert():
    392       1.1       cgd  *	Vi enter insert mode
    393       1.1       cgd  *	[i]
    394       1.1       cgd  */
    395       1.1       cgd protected el_action_t
    396       1.1       cgd /*ARGSUSED*/
    397      1.18  christos vi_insert(EditLine *el, int c __attribute__((__unused__)))
    398       1.1       cgd {
    399       1.1       cgd 
    400       1.8     lukem 	el->el_map.current = el->el_map.key;
    401      1.12  christos 	cv_undo(el);
    402       1.8     lukem 	return (CC_NORM);
    403       1.1       cgd }
    404       1.1       cgd 
    405       1.1       cgd 
    406       1.1       cgd /* vi_add():
    407       1.7    simonb  *	Vi enter insert mode after the cursor
    408       1.1       cgd  *	[a]
    409       1.1       cgd  */
    410       1.1       cgd protected el_action_t
    411       1.1       cgd /*ARGSUSED*/
    412      1.18  christos vi_add(EditLine *el, int c __attribute__((__unused__)))
    413       1.8     lukem {
    414       1.8     lukem 	int ret;
    415       1.8     lukem 
    416       1.8     lukem 	el->el_map.current = el->el_map.key;
    417       1.8     lukem 	if (el->el_line.cursor < el->el_line.lastchar) {
    418       1.8     lukem 		el->el_line.cursor++;
    419       1.8     lukem 		if (el->el_line.cursor > el->el_line.lastchar)
    420       1.8     lukem 			el->el_line.cursor = el->el_line.lastchar;
    421       1.8     lukem 		ret = CC_CURSOR;
    422       1.8     lukem 	} else
    423       1.8     lukem 		ret = CC_NORM;
    424       1.8     lukem 
    425      1.12  christos 	cv_undo(el);
    426       1.1       cgd 
    427       1.8     lukem 	return (ret);
    428       1.1       cgd }
    429       1.1       cgd 
    430       1.1       cgd 
    431       1.1       cgd /* vi_add_at_eol():
    432       1.1       cgd  *	Vi enter insert mode at end of line
    433       1.1       cgd  *	[A]
    434       1.1       cgd  */
    435       1.1       cgd protected el_action_t
    436       1.1       cgd /*ARGSUSED*/
    437      1.18  christos vi_add_at_eol(EditLine *el, int c __attribute__((__unused__)))
    438       1.8     lukem {
    439       1.8     lukem 
    440       1.8     lukem 	el->el_map.current = el->el_map.key;
    441       1.8     lukem 	el->el_line.cursor = el->el_line.lastchar;
    442      1.12  christos 	cv_undo(el);
    443       1.8     lukem 	return (CC_CURSOR);
    444       1.1       cgd }
    445       1.1       cgd 
    446       1.1       cgd 
    447       1.1       cgd /* vi_delete_meta():
    448       1.7    simonb  *	Vi delete prefix command
    449       1.1       cgd  *	[d]
    450       1.1       cgd  */
    451       1.1       cgd protected el_action_t
    452       1.1       cgd /*ARGSUSED*/
    453      1.18  christos vi_delete_meta(EditLine *el, int c __attribute__((__unused__)))
    454       1.1       cgd {
    455       1.8     lukem 
    456       1.8     lukem 	return (cv_action(el, DELETE));
    457       1.1       cgd }
    458       1.1       cgd 
    459       1.1       cgd 
    460      1.10  christos /* vi_end_big_word():
    461       1.7    simonb  *	Vi move to the end of the current space delimited word
    462       1.7    simonb  *	[E]
    463       1.1       cgd  */
    464       1.1       cgd protected el_action_t
    465       1.1       cgd /*ARGSUSED*/
    466      1.10  christos vi_end_big_word(EditLine *el, int c)
    467       1.8     lukem {
    468       1.8     lukem 
    469       1.8     lukem 	if (el->el_line.cursor == el->el_line.lastchar)
    470       1.8     lukem 		return (CC_ERROR);
    471       1.1       cgd 
    472       1.8     lukem 	el->el_line.cursor = cv__endword(el->el_line.cursor,
    473      1.10  christos 	    el->el_line.lastchar, el->el_state.argument, cv__isWord);
    474       1.8     lukem 
    475      1.12  christos 	if (el->el_chared.c_vcmd.action != NOP) {
    476       1.8     lukem 		el->el_line.cursor++;
    477       1.8     lukem 		cv_delfini(el);
    478       1.8     lukem 		return (CC_REFRESH);
    479       1.8     lukem 	}
    480       1.8     lukem 	return (CC_CURSOR);
    481       1.1       cgd }
    482       1.1       cgd 
    483       1.1       cgd 
    484      1.10  christos /* vi_end_word():
    485       1.1       cgd  *	Vi move to the end of the current word
    486       1.1       cgd  *	[e]
    487       1.1       cgd  */
    488       1.1       cgd protected el_action_t
    489       1.1       cgd /*ARGSUSED*/
    490      1.18  christos vi_end_word(EditLine *el, int c __attribute__((__unused__)))
    491       1.8     lukem {
    492       1.8     lukem 
    493       1.8     lukem 	if (el->el_line.cursor == el->el_line.lastchar)
    494       1.8     lukem 		return (CC_ERROR);
    495       1.8     lukem 
    496       1.8     lukem 	el->el_line.cursor = cv__endword(el->el_line.cursor,
    497      1.10  christos 	    el->el_line.lastchar, el->el_state.argument, cv__isword);
    498       1.1       cgd 
    499      1.12  christos 	if (el->el_chared.c_vcmd.action != NOP) {
    500       1.8     lukem 		el->el_line.cursor++;
    501       1.8     lukem 		cv_delfini(el);
    502       1.8     lukem 		return (CC_REFRESH);
    503       1.8     lukem 	}
    504       1.8     lukem 	return (CC_CURSOR);
    505       1.1       cgd }
    506       1.1       cgd 
    507       1.1       cgd 
    508       1.1       cgd /* vi_undo():
    509       1.1       cgd  *	Vi undo last change
    510       1.1       cgd  *	[u]
    511       1.1       cgd  */
    512       1.1       cgd protected el_action_t
    513       1.1       cgd /*ARGSUSED*/
    514      1.18  christos vi_undo(EditLine *el, int c __attribute__((__unused__)))
    515       1.8     lukem {
    516      1.10  christos 	c_undo_t un = el->el_chared.c_undo;
    517       1.1       cgd 
    518      1.10  christos 	if (un.len == -1)
    519      1.10  christos 		return CC_ERROR;
    520       1.1       cgd 
    521      1.10  christos 	/* switch line buffer and undo buffer */
    522      1.10  christos 	el->el_chared.c_undo.buf = el->el_line.buffer;
    523      1.10  christos 	el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer;
    524  1.28.2.1       jym 	el->el_chared.c_undo.cursor =
    525  1.28.2.1       jym 	    (int)(el->el_line.cursor - el->el_line.buffer);
    526      1.10  christos 	el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer);
    527      1.10  christos 	el->el_line.buffer = un.buf;
    528      1.10  christos 	el->el_line.cursor = un.buf + un.cursor;
    529      1.10  christos 	el->el_line.lastchar = un.buf + un.len;
    530       1.1       cgd 
    531       1.8     lukem 	return (CC_REFRESH);
    532       1.1       cgd }
    533       1.1       cgd 
    534       1.1       cgd 
    535       1.1       cgd /* vi_command_mode():
    536       1.1       cgd  *	Vi enter command mode (use alternative key bindings)
    537       1.1       cgd  *	[<ESC>]
    538       1.1       cgd  */
    539       1.1       cgd protected el_action_t
    540       1.1       cgd /*ARGSUSED*/
    541      1.18  christos vi_command_mode(EditLine *el, int c __attribute__((__unused__)))
    542       1.8     lukem {
    543       1.8     lukem 
    544       1.8     lukem 	/* [Esc] cancels pending action */
    545       1.8     lukem 	el->el_chared.c_vcmd.action = NOP;
    546       1.8     lukem 	el->el_chared.c_vcmd.pos = 0;
    547       1.8     lukem 
    548       1.8     lukem 	el->el_state.doingarg = 0;
    549       1.1       cgd 
    550       1.8     lukem 	el->el_state.inputmode = MODE_INSERT;
    551       1.8     lukem 	el->el_map.current = el->el_map.alt;
    552       1.1       cgd #ifdef VI_MOVE
    553       1.8     lukem 	if (el->el_line.cursor > el->el_line.buffer)
    554       1.8     lukem 		el->el_line.cursor--;
    555       1.1       cgd #endif
    556       1.8     lukem 	return (CC_CURSOR);
    557       1.1       cgd }
    558       1.1       cgd 
    559       1.8     lukem 
    560       1.1       cgd /* vi_zero():
    561       1.7    simonb  *	Vi move to the beginning of line
    562       1.1       cgd  *	[0]
    563       1.1       cgd  */
    564       1.1       cgd protected el_action_t
    565       1.8     lukem vi_zero(EditLine *el, int c)
    566       1.8     lukem {
    567       1.8     lukem 
    568      1.12  christos 	if (el->el_state.doingarg)
    569      1.12  christos 		return ed_argument_digit(el, c);
    570      1.12  christos 
    571      1.12  christos 	el->el_line.cursor = el->el_line.buffer;
    572      1.12  christos 	if (el->el_chared.c_vcmd.action != NOP) {
    573      1.12  christos 		cv_delfini(el);
    574      1.12  christos 		return (CC_REFRESH);
    575       1.8     lukem 	}
    576      1.12  christos 	return (CC_CURSOR);
    577       1.1       cgd }
    578       1.1       cgd 
    579       1.1       cgd 
    580       1.1       cgd /* vi_delete_prev_char():
    581       1.7    simonb  * 	Vi move to previous character (backspace)
    582      1.10  christos  *	[^H] in insert mode only
    583       1.7    simonb  */
    584       1.1       cgd protected el_action_t
    585       1.1       cgd /*ARGSUSED*/
    586      1.18  christos vi_delete_prev_char(EditLine *el, int c __attribute__((__unused__)))
    587       1.8     lukem {
    588       1.1       cgd 
    589      1.20   mycroft 	if (el->el_line.cursor <= el->el_line.buffer)
    590       1.8     lukem 		return (CC_ERROR);
    591       1.8     lukem 
    592      1.20   mycroft 	c_delbefore1(el);
    593      1.20   mycroft 	el->el_line.cursor--;
    594       1.8     lukem 	return (CC_REFRESH);
    595       1.8     lukem }
    596       1.1       cgd 
    597       1.1       cgd 
    598       1.1       cgd /* vi_list_or_eof():
    599       1.1       cgd  *	Vi list choices for completion or indicate end of file if empty line
    600       1.1       cgd  *	[^D]
    601       1.1       cgd  */
    602       1.1       cgd protected el_action_t
    603       1.1       cgd /*ARGSUSED*/
    604      1.25  christos vi_list_or_eof(EditLine *el, int c)
    605       1.1       cgd {
    606       1.8     lukem 
    607      1.17      matt 	if (el->el_line.cursor == el->el_line.lastchar) {
    608      1.17      matt 		if (el->el_line.cursor == el->el_line.buffer) {
    609      1.25  christos 			term_writec(el, c);	/* then do a EOF */
    610      1.17      matt 			return (CC_EOF);
    611      1.17      matt 		} else {
    612      1.17      matt 			/*
    613      1.17      matt 			 * Here we could list completions, but it is an
    614      1.17      matt 			 * error right now
    615      1.17      matt 			 */
    616      1.17      matt 			term_beep(el);
    617      1.17      matt 			return (CC_ERROR);
    618      1.17      matt 		}
    619      1.17      matt 	} else {
    620       1.1       cgd #ifdef notyet
    621       1.8     lukem 		re_goto_bottom(el);
    622       1.8     lukem 		*el->el_line.lastchar = '\0';	/* just in case */
    623       1.8     lukem 		return (CC_LIST_CHOICES);
    624      1.17      matt #else
    625      1.17      matt 		/*
    626      1.17      matt 		 * Just complain for now.
    627      1.17      matt 		 */
    628      1.17      matt 		term_beep(el);
    629      1.17      matt 		return (CC_ERROR);
    630      1.17      matt #endif
    631       1.8     lukem 	}
    632       1.1       cgd }
    633       1.1       cgd 
    634       1.1       cgd 
    635       1.1       cgd /* vi_kill_line_prev():
    636       1.7    simonb  *	Vi cut from beginning of line to cursor
    637       1.1       cgd  *	[^U]
    638       1.1       cgd  */
    639       1.1       cgd protected el_action_t
    640       1.1       cgd /*ARGSUSED*/
    641      1.18  christos vi_kill_line_prev(EditLine *el, int c __attribute__((__unused__)))
    642       1.8     lukem {
    643       1.8     lukem 	char *kp, *cp;
    644       1.8     lukem 
    645       1.8     lukem 	cp = el->el_line.buffer;
    646       1.8     lukem 	kp = el->el_chared.c_kill.buf;
    647       1.8     lukem 	while (cp < el->el_line.cursor)
    648       1.8     lukem 		*kp++ = *cp++;	/* copy it */
    649       1.8     lukem 	el->el_chared.c_kill.last = kp;
    650  1.28.2.1       jym 	c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer));
    651       1.8     lukem 	el->el_line.cursor = el->el_line.buffer;	/* zap! */
    652       1.8     lukem 	return (CC_REFRESH);
    653       1.1       cgd }
    654       1.1       cgd 
    655       1.1       cgd 
    656       1.1       cgd /* vi_search_prev():
    657       1.1       cgd  *	Vi search history previous
    658       1.1       cgd  *	[?]
    659       1.1       cgd  */
    660       1.1       cgd protected el_action_t
    661       1.1       cgd /*ARGSUSED*/
    662      1.18  christos vi_search_prev(EditLine *el, int c __attribute__((__unused__)))
    663       1.1       cgd {
    664       1.8     lukem 
    665       1.8     lukem 	return (cv_search(el, ED_SEARCH_PREV_HISTORY));
    666       1.1       cgd }
    667       1.1       cgd 
    668       1.1       cgd 
    669       1.1       cgd /* vi_search_next():
    670       1.1       cgd  *	Vi search history next
    671       1.1       cgd  *	[/]
    672       1.1       cgd  */
    673       1.1       cgd protected el_action_t
    674       1.1       cgd /*ARGSUSED*/
    675      1.18  christos vi_search_next(EditLine *el, int c __attribute__((__unused__)))
    676       1.1       cgd {
    677       1.8     lukem 
    678       1.8     lukem 	return (cv_search(el, ED_SEARCH_NEXT_HISTORY));
    679       1.1       cgd }
    680       1.1       cgd 
    681       1.1       cgd 
    682       1.1       cgd /* vi_repeat_search_next():
    683       1.1       cgd  *	Vi repeat current search in the same search direction
    684       1.1       cgd  *	[n]
    685       1.1       cgd  */
    686       1.1       cgd protected el_action_t
    687       1.1       cgd /*ARGSUSED*/
    688      1.18  christos vi_repeat_search_next(EditLine *el, int c __attribute__((__unused__)))
    689       1.8     lukem {
    690       1.8     lukem 
    691       1.8     lukem 	if (el->el_search.patlen == 0)
    692       1.8     lukem 		return (CC_ERROR);
    693       1.8     lukem 	else
    694       1.8     lukem 		return (cv_repeat_srch(el, el->el_search.patdir));
    695       1.1       cgd }
    696       1.1       cgd 
    697       1.1       cgd 
    698       1.1       cgd /* vi_repeat_search_prev():
    699       1.1       cgd  *	Vi repeat current search in the opposite search direction
    700       1.1       cgd  *	[N]
    701       1.1       cgd  */
    702       1.1       cgd /*ARGSUSED*/
    703       1.1       cgd protected el_action_t
    704      1.18  christos vi_repeat_search_prev(EditLine *el, int c __attribute__((__unused__)))
    705       1.8     lukem {
    706       1.8     lukem 
    707       1.8     lukem 	if (el->el_search.patlen == 0)
    708       1.8     lukem 		return (CC_ERROR);
    709       1.8     lukem 	else
    710       1.8     lukem 		return (cv_repeat_srch(el,
    711       1.8     lukem 		    el->el_search.patdir == ED_SEARCH_PREV_HISTORY ?
    712       1.8     lukem 		    ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY));
    713       1.1       cgd }
    714       1.1       cgd 
    715       1.1       cgd 
    716       1.1       cgd /* vi_next_char():
    717       1.1       cgd  *	Vi move to the character specified next
    718       1.1       cgd  *	[f]
    719       1.1       cgd  */
    720       1.1       cgd protected el_action_t
    721       1.1       cgd /*ARGSUSED*/
    722      1.18  christos vi_next_char(EditLine *el, int c __attribute__((__unused__)))
    723       1.1       cgd {
    724      1.12  christos 	return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0);
    725       1.1       cgd }
    726       1.1       cgd 
    727       1.1       cgd 
    728       1.1       cgd /* vi_prev_char():
    729       1.1       cgd  *	Vi move to the character specified previous
    730       1.1       cgd  *	[F]
    731       1.1       cgd  */
    732       1.1       cgd protected el_action_t
    733       1.1       cgd /*ARGSUSED*/
    734      1.18  christos vi_prev_char(EditLine *el, int c __attribute__((__unused__)))
    735       1.1       cgd {
    736      1.12  christos 	return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0);
    737       1.1       cgd }
    738       1.1       cgd 
    739       1.1       cgd 
    740       1.1       cgd /* vi_to_next_char():
    741       1.1       cgd  *	Vi move up to the character specified next
    742       1.1       cgd  *	[t]
    743       1.1       cgd  */
    744       1.1       cgd protected el_action_t
    745       1.1       cgd /*ARGSUSED*/
    746      1.18  christos vi_to_next_char(EditLine *el, int c __attribute__((__unused__)))
    747       1.1       cgd {
    748      1.12  christos 	return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1);
    749       1.1       cgd }
    750       1.1       cgd 
    751       1.1       cgd 
    752       1.1       cgd /* vi_to_prev_char():
    753       1.1       cgd  *	Vi move up to the character specified previous
    754       1.1       cgd  *	[T]
    755       1.1       cgd  */
    756       1.1       cgd protected el_action_t
    757       1.1       cgd /*ARGSUSED*/
    758      1.18  christos vi_to_prev_char(EditLine *el, int c __attribute__((__unused__)))
    759       1.8     lukem {
    760      1.12  christos 	return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1);
    761       1.1       cgd }
    762       1.1       cgd 
    763       1.1       cgd 
    764       1.1       cgd /* vi_repeat_next_char():
    765       1.1       cgd  *	Vi repeat current character search in the same search direction
    766       1.1       cgd  *	[;]
    767       1.1       cgd  */
    768       1.1       cgd protected el_action_t
    769       1.1       cgd /*ARGSUSED*/
    770      1.18  christos vi_repeat_next_char(EditLine *el, int c __attribute__((__unused__)))
    771       1.8     lukem {
    772       1.8     lukem 
    773      1.12  christos 	return cv_csearch(el, el->el_search.chadir, el->el_search.chacha,
    774      1.12  christos 		el->el_state.argument, el->el_search.chatflg);
    775       1.1       cgd }
    776       1.1       cgd 
    777       1.1       cgd 
    778       1.1       cgd /* vi_repeat_prev_char():
    779       1.1       cgd  *	Vi repeat current character search in the opposite search direction
    780       1.1       cgd  *	[,]
    781       1.1       cgd  */
    782       1.1       cgd protected el_action_t
    783       1.1       cgd /*ARGSUSED*/
    784      1.18  christos vi_repeat_prev_char(EditLine *el, int c __attribute__((__unused__)))
    785       1.8     lukem {
    786      1.12  christos 	el_action_t r;
    787      1.12  christos 	int dir = el->el_search.chadir;
    788       1.8     lukem 
    789      1.12  christos 	r = cv_csearch(el, -dir, el->el_search.chacha,
    790      1.12  christos 		el->el_state.argument, el->el_search.chatflg);
    791      1.12  christos 	el->el_search.chadir = dir;
    792      1.12  christos 	return r;
    793      1.11  christos }
    794      1.11  christos 
    795      1.11  christos 
    796      1.11  christos /* vi_match():
    797      1.11  christos  *	Vi go to matching () {} or []
    798      1.11  christos  *	[%]
    799      1.11  christos  */
    800      1.11  christos protected el_action_t
    801      1.11  christos /*ARGSUSED*/
    802      1.11  christos vi_match(EditLine *el, int c)
    803      1.11  christos {
    804      1.11  christos 	const char match_chars[] = "()[]{}";
    805      1.11  christos 	char *cp;
    806  1.28.2.1       jym 	size_t delta, i, count;
    807      1.11  christos 	char o_ch, c_ch;
    808      1.11  christos 
    809      1.11  christos 	*el->el_line.lastchar = '\0';		/* just in case */
    810      1.11  christos 
    811      1.11  christos 	i = strcspn(el->el_line.cursor, match_chars);
    812      1.11  christos 	o_ch = el->el_line.cursor[i];
    813      1.11  christos 	if (o_ch == 0)
    814      1.11  christos 		return CC_ERROR;
    815      1.11  christos 	delta = strchr(match_chars, o_ch) - match_chars;
    816      1.11  christos 	c_ch = match_chars[delta ^ 1];
    817      1.11  christos 	count = 1;
    818      1.11  christos 	delta = 1 - (delta & 1) * 2;
    819      1.11  christos 
    820      1.11  christos 	for (cp = &el->el_line.cursor[i]; count; ) {
    821      1.11  christos 		cp += delta;
    822      1.11  christos 		if (cp < el->el_line.buffer || cp >= el->el_line.lastchar)
    823      1.11  christos 			return CC_ERROR;
    824      1.11  christos 		if (*cp == o_ch)
    825      1.11  christos 			count++;
    826      1.11  christos 		else if (*cp == c_ch)
    827      1.11  christos 			count--;
    828      1.11  christos 	}
    829      1.11  christos 
    830      1.11  christos 	el->el_line.cursor = cp;
    831      1.11  christos 
    832      1.12  christos 	if (el->el_chared.c_vcmd.action != NOP) {
    833      1.12  christos 		/* NB posix says char under cursor should NOT be deleted
    834      1.12  christos 		   for -ve delta - this is different to netbsd vi. */
    835      1.11  christos 		if (delta > 0)
    836      1.11  christos 			el->el_line.cursor++;
    837      1.11  christos 		cv_delfini(el);
    838      1.11  christos 		return (CC_REFRESH);
    839      1.11  christos 	}
    840      1.11  christos 	return (CC_CURSOR);
    841      1.12  christos }
    842      1.12  christos 
    843      1.12  christos /* vi_undo_line():
    844      1.12  christos  *	Vi undo all changes to line
    845      1.12  christos  *	[U]
    846      1.12  christos  */
    847      1.12  christos protected el_action_t
    848      1.12  christos /*ARGSUSED*/
    849      1.12  christos vi_undo_line(EditLine *el, int c)
    850      1.12  christos {
    851      1.12  christos 
    852      1.12  christos 	cv_undo(el);
    853      1.12  christos 	return hist_get(el);
    854      1.12  christos }
    855      1.12  christos 
    856      1.12  christos /* vi_to_column():
    857      1.12  christos  *	Vi go to specified column
    858      1.12  christos  *	[|]
    859      1.12  christos  * NB netbsd vi goes to screen column 'n', posix says nth character
    860      1.12  christos  */
    861      1.12  christos protected el_action_t
    862      1.12  christos /*ARGSUSED*/
    863      1.12  christos vi_to_column(EditLine *el, int c)
    864      1.12  christos {
    865      1.12  christos 
    866      1.12  christos 	el->el_line.cursor = el->el_line.buffer;
    867      1.12  christos 	el->el_state.argument--;
    868      1.12  christos 	return ed_next_char(el, 0);
    869      1.12  christos }
    870      1.12  christos 
    871      1.12  christos /* vi_yank_end():
    872      1.12  christos  *	Vi yank to end of line
    873      1.12  christos  *	[Y]
    874      1.12  christos  */
    875      1.12  christos protected el_action_t
    876      1.12  christos /*ARGSUSED*/
    877      1.12  christos vi_yank_end(EditLine *el, int c)
    878      1.12  christos {
    879      1.12  christos 
    880      1.12  christos 	cv_yank(el, el->el_line.cursor,
    881  1.28.2.1       jym 	    (int)(el->el_line.lastchar - el->el_line.cursor));
    882      1.12  christos 	return CC_REFRESH;
    883      1.12  christos }
    884      1.12  christos 
    885      1.12  christos /* vi_yank():
    886      1.12  christos  *	Vi yank
    887      1.12  christos  *	[y]
    888      1.12  christos  */
    889      1.12  christos protected el_action_t
    890      1.12  christos /*ARGSUSED*/
    891      1.12  christos vi_yank(EditLine *el, int c)
    892      1.12  christos {
    893      1.12  christos 
    894      1.12  christos 	return cv_action(el, YANK);
    895      1.12  christos }
    896      1.12  christos 
    897      1.12  christos /* vi_comment_out():
    898      1.12  christos  *	Vi comment out current command
    899      1.22  christos  *	[#]
    900      1.12  christos  */
    901      1.12  christos protected el_action_t
    902      1.12  christos /*ARGSUSED*/
    903      1.12  christos vi_comment_out(EditLine *el, int c)
    904      1.12  christos {
    905      1.12  christos 
    906      1.12  christos 	el->el_line.cursor = el->el_line.buffer;
    907      1.12  christos 	c_insert(el, 1);
    908      1.12  christos 	*el->el_line.cursor = '#';
    909      1.12  christos 	re_refresh(el);
    910      1.12  christos 	return ed_newline(el, 0);
    911      1.12  christos }
    912      1.12  christos 
    913      1.12  christos /* vi_alias():
    914      1.12  christos  *	Vi include shell alias
    915      1.12  christos  *	[@]
    916      1.22  christos  * NB: posix implies that we should enter insert mode, however
    917      1.12  christos  * this is against historical precedent...
    918      1.12  christos  */
    919      1.27       mrg #ifdef __weak_reference
    920      1.27       mrg extern char *get_alias_text(const char *) __weak_reference(get_alias_text);
    921      1.27       mrg #endif
    922      1.12  christos protected el_action_t
    923      1.12  christos /*ARGSUSED*/
    924      1.12  christos vi_alias(EditLine *el, int c)
    925      1.12  christos {
    926      1.26  christos #ifdef __weak_reference
    927      1.12  christos 	char alias_name[3];
    928      1.12  christos 	char *alias_text;
    929      1.12  christos 
    930      1.12  christos 	if (get_alias_text == 0) {
    931      1.12  christos 		return CC_ERROR;
    932      1.12  christos 	}
    933      1.14  christos 
    934      1.12  christos 	alias_name[0] = '_';
    935      1.12  christos 	alias_name[2] = 0;
    936      1.12  christos 	if (el_getc(el, &alias_name[1]) != 1)
    937      1.12  christos 		return CC_ERROR;
    938      1.12  christos 
    939      1.12  christos 	alias_text = get_alias_text(alias_name);
    940      1.12  christos 	if (alias_text != NULL)
    941      1.12  christos 		el_push(el, alias_text);
    942      1.12  christos 	return CC_NORM;
    943      1.14  christos #else
    944      1.14  christos 	return CC_ERROR;
    945      1.14  christos #endif
    946      1.12  christos }
    947      1.12  christos 
    948      1.12  christos /* vi_to_history_line():
    949      1.12  christos  *	Vi go to specified history file line.
    950      1.12  christos  *	[G]
    951      1.12  christos  */
    952      1.12  christos protected el_action_t
    953      1.12  christos /*ARGSUSED*/
    954      1.12  christos vi_to_history_line(EditLine *el, int c)
    955      1.12  christos {
    956      1.12  christos 	int sv_event_no = el->el_history.eventno;
    957      1.12  christos 	el_action_t rval;
    958      1.12  christos 
    959      1.12  christos 
    960      1.12  christos 	if (el->el_history.eventno == 0) {
    961      1.12  christos 		 (void) strncpy(el->el_history.buf, el->el_line.buffer,
    962      1.12  christos 		     EL_BUFSIZ);
    963      1.12  christos 		 el->el_history.last = el->el_history.buf +
    964      1.12  christos 			 (el->el_line.lastchar - el->el_line.buffer);
    965      1.12  christos 	}
    966      1.12  christos 
    967      1.12  christos 	/* Lack of a 'count' means oldest, not 1 */
    968      1.12  christos 	if (!el->el_state.doingarg) {
    969      1.12  christos 		el->el_history.eventno = 0x7fffffff;
    970      1.12  christos 		hist_get(el);
    971      1.12  christos 	} else {
    972      1.12  christos 		/* This is brain dead, all the rest of this code counts
    973      1.12  christos 		 * upwards going into the past.  Here we need count in the
    974      1.12  christos 		 * other direction (to match the output of fc -l).
    975      1.12  christos 		 * I could change the world, but this seems to suffice.
    976      1.12  christos 		 */
    977      1.12  christos 		el->el_history.eventno = 1;
    978      1.12  christos 		if (hist_get(el) == CC_ERROR)
    979      1.12  christos 			return CC_ERROR;
    980      1.12  christos 		el->el_history.eventno = 1 + el->el_history.ev.num
    981      1.12  christos 					- el->el_state.argument;
    982      1.12  christos 		if (el->el_history.eventno < 0) {
    983      1.12  christos 			el->el_history.eventno = sv_event_no;
    984      1.12  christos 			return CC_ERROR;
    985      1.12  christos 		}
    986      1.12  christos 	}
    987      1.12  christos 	rval = hist_get(el);
    988      1.12  christos 	if (rval == CC_ERROR)
    989      1.12  christos 		el->el_history.eventno = sv_event_no;
    990      1.12  christos 	return rval;
    991      1.12  christos }
    992      1.12  christos 
    993      1.12  christos /* vi_histedit():
    994      1.12  christos  *	Vi edit history line with vi
    995      1.12  christos  *	[v]
    996      1.12  christos  */
    997      1.12  christos protected el_action_t
    998      1.12  christos /*ARGSUSED*/
    999      1.12  christos vi_histedit(EditLine *el, int c)
   1000      1.12  christos {
   1001      1.12  christos 	int fd;
   1002      1.12  christos 	pid_t pid;
   1003  1.28.2.1       jym 	ssize_t st;
   1004  1.28.2.1       jym 	int status;
   1005      1.12  christos 	char tempfile[] = "/tmp/histedit.XXXXXXXXXX";
   1006      1.12  christos 	char *cp;
   1007      1.12  christos 
   1008      1.12  christos 	if (el->el_state.doingarg) {
   1009      1.12  christos 		if (vi_to_history_line(el, 0) == CC_ERROR)
   1010      1.12  christos 			return CC_ERROR;
   1011      1.12  christos 	}
   1012      1.12  christos 
   1013      1.12  christos 	fd = mkstemp(tempfile);
   1014      1.12  christos 	if (fd < 0)
   1015      1.12  christos 		return CC_ERROR;
   1016      1.12  christos 	cp = el->el_line.buffer;
   1017  1.28.2.1       jym 	write(fd, cp, (size_t)(el->el_line.lastchar - cp));
   1018      1.12  christos 	write(fd, "\n", 1);
   1019      1.12  christos 	pid = fork();
   1020      1.12  christos 	switch (pid) {
   1021      1.12  christos 	case -1:
   1022      1.12  christos 		close(fd);
   1023      1.12  christos 		unlink(tempfile);
   1024      1.12  christos 		return CC_ERROR;
   1025      1.12  christos 	case 0:
   1026      1.12  christos 		close(fd);
   1027      1.28    sketch 		execlp("vi", "vi", tempfile, (char *)NULL);
   1028      1.12  christos 		exit(0);
   1029      1.12  christos 		/*NOTREACHED*/
   1030      1.12  christos 	default:
   1031  1.28.2.1       jym 		while (waitpid(pid, &status, 0) != pid)
   1032      1.12  christos 			continue;
   1033  1.28.2.1       jym 		lseek(fd, (off_t)0, SEEK_SET);
   1034  1.28.2.1       jym 		st = read(fd, cp, (size_t)(el->el_line.limit - cp));
   1035      1.12  christos 		if (st > 0 && cp[st - 1] == '\n')
   1036      1.12  christos 			st--;
   1037      1.12  christos 		el->el_line.cursor = cp;
   1038      1.12  christos 		el->el_line.lastchar = cp + st;
   1039      1.12  christos 		break;
   1040      1.12  christos 	}
   1041      1.12  christos 
   1042      1.12  christos 	close(fd);
   1043      1.12  christos 	unlink(tempfile);
   1044      1.12  christos 	/* return CC_REFRESH; */
   1045      1.12  christos 	return ed_newline(el, 0);
   1046      1.12  christos }
   1047      1.12  christos 
   1048      1.12  christos /* vi_history_word():
   1049      1.12  christos  *	Vi append word from previous input line
   1050      1.12  christos  *	[_]
   1051      1.12  christos  * Who knows where this one came from!
   1052      1.12  christos  * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_'
   1053      1.12  christos  */
   1054      1.12  christos protected el_action_t
   1055      1.12  christos /*ARGSUSED*/
   1056      1.12  christos vi_history_word(EditLine *el, int c)
   1057      1.12  christos {
   1058      1.12  christos 	const char *wp = HIST_FIRST(el);
   1059      1.12  christos 	const char *wep, *wsp;
   1060      1.12  christos 	int len;
   1061      1.12  christos 	char *cp;
   1062      1.12  christos 	const char *lim;
   1063      1.12  christos 
   1064      1.12  christos 	if (wp == NULL)
   1065      1.12  christos 		return CC_ERROR;
   1066      1.12  christos 
   1067      1.13  christos 	wep = wsp = 0;
   1068      1.12  christos 	do {
   1069      1.12  christos 		while (isspace((unsigned char)*wp))
   1070      1.12  christos 			wp++;
   1071      1.12  christos 		if (*wp == 0)
   1072      1.12  christos 			break;
   1073      1.12  christos 		wsp = wp;
   1074      1.12  christos 		while (*wp && !isspace((unsigned char)*wp))
   1075      1.12  christos 			wp++;
   1076      1.12  christos 		wep = wp;
   1077      1.12  christos 	} while ((!el->el_state.doingarg || --el->el_state.argument > 0) && *wp != 0);
   1078      1.12  christos 
   1079      1.12  christos 	if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0))
   1080      1.12  christos 		return CC_ERROR;
   1081      1.12  christos 
   1082      1.12  christos 	cv_undo(el);
   1083  1.28.2.1       jym 	len = (int)(wep - wsp);
   1084      1.12  christos 	if (el->el_line.cursor < el->el_line.lastchar)
   1085      1.12  christos 		el->el_line.cursor++;
   1086      1.12  christos 	c_insert(el, len + 1);
   1087      1.12  christos 	cp = el->el_line.cursor;
   1088      1.12  christos 	lim = el->el_line.limit;
   1089      1.12  christos 	if (cp < lim)
   1090      1.12  christos 		*cp++ = ' ';
   1091      1.12  christos 	while (wsp < wep && cp < lim)
   1092      1.12  christos 		*cp++ = *wsp++;
   1093      1.12  christos 	el->el_line.cursor = cp;
   1094      1.12  christos 
   1095      1.12  christos 	el->el_map.current = el->el_map.key;
   1096      1.12  christos 	return CC_REFRESH;
   1097      1.12  christos }
   1098      1.12  christos 
   1099      1.12  christos /* vi_redo():
   1100      1.12  christos  *	Vi redo last non-motion command
   1101      1.12  christos  *	[.]
   1102      1.12  christos  */
   1103      1.12  christos protected el_action_t
   1104      1.12  christos /*ARGSUSED*/
   1105      1.12  christos vi_redo(EditLine *el, int c)
   1106      1.12  christos {
   1107      1.12  christos 	c_redo_t *r = &el->el_chared.c_redo;
   1108      1.12  christos 
   1109      1.12  christos 	if (!el->el_state.doingarg && r->count) {
   1110      1.12  christos 		el->el_state.doingarg = 1;
   1111      1.12  christos 		el->el_state.argument = r->count;
   1112      1.12  christos 	}
   1113      1.12  christos 
   1114      1.12  christos 	el->el_chared.c_vcmd.pos = el->el_line.cursor;
   1115      1.12  christos 	el->el_chared.c_vcmd.action = r->action;
   1116      1.12  christos 	if (r->pos != r->buf) {
   1117      1.12  christos 		if (r->pos + 1 > r->lim)
   1118      1.12  christos 			/* sanity */
   1119      1.12  christos 			r->pos = r->lim - 1;
   1120      1.12  christos 		r->pos[0] = 0;
   1121      1.12  christos 		el_push(el, r->buf);
   1122      1.12  christos 	}
   1123      1.12  christos 
   1124      1.12  christos 	el->el_state.thiscmd = r->cmd;
   1125      1.12  christos 	el->el_state.thisch = r->ch;
   1126      1.12  christos 	return  (*el->el_map.func[r->cmd])(el, r->ch);
   1127       1.1       cgd }
   1128