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