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