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