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