igb.4: Update according to the recent TX/RX MSI-X handling work
[dragonfly.git] / contrib / libedit / src / vi.c
1 /*      $NetBSD: vi.c,v 1.45 2014/06/18 18:12:28 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. Neither the name of the University nor the names of its contributors
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
35 #include "config.h"
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <limits.h>
39 #include <sys/wait.h>
40
41 #if !defined(lint) && !defined(SCCSID)
42 #if 0
43 static char sccsid[] = "@(#)vi.c        8.1 (Berkeley) 6/4/93";
44 #else
45 __RCSID("$NetBSD: vi.c,v 1.45 2014/06/18 18:12:28 christos Exp $");
46 #endif
47 #endif /* not lint && not SCCSID */
48
49 /*
50  * vi.c: Vi mode commands.
51  */
52 #include "el.h"
53
54 private el_action_t     cv_action(EditLine *, Int);
55 private el_action_t     cv_paste(EditLine *, Int);
56
57 /* cv_action():
58  *      Handle vi actions.
59  */
60 private el_action_t
61 cv_action(EditLine *el, Int c)
62 {
63
64         if (el->el_chared.c_vcmd.action != NOP) {
65                 /* 'cc', 'dd' and (possibly) friends */
66                 if (c != (Int)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,
72                     (int)(el->el_line.lastchar - el->el_line.buffer));
73                 el->el_chared.c_vcmd.action = NOP;
74                 el->el_chared.c_vcmd.pos = 0;
75                 if (!(c & YANK)) {
76                         el->el_line.lastchar = el->el_line.buffer;
77                         el->el_line.cursor = el->el_line.buffer;
78                 }
79                 if (c & INSERT)
80                         el->el_map.current = el->el_map.key;
81
82                 return CC_REFRESH;
83         }
84         el->el_chared.c_vcmd.pos = el->el_line.cursor;
85         el->el_chared.c_vcmd.action = c;
86         return CC_ARGHACK;
87 }
88
89 /* cv_paste():
90  *      Paste previous deletion before or after the cursor
91  */
92 private el_action_t
93 cv_paste(EditLine *el, Int c)
94 {
95         c_kill_t *k = &el->el_chared.c_kill;
96         size_t len = (size_t)(k->last - k->buf);
97
98         if (k->buf == NULL || len == 0)
99                 return CC_ERROR;
100 #ifdef DEBUG_PASTE
101         (void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", (int)len, k->buf);
102 #endif
103
104         cv_undo(el);
105
106         if (!c && el->el_line.cursor < el->el_line.lastchar)
107                 el->el_line.cursor++;
108
109         c_insert(el, (int)len);
110         if (el->el_line.cursor + len > el->el_line.lastchar)
111                 return CC_ERROR;
112         (void) memcpy(el->el_line.cursor, k->buf, len *
113             sizeof(*el->el_line.cursor));
114
115         return CC_REFRESH;
116 }
117
118
119 /* vi_paste_next():
120  *      Vi paste previous deletion to the right of the cursor
121  *      [p]
122  */
123 protected el_action_t
124 /*ARGSUSED*/
125 vi_paste_next(EditLine *el, Int c __attribute__((__unused__)))
126 {
127
128         return cv_paste(el, 0);
129 }
130
131
132 /* vi_paste_prev():
133  *      Vi paste previous deletion to the left of the cursor
134  *      [P]
135  */
136 protected el_action_t
137 /*ARGSUSED*/
138 vi_paste_prev(EditLine *el, Int c __attribute__((__unused__)))
139 {
140
141         return cv_paste(el, 1);
142 }
143
144
145 /* vi_prev_big_word():
146  *      Vi move to the previous space delimited word
147  *      [B]
148  */
149 protected el_action_t
150 /*ARGSUSED*/
151 vi_prev_big_word(EditLine *el, Int c __attribute__((__unused__)))
152 {
153
154         if (el->el_line.cursor == el->el_line.buffer)
155                 return CC_ERROR;
156
157         el->el_line.cursor = cv_prev_word(el->el_line.cursor,
158             el->el_line.buffer,
159             el->el_state.argument,
160             cv__isWord);
161
162         if (el->el_chared.c_vcmd.action != NOP) {
163                 cv_delfini(el);
164                 return CC_REFRESH;
165         }
166         return CC_CURSOR;
167 }
168
169
170 /* vi_prev_word():
171  *      Vi move to the previous word
172  *      [b]
173  */
174 protected el_action_t
175 /*ARGSUSED*/
176 vi_prev_word(EditLine *el, Int c __attribute__((__unused__)))
177 {
178
179         if (el->el_line.cursor == el->el_line.buffer)
180                 return CC_ERROR;
181
182         el->el_line.cursor = cv_prev_word(el->el_line.cursor,
183             el->el_line.buffer,
184             el->el_state.argument,
185             cv__isword);
186
187         if (el->el_chared.c_vcmd.action != NOP) {
188                 cv_delfini(el);
189                 return CC_REFRESH;
190         }
191         return CC_CURSOR;
192 }
193
194
195 /* vi_next_big_word():
196  *      Vi move to the next space delimited word
197  *      [W]
198  */
199 protected el_action_t
200 /*ARGSUSED*/
201 vi_next_big_word(EditLine *el, Int c __attribute__((__unused__)))
202 {
203
204         if (el->el_line.cursor >= el->el_line.lastchar - 1)
205                 return CC_ERROR;
206
207         el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
208             el->el_line.lastchar, el->el_state.argument, cv__isWord);
209
210         if (el->el_map.type == MAP_VI)
211                 if (el->el_chared.c_vcmd.action != NOP) {
212                         cv_delfini(el);
213                         return CC_REFRESH;
214                 }
215         return CC_CURSOR;
216 }
217
218
219 /* vi_next_word():
220  *      Vi move to the next word
221  *      [w]
222  */
223 protected el_action_t
224 /*ARGSUSED*/
225 vi_next_word(EditLine *el, Int c __attribute__((__unused__)))
226 {
227
228         if (el->el_line.cursor >= el->el_line.lastchar - 1)
229                 return CC_ERROR;
230
231         el->el_line.cursor = cv_next_word(el, el->el_line.cursor,
232             el->el_line.lastchar, el->el_state.argument, cv__isword);
233
234         if (el->el_map.type == MAP_VI)
235                 if (el->el_chared.c_vcmd.action != NOP) {
236                         cv_delfini(el);
237                         return CC_REFRESH;
238                 }
239         return CC_CURSOR;
240 }
241
242
243 /* vi_change_case():
244  *      Vi change case of character under the cursor and advance one character
245  *      [~]
246  */
247 protected el_action_t
248 vi_change_case(EditLine *el, Int c)
249 {
250         int i;
251
252         if (el->el_line.cursor >= el->el_line.lastchar)
253                 return CC_ERROR;
254         cv_undo(el);
255         for (i = 0; i < el->el_state.argument; i++) {
256
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);
262
263                 if (++el->el_line.cursor >= el->el_line.lastchar) {
264                         el->el_line.cursor--;
265                         re_fastaddc(el);
266                         break;
267                 }
268                 re_fastaddc(el);
269         }
270         return CC_NORM;
271 }
272
273
274 /* vi_change_meta():
275  *      Vi change prefix command
276  *      [c]
277  */
278 protected el_action_t
279 /*ARGSUSED*/
280 vi_change_meta(EditLine *el, Int c __attribute__((__unused__)))
281 {
282
283         /*
284          * Delete with insert == change: first we delete and then we leave in
285          * insert mode.
286          */
287         return cv_action(el, DELETE | INSERT);
288 }
289
290
291 /* vi_insert_at_bol():
292  *      Vi enter insert mode at the beginning of line
293  *      [I]
294  */
295 protected el_action_t
296 /*ARGSUSED*/
297 vi_insert_at_bol(EditLine *el, Int c __attribute__((__unused__)))
298 {
299
300         el->el_line.cursor = el->el_line.buffer;
301         cv_undo(el);
302         el->el_map.current = el->el_map.key;
303         return CC_CURSOR;
304 }
305
306
307 /* vi_replace_char():
308  *      Vi replace character under the cursor with the next character typed
309  *      [r]
310  */
311 protected el_action_t
312 /*ARGSUSED*/
313 vi_replace_char(EditLine *el, Int c __attribute__((__unused__)))
314 {
315
316         if (el->el_line.cursor >= el->el_line.lastchar)
317                 return CC_ERROR;
318
319         el->el_map.current = el->el_map.key;
320         el->el_state.inputmode = MODE_REPLACE_1;
321         cv_undo(el);
322         return CC_ARGHACK;
323 }
324
325
326 /* vi_replace_mode():
327  *      Vi enter replace mode
328  *      [R]
329  */
330 protected el_action_t
331 /*ARGSUSED*/
332 vi_replace_mode(EditLine *el, Int c __attribute__((__unused__)))
333 {
334
335         el->el_map.current = el->el_map.key;
336         el->el_state.inputmode = MODE_REPLACE;
337         cv_undo(el);
338         return CC_NORM;
339 }
340
341
342 /* vi_substitute_char():
343  *      Vi replace character under the cursor and enter insert mode
344  *      [s]
345  */
346 protected el_action_t
347 /*ARGSUSED*/
348 vi_substitute_char(EditLine *el, Int c __attribute__((__unused__)))
349 {
350
351         c_delafter(el, el->el_state.argument);
352         el->el_map.current = el->el_map.key;
353         return CC_REFRESH;
354 }
355
356
357 /* vi_substitute_line():
358  *      Vi substitute entire line
359  *      [S]
360  */
361 protected el_action_t
362 /*ARGSUSED*/
363 vi_substitute_line(EditLine *el, Int c __attribute__((__unused__)))
364 {
365
366         cv_undo(el);
367         cv_yank(el, el->el_line.buffer,
368             (int)(el->el_line.lastchar - el->el_line.buffer));
369         (void) em_kill_line(el, 0);
370         el->el_map.current = el->el_map.key;
371         return CC_REFRESH;
372 }
373
374
375 /* vi_change_to_eol():
376  *      Vi change to end of line
377  *      [C]
378  */
379 protected el_action_t
380 /*ARGSUSED*/
381 vi_change_to_eol(EditLine *el, Int c __attribute__((__unused__)))
382 {
383
384         cv_undo(el);
385         cv_yank(el, el->el_line.cursor,
386             (int)(el->el_line.lastchar - el->el_line.cursor));
387         (void) ed_kill_line(el, 0);
388         el->el_map.current = el->el_map.key;
389         return CC_REFRESH;
390 }
391
392
393 /* vi_insert():
394  *      Vi enter insert mode
395  *      [i]
396  */
397 protected el_action_t
398 /*ARGSUSED*/
399 vi_insert(EditLine *el, Int c __attribute__((__unused__)))
400 {
401
402         el->el_map.current = el->el_map.key;
403         cv_undo(el);
404         return CC_NORM;
405 }
406
407
408 /* vi_add():
409  *      Vi enter insert mode after the cursor
410  *      [a]
411  */
412 protected el_action_t
413 /*ARGSUSED*/
414 vi_add(EditLine *el, Int c __attribute__((__unused__)))
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
427         cv_undo(el);
428
429         return (el_action_t)ret;
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*/
439 vi_add_at_eol(EditLine *el, Int c __attribute__((__unused__)))
440 {
441
442         el->el_map.current = el->el_map.key;
443         el->el_line.cursor = el->el_line.lastchar;
444         cv_undo(el);
445         return CC_CURSOR;
446 }
447
448
449 /* vi_delete_meta():
450  *      Vi delete prefix command
451  *      [d]
452  */
453 protected el_action_t
454 /*ARGSUSED*/
455 vi_delete_meta(EditLine *el, Int c __attribute__((__unused__)))
456 {
457
458         return cv_action(el, DELETE);
459 }
460
461
462 /* vi_end_big_word():
463  *      Vi move to the end of the current space delimited word
464  *      [E]
465  */
466 protected el_action_t
467 /*ARGSUSED*/
468 vi_end_big_word(EditLine *el, Int c __attribute__((__unused__)))
469 {
470
471         if (el->el_line.cursor == el->el_line.lastchar)
472                 return CC_ERROR;
473
474         el->el_line.cursor = cv__endword(el->el_line.cursor,
475             el->el_line.lastchar, el->el_state.argument, cv__isWord);
476
477         if (el->el_chared.c_vcmd.action != NOP) {
478                 el->el_line.cursor++;
479                 cv_delfini(el);
480                 return CC_REFRESH;
481         }
482         return CC_CURSOR;
483 }
484
485
486 /* vi_end_word():
487  *      Vi move to the end of the current word
488  *      [e]
489  */
490 protected el_action_t
491 /*ARGSUSED*/
492 vi_end_word(EditLine *el, Int c __attribute__((__unused__)))
493 {
494
495         if (el->el_line.cursor == el->el_line.lastchar)
496                 return CC_ERROR;
497
498         el->el_line.cursor = cv__endword(el->el_line.cursor,
499             el->el_line.lastchar, el->el_state.argument, cv__isword);
500
501         if (el->el_chared.c_vcmd.action != NOP) {
502                 el->el_line.cursor++;
503                 cv_delfini(el);
504                 return CC_REFRESH;
505         }
506         return CC_CURSOR;
507 }
508
509
510 /* vi_undo():
511  *      Vi undo last change
512  *      [u]
513  */
514 protected el_action_t
515 /*ARGSUSED*/
516 vi_undo(EditLine *el, Int c __attribute__((__unused__)))
517 {
518         c_undo_t un = el->el_chared.c_undo;
519
520         if (un.len == -1)
521                 return CC_ERROR;
522
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;
526         el->el_chared.c_undo.cursor =
527             (int)(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 __attribute__((__unused__)))
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 __attribute__((__unused__)))
589 {
590
591         if (el->el_line.cursor <= el->el_line.buffer)
592                 return CC_ERROR;
593
594         c_delbefore1(el);
595         el->el_line.cursor--;
596         return CC_REFRESH;
597 }
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*/
606 vi_list_or_eof(EditLine *el, Int c)
607 {
608
609         if (el->el_line.cursor == el->el_line.lastchar) {
610                 if (el->el_line.cursor == el->el_line.buffer) {
611                         terminal_writec(el, c); /* then do a EOF */
612                         return CC_EOF;
613                 } else {
614                         /*
615                          * Here we could list completions, but it is an
616                          * error right now
617                          */
618                         terminal_beep(el);
619                         return CC_ERROR;
620                 }
621         } else {
622 #ifdef notyet
623                 re_goto_bottom(el);
624                 *el->el_line.lastchar = '\0';   /* just in case */
625                 return CC_LIST_CHOICES;
626 #else
627                 /*
628                  * Just complain for now.
629                  */
630                 terminal_beep(el);
631                 return CC_ERROR;
632 #endif
633         }
634 }
635
636
637 /* vi_kill_line_prev():
638  *      Vi cut from beginning of line to cursor
639  *      [^U]
640  */
641 protected el_action_t
642 /*ARGSUSED*/
643 vi_kill_line_prev(EditLine *el, Int c __attribute__((__unused__)))
644 {
645         Char *kp, *cp;
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;
652         c_delbefore(el, (int)(el->el_line.cursor - el->el_line.buffer));
653         el->el_line.cursor = el->el_line.buffer;        /* zap! */
654         return CC_REFRESH;
655 }
656
657
658 /* vi_search_prev():
659  *      Vi search history previous
660  *      [?]
661  */
662 protected el_action_t
663 /*ARGSUSED*/
664 vi_search_prev(EditLine *el, Int c __attribute__((__unused__)))
665 {
666
667         return cv_search(el, ED_SEARCH_PREV_HISTORY);
668 }
669
670
671 /* vi_search_next():
672  *      Vi search history next
673  *      [/]
674  */
675 protected el_action_t
676 /*ARGSUSED*/
677 vi_search_next(EditLine *el, Int c __attribute__((__unused__)))
678 {
679
680         return cv_search(el, ED_SEARCH_NEXT_HISTORY);
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*/
690 vi_repeat_search_next(EditLine *el, Int c __attribute__((__unused__)))
691 {
692
693         if (el->el_search.patlen == 0)
694                 return CC_ERROR;
695         else
696                 return cv_repeat_srch(el, el->el_search.patdir);
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
706 vi_repeat_search_prev(EditLine *el, Int c __attribute__((__unused__)))
707 {
708
709         if (el->el_search.patlen == 0)
710                 return CC_ERROR;
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));
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*/
724 vi_next_char(EditLine *el, Int c __attribute__((__unused__)))
725 {
726         return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0);
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*/
736 vi_prev_char(EditLine *el, Int c __attribute__((__unused__)))
737 {
738         return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0);
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*/
748 vi_to_next_char(EditLine *el, Int c __attribute__((__unused__)))
749 {
750         return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1);
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*/
760 vi_to_prev_char(EditLine *el, Int c __attribute__((__unused__)))
761 {
762         return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1);
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*/
772 vi_repeat_next_char(EditLine *el, Int c __attribute__((__unused__)))
773 {
774
775         return cv_csearch(el, el->el_search.chadir, el->el_search.chacha,
776                 el->el_state.argument, el->el_search.chatflg);
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*/
786 vi_repeat_prev_char(EditLine *el, Int c __attribute__((__unused__)))
787 {
788         el_action_t r;
789         int dir = el->el_search.chadir;
790
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;
795 }
796
797
798 /* vi_match():
799  *      Vi go to matching () {} or []
800  *      [%]
801  */
802 protected el_action_t
803 /*ARGSUSED*/
804 vi_match(EditLine *el, Int c __attribute__((__unused__)))
805 {
806         const Char match_chars[] = STR("()[]{}");
807         Char *cp;
808         size_t delta, i, count;
809         Char o_ch, c_ch;
810
811         *el->el_line.lastchar = '\0';           /* just in case */
812
813         i = Strcspn(el->el_line.cursor, match_chars);
814         o_ch = el->el_line.cursor[i];
815         if (o_ch == 0)
816                 return CC_ERROR;
817         delta = (size_t)(Strchr(match_chars, o_ch) - match_chars);
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
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. */
837                 if (delta > 0)
838                         el->el_line.cursor++;
839                 cv_delfini(el);
840                 return CC_REFRESH;
841         }
842         return CC_CURSOR;
843 }
844
845 /* vi_undo_line():
846  *      Vi undo all changes to line
847  *      [U]
848  */
849 protected el_action_t
850 /*ARGSUSED*/
851 vi_undo_line(EditLine *el, Int c __attribute__((__unused__)))
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*/
865 vi_to_column(EditLine *el, Int c __attribute__((__unused__)))
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*/
879 vi_yank_end(EditLine *el, Int c __attribute__((__unused__)))
880 {
881
882         cv_yank(el, el->el_line.cursor,
883             (int)(el->el_line.lastchar - el->el_line.cursor));
884         return CC_REFRESH;
885 }
886
887 /* vi_yank():
888  *      Vi yank
889  *      [y]
890  */
891 protected el_action_t
892 /*ARGSUSED*/
893 vi_yank(EditLine *el, Int c __attribute__((__unused__)))
894 {
895
896         return cv_action(el, YANK);
897 }
898
899 /* vi_comment_out():
900  *      Vi comment out current command
901  *      [#]
902  */
903 protected el_action_t
904 /*ARGSUSED*/
905 vi_comment_out(EditLine *el, Int c __attribute__((__unused__)))
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  *      [@]
918  * NB: posix implies that we should enter insert mode, however
919  * this is against historical precedent...
920  */
921 protected el_action_t
922 /*ARGSUSED*/
923 vi_alias(EditLine *el __attribute__((__unused__)), Int c __attribute__((__unused__)))
924 {
925         char alias_name[3];
926         const char *alias_text;
927
928         if (el->el_chared.c_aliasfun == NULL)
929                 return CC_ERROR;
930
931         alias_name[0] = '_';
932         alias_name[2] = 0;
933         if (el_getc(el, &alias_name[1]) != 1)
934                 return CC_ERROR;
935
936         alias_text = (*el->el_chared.c_aliasfun)(el->el_chared.c_aliasarg,
937             alias_name);
938         if (alias_text != NULL)
939                 FUN(el,push)(el, ct_decode_string(alias_text, &el->el_scratch));
940         return CC_NORM;
941 }
942
943 /* vi_to_history_line():
944  *      Vi go to specified history file line.
945  *      [G]
946  */
947 protected el_action_t
948 /*ARGSUSED*/
949 vi_to_history_line(EditLine *el, Int c __attribute__((__unused__)))
950 {
951         int sv_event_no = el->el_history.eventno;
952         el_action_t rval;
953
954
955         if (el->el_history.eventno == 0) {
956                  (void) Strncpy(el->el_history.buf, el->el_line.buffer,
957                      EL_BUFSIZ);
958                  el->el_history.last = el->el_history.buf +
959                          (el->el_line.lastchar - el->el_line.buffer);
960         }
961
962         /* Lack of a 'count' means oldest, not 1 */
963         if (!el->el_state.doingarg) {
964                 el->el_history.eventno = 0x7fffffff;
965                 hist_get(el);
966         } else {
967                 /* This is brain dead, all the rest of this code counts
968                  * upwards going into the past.  Here we need count in the
969                  * other direction (to match the output of fc -l).
970                  * I could change the world, but this seems to suffice.
971                  */
972                 el->el_history.eventno = 1;
973                 if (hist_get(el) == CC_ERROR)
974                         return CC_ERROR;
975                 el->el_history.eventno = 1 + el->el_history.ev.num 
976                                         - el->el_state.argument;
977                 if (el->el_history.eventno < 0) {
978                         el->el_history.eventno = sv_event_no;
979                         return CC_ERROR;
980                 }
981         }
982         rval = hist_get(el);
983         if (rval == CC_ERROR)
984                 el->el_history.eventno = sv_event_no;
985         return rval;
986 }
987
988 /* vi_histedit():
989  *      Vi edit history line with vi
990  *      [v]
991  */
992 protected el_action_t
993 /*ARGSUSED*/
994 vi_histedit(EditLine *el, Int c __attribute__((__unused__)))
995 {
996         int fd;
997         pid_t pid;
998         ssize_t st;
999         int status;
1000         char tempfile[] = "/tmp/histedit.XXXXXXXXXX";
1001         char *cp = NULL;
1002         size_t len;
1003         Char *line = NULL;
1004
1005         if (el->el_state.doingarg) {
1006                 if (vi_to_history_line(el, 0) == CC_ERROR)
1007                         return CC_ERROR;
1008         }
1009
1010         fd = mkstemp(tempfile);
1011         if (fd < 0)
1012                 return CC_ERROR;
1013         len = (size_t)(el->el_line.lastchar - el->el_line.buffer);
1014 #define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX)
1015         cp = el_malloc(TMP_BUFSIZ * sizeof(*cp));
1016         if (cp == NULL)
1017                 goto error;
1018         line = el_malloc(len * sizeof(*line) + 1);
1019         if (line == NULL)
1020                 goto error;
1021         Strncpy(line, el->el_line.buffer, len);
1022         line[len] = '\0';
1023         ct_wcstombs(cp, line, TMP_BUFSIZ - 1);
1024         cp[TMP_BUFSIZ - 1] = '\0';
1025         len = strlen(cp);
1026         write(fd, cp, len);
1027         write(fd, "\n", (size_t)1);
1028         pid = fork();
1029         switch (pid) {
1030         case -1:
1031                 goto error;
1032         case 0:
1033                 close(fd);
1034                 execlp("vi", "vi", tempfile, (char *)NULL);
1035                 exit(0);
1036                 /*NOTREACHED*/
1037         default:
1038                 while (waitpid(pid, &status, 0) != pid)
1039                         continue;
1040                 lseek(fd, (off_t)0, SEEK_SET);
1041                 st = read(fd, cp, TMP_BUFSIZ);
1042                 if (st > 0) {
1043                         len = (size_t)(el->el_line.lastchar -
1044                             el->el_line.buffer);
1045                         len = ct_mbstowcs(el->el_line.buffer, cp, len);
1046                         if (len > 0 && el->el_line.buffer[len -1] == '\n')
1047                                 --len;
1048                 }
1049                 else
1050                         len = 0;
1051                 el->el_line.cursor = el->el_line.buffer;
1052                 el->el_line.lastchar = el->el_line.buffer + len;
1053                 el_free(cp);
1054                 el_free(line);
1055                 break;
1056         }
1057
1058         close(fd);
1059         unlink(tempfile);
1060         /* return CC_REFRESH; */
1061         return ed_newline(el, 0);
1062 error:
1063         el_free(line);
1064         el_free(cp);
1065         close(fd);
1066         unlink(tempfile);
1067         return CC_ERROR;
1068 }
1069
1070 /* vi_history_word():
1071  *      Vi append word from previous input line
1072  *      [_]
1073  * Who knows where this one came from!
1074  * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_'
1075  */
1076 protected el_action_t
1077 /*ARGSUSED*/
1078 vi_history_word(EditLine *el, Int c __attribute__((__unused__)))
1079 {
1080         const Char *wp = HIST_FIRST(el);
1081         const Char *wep, *wsp;
1082         int len;
1083         Char *cp;
1084         const Char *lim;
1085
1086         if (wp == NULL)
1087                 return CC_ERROR;
1088
1089         wep = wsp = 0;
1090         do {
1091                 while (Isspace(*wp))
1092                         wp++;
1093                 if (*wp == 0)
1094                         break;
1095                 wsp = wp;
1096                 while (*wp && !Isspace(*wp))
1097                         wp++;
1098                 wep = wp;
1099         } while ((!el->el_state.doingarg || --el->el_state.argument > 0)
1100             && *wp != 0);
1101
1102         if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0))
1103                 return CC_ERROR;
1104
1105         cv_undo(el);
1106         len = (int)(wep - wsp);
1107         if (el->el_line.cursor < el->el_line.lastchar)
1108                 el->el_line.cursor++;
1109         c_insert(el, len + 1);
1110         cp = el->el_line.cursor;
1111         lim = el->el_line.limit;
1112         if (cp < lim)
1113                 *cp++ = ' ';
1114         while (wsp < wep && cp < lim)
1115                 *cp++ = *wsp++;
1116         el->el_line.cursor = cp;
1117
1118         el->el_map.current = el->el_map.key;
1119         return CC_REFRESH;
1120 }
1121
1122 /* vi_redo():
1123  *      Vi redo last non-motion command
1124  *      [.]
1125  */
1126 protected el_action_t
1127 /*ARGSUSED*/
1128 vi_redo(EditLine *el, Int c __attribute__((__unused__)))
1129 {
1130         c_redo_t *r = &el->el_chared.c_redo;
1131
1132         if (!el->el_state.doingarg && r->count) {
1133                 el->el_state.doingarg = 1;
1134                 el->el_state.argument = r->count;
1135         }
1136
1137         el->el_chared.c_vcmd.pos = el->el_line.cursor;
1138         el->el_chared.c_vcmd.action = r->action;
1139         if (r->pos != r->buf) {
1140                 if (r->pos + 1 > r->lim)
1141                         /* sanity */
1142                         r->pos = r->lim - 1;
1143                 r->pos[0] = 0;
1144                 FUN(el,push)(el, r->buf);
1145         }
1146
1147         el->el_state.thiscmd = r->cmd;
1148         el->el_state.thisch = r->ch;
1149         return (*el->el_map.func[r->cmd])(el, r->ch);
1150 }