* c-exp.y, m2-exp.y: Lint.
[deliverable/binutils-gdb.git] / readline / vi_mode.c
1 /* vi_mode.c -- A vi emulation mode for Bash.
2
3 Derived from code written by Jeff Sparkes (jeff1@????).
4 */
5
6 \f
7 /* **************************************************************** */
8 /* */
9 /* VI Emulation Mode */
10 /* */
11 /* **************************************************************** */
12
13 /* Last string searched for from `/' or `?'. */
14 static char *vi_last_search = (char *)NULL;
15 static int vi_histpos;
16
17 /* Non-zero means enter insertion mode. */
18 int vi_doing_insert = 0;
19
20 /* *** UNCLEAN *** */
21 /* Command keys which do movement for xxx_to commands. */
22 static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
23
24 /* Keymap used for vi replace characters. Created dynamically since
25 rarely used. */
26 static Keymap vi_replace_map = (Keymap)NULL;
27
28 /* The number of characters inserted in the last replace operation. */
29 static vi_replace_count = 0;
30
31 /* Yank the nth arg from the previous line into this line at point. */
32 rl_vi_yank_arg (count)
33 int count;
34 {
35 rl_yank_nth_arg (count, 0);
36 }
37
38 /* Search again for the last thing searched for. */
39 rl_vi_search_again (ignore, key)
40 int ignore, key;
41 {
42 switch (key)
43 {
44 case 'n':
45 rl_vi_dosearch (vi_last_search, -1);
46 break;
47
48 case 'N':
49 rl_vi_dosearch (vi_last_search, 1);
50 break;
51 }
52 }
53
54 /* Do a vi style search. */
55 rl_vi_search (count, key)
56 int count, key;
57 {
58 int dir, c, save_pos;
59 char *p;
60
61 switch (key)
62 {
63 case '?':
64 dir = 1;
65 break;
66
67 case '/':
68 dir = -1;
69 break;
70
71 default:
72 ding ();
73 return;
74 }
75
76 vi_histpos = where_history ();
77 maybe_save_line ();
78 save_pos = rl_point;
79
80 /* Reuse the line input buffer to read the search string. */
81 the_line[0] = 0;
82 rl_end = rl_point = 0;
83 p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0));
84
85 sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key);
86
87 rl_message (p, 0, 0);
88
89 while (c = rl_read_key ())
90 {
91 switch (c)
92 {
93 case CTRL('H'):
94 case RUBOUT:
95 if (rl_point == 0)
96 {
97 maybe_unsave_line ();
98 rl_clear_message ();
99 rl_point = save_pos;
100 return;
101 }
102
103 case CTRL('W'):
104 case CTRL('U'):
105 rl_dispatch (c, keymap);
106 break;
107
108 case ESC:
109 case RETURN:
110 case NEWLINE:
111 goto dosearch;
112 break;
113
114 case CTRL('C'):
115 maybe_unsave_line ();
116 rl_clear_message ();
117 rl_point = 0;
118 ding ();
119 return;
120
121 default:
122 rl_insert (1, c);
123 break;
124 }
125 rl_redisplay ();
126 }
127 dosearch:
128 if (vi_last_search)
129 free (vi_last_search);
130
131 vi_last_search = savestring (the_line);
132 rl_vi_dosearch (the_line, dir);
133 }
134
135 rl_vi_dosearch (string, dir)
136 char *string;
137 int dir;
138 {
139 int old, save = vi_histpos;
140 HIST_ENTRY *h;
141
142 if (string == 0 || *string == 0 || vi_histpos < 0)
143 {
144 ding ();
145 return;
146 }
147
148 if ((save = history_search_pos (string, dir, vi_histpos + dir)) == -1)
149 {
150 maybe_unsave_line ();
151 rl_clear_message ();
152 rl_point = 0;
153 ding ();
154 return;
155 }
156
157 vi_histpos = save;
158
159 old = where_history ();
160 history_set_pos (vi_histpos);
161 h = current_history ();
162 history_set_pos (old);
163
164 strcpy (the_line, h->line);
165 rl_undo_list = (UNDO_LIST *)h->data;
166 rl_end = strlen (the_line);
167 rl_point = 0;
168 rl_clear_message ();
169 }
170
171 /* Completion, from vi's point of view. */
172 rl_vi_complete (ignore, key)
173 int ignore, key;
174 {
175 if (!whitespace (the_line[rl_point]))
176 {
177 if (!whitespace (the_line[rl_point + 1]))
178 rl_vi_end_word (1, 'E');
179 rl_point++;
180 }
181
182 if (key == '*')
183 rl_complete_internal ('*');
184 else
185 rl_complete (0, key);
186
187 rl_vi_insertion_mode ();
188 }
189
190 /* Previous word in vi mode. */
191 rl_vi_prev_word (count, key)
192 int count, key;
193 {
194 if (count < 0)
195 {
196 rl_vi_next_word (-count, key);
197 return;
198 }
199
200 if (uppercase_p (key))
201 rl_vi_bWord (count);
202 else
203 rl_vi_bword (count);
204 }
205
206 /* Next word in vi mode. */
207 rl_vi_next_word (count, key)
208 int count;
209 {
210 if (count < 0)
211 {
212 rl_vi_prev_word (-count, key);
213 return;
214 }
215
216 if (uppercase_p (key))
217 rl_vi_fWord (count);
218 else
219 rl_vi_fword (count);
220 }
221
222 /* Move to the end of the ?next? word. */
223 rl_vi_end_word (count, key)
224 int count, key;
225 {
226 if (count < 0)
227 {
228 ding ();
229 return;
230 }
231
232 if (uppercase_p (key))
233 rl_vi_eWord (count);
234 else
235 rl_vi_eword (count);
236 }
237
238 /* Move forward a word the way that 'W' does. */
239 rl_vi_fWord (count)
240 int count;
241 {
242 while (count-- && rl_point < (rl_end - 1))
243 {
244 /* Skip until whitespace. */
245 while (!whitespace (the_line[rl_point]) && rl_point < rl_end)
246 rl_point++;
247
248 /* Now skip whitespace. */
249 while (whitespace (the_line[rl_point]) && rl_point < rl_end)
250 rl_point++;
251 }
252 }
253
254 rl_vi_bWord (count)
255 int count;
256 {
257 while (count-- && rl_point > 0)
258 {
259 while (rl_point-- >= 0 && whitespace (the_line[rl_point]));
260 while (rl_point >= 0 && !whitespace (the_line[rl_point]))
261 rl_point--;
262 rl_point++;
263 }
264 }
265
266 rl_vi_eWord (count)
267 int count;
268 {
269 while (count -- && rl_point < (rl_end - 1))
270 {
271 while (rl_point++ < rl_end && whitespace (the_line[rl_point]));
272 while (rl_point++ < rl_end && !whitespace (the_line[rl_point]));
273 rl_point--;
274 }
275 }
276
277 rl_vi_fword (count)
278 int count;
279 {
280 while (count -- && rl_point < (rl_end - 1))
281 {
282 if (isident (the_line[rl_point]))
283 {
284 while (isident (the_line[rl_point]) && rl_point < rl_end)
285 rl_point += 1;
286 }
287 else if (!whitespace (the_line[rl_point]))
288 {
289 while (!isident (the_line[rl_point]) &&
290 !whitespace (the_line[rl_point]) && rl_point < rl_end)
291 rl_point += 1;
292 }
293
294 while (whitespace (the_line[rl_point]) && rl_point < rl_end)
295 rl_point++;
296 }
297 }
298
299 rl_vi_bword (count)
300 int count;
301 {
302 while (count -- && rl_point > 0)
303 {
304 while (--rl_point > 0 && whitespace (the_line[rl_point]));
305 if (rl_point > 0)
306 {
307 if (isident (the_line[rl_point]))
308 while (--rl_point >= 0 && isident (the_line[rl_point]));
309 else
310 while (--rl_point >= 0 && !isident (the_line[rl_point]) &&
311 !whitespace (the_line[rl_point]));
312 rl_point++;
313 }
314 }
315 }
316
317 rl_vi_eword (count)
318 int count;
319 {
320 while (count -- && rl_point < rl_end - 1)
321 {
322 while (++rl_point < rl_end && whitespace (the_line[rl_point]));
323
324 if (rl_point < rl_end)
325 {
326 if (isident (the_line[rl_point]))
327 while (++rl_point < rl_end && isident (the_line[rl_point]));
328 else
329 while (++rl_point < rl_end && !isident (the_line[rl_point])
330 && !whitespace (the_line[rl_point]));
331 rl_point--;
332 }
333 }
334 }
335
336 rl_vi_insert_beg ()
337 {
338 rl_beg_of_line ();
339 rl_vi_insertion_mode ();
340 return 0;
341 }
342
343 rl_vi_append_mode ()
344 {
345 if (rl_point < rl_end)
346 rl_point += 1;
347 rl_vi_insertion_mode ();
348 return 0;
349 }
350
351 rl_vi_append_eol ()
352 {
353 rl_end_of_line ();
354 rl_vi_append_mode ();
355 return 0;
356 }
357
358 /* What to do in the case of C-d. */
359 rl_vi_eof_maybe (count, c)
360 int count, c;
361 {
362 rl_newline (1, '\n');
363 }
364
365 /* Insertion mode stuff. */
366
367 /* Switching from one mode to the other really just involves
368 switching keymaps. */
369 rl_vi_insertion_mode ()
370 {
371 keymap = vi_insertion_keymap;
372 }
373
374 rl_vi_movement_mode ()
375 {
376 if (rl_point > 0)
377 rl_backward (1);
378
379 keymap = vi_movement_keymap;
380 vi_done_inserting ();
381 }
382
383 vi_done_inserting ()
384 {
385 if (vi_doing_insert)
386 {
387 rl_end_undo_group ();
388 vi_doing_insert = 0;
389 }
390 }
391
392 rl_vi_arg_digit (count, c)
393 int count, c;
394 {
395 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
396 rl_beg_of_line ();
397 else
398 rl_digit_argument (count, c);
399 }
400
401 /* Doesn't take an arg count in vi */
402 rl_vi_change_case (ignore1, ignore2)
403 int ignore1, ignore2;
404 {
405 char c = 0;
406
407 if (uppercase_p (the_line[rl_point]))
408 c = to_lower (the_line[rl_point]);
409 else if (lowercase_p (the_line[rl_point]))
410 c = to_upper (the_line[rl_point]);
411
412 /* Vi is kind of strange here. */
413 if (c)
414 {
415 rl_begin_undo_group ();
416 rl_delete (1, c);
417 rl_insert (1, c);
418 rl_end_undo_group ();
419 rl_vi_check ();
420 }
421 else
422 rl_forward (1);
423 }
424
425 rl_vi_put (count, key)
426 int count, key;
427 {
428 if (!uppercase_p (key))
429 rl_forward (1);
430
431 rl_yank ();
432 rl_backward (1);
433 }
434
435 rl_vi_check ()
436 {
437 if (rl_point && rl_point == rl_end)
438 rl_point--;
439 }
440
441 rl_vi_column (count)
442 {
443 if (count > rl_end)
444 rl_end_of_line ();
445 else
446 rl_point = count - 1;
447 }
448
449 int
450 rl_vi_domove (key, nextkey)
451 int key, *nextkey;
452 {
453 int c, save;
454
455 rl_mark = rl_point;
456 c = rl_read_key ();
457 *nextkey = c;
458
459 if (!member (c, vi_motion))
460 {
461 if (digit (c))
462 {
463 save = rl_numeric_arg;
464 rl_digit_loop1 ();
465 rl_numeric_arg *= save;
466 }
467 else if ((key == 'd' && c == 'd') ||
468 (key == 'c' && c == 'c'))
469 {
470 rl_mark = rl_end;
471 rl_beg_of_line ();
472 return (0);
473 }
474 else
475 return (-1);
476 }
477
478 rl_dispatch (c, keymap);
479
480 /* No change in position means the command failed. */
481 if (rl_mark == rl_point)
482 return (-1);
483
484 if ((c == 'w' || c == 'W') && rl_point < rl_end)
485 rl_point--;
486
487 if (rl_mark < rl_point)
488 exchange (rl_point, rl_mark);
489
490 return (0);
491 }
492
493 /* A simplified loop for vi. Don't dispatch key at end.
494 Don't recognize minus sign? */
495 rl_digit_loop1 ()
496 {
497 int key, c;
498
499 while (1)
500 {
501 rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg, 0);
502 key = c = rl_read_key ();
503
504 if (keymap[c].type == ISFUNC &&
505 keymap[c].function == rl_universal_argument)
506 {
507 rl_numeric_arg *= 4;
508 continue;
509 }
510 c = UNMETA (c);
511 if (numeric (c))
512 {
513 if (rl_explicit_arg)
514 rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
515 else
516 rl_numeric_arg = (c - '0');
517 rl_explicit_arg = 1;
518 }
519 else
520 {
521 rl_clear_message ();
522 rl_stuff_char (key);
523 }
524 }
525 }
526
527 rl_vi_delete_to (count, key)
528 int count, key;
529 {
530 int c;
531
532 if (uppercase_p (key))
533 rl_stuff_char ('$');
534
535 if (rl_vi_domove (key, &c))
536 {
537 ding ();
538 return;
539 }
540
541 if ((c != '|') && (c != 'h') && rl_mark < rl_end)
542 rl_mark++;
543
544 rl_kill_text (rl_point, rl_mark);
545 }
546
547 rl_vi_change_to (count, key)
548 int count, key;
549 {
550 int c;
551
552 if (uppercase_p (key))
553 rl_stuff_char ('$');
554
555 if (rl_vi_domove (key, &c))
556 {
557 ding ();
558 return;
559 }
560
561 if ((c != '|') && (c != 'h') && rl_mark < rl_end)
562 rl_mark++;
563
564 rl_begin_undo_group ();
565 vi_doing_insert = 1;
566 rl_kill_text (rl_point, rl_mark);
567 rl_vi_insertion_mode ();
568 }
569
570 rl_vi_yank_to (count, key)
571 int count, key;
572 {
573 int c, save = rl_point;
574
575 if (uppercase_p (key))
576 rl_stuff_char ('$');
577
578 if (rl_vi_domove (key, &c))
579 {
580 ding ();
581 return;
582 }
583
584 rl_begin_undo_group ();
585 rl_kill_text (rl_point, rl_mark);
586 rl_end_undo_group ();
587 rl_do_undo ();
588 rl_point = save;
589 }
590
591 rl_vi_delete (count)
592 {
593 if (rl_point >= rl_end - 1)
594 {
595 rl_delete (count, 0);
596 if (rl_point > 0)
597 rl_backward (1);
598 }
599 else
600 rl_delete (count, 0);
601 }
602
603 /* Turn the current line into a comment in shell history. A ksh function */
604 rl_vi_comment ()
605 {
606 rl_beg_of_line ();
607 rl_insert_text (": "); /* # doesn't work in interactive mode */
608 rl_redisplay ();
609 rl_newline (1, '\010');
610 }
611
612 rl_vi_first_print ()
613 {
614 rl_back_to_indent ();
615 }
616
617 rl_back_to_indent (ignore1, ignore2)
618 int ignore1, ignore2;
619 {
620 rl_beg_of_line ();
621 while (rl_point < rl_end && whitespace (the_line[rl_point]))
622 rl_point++;
623 }
624
625 /* NOTE: it is necessary that opposite directions are inverses */
626 #define FTO 1 /* forward to */
627 #define BTO -1 /* backward to */
628 #define FFIND 2 /* forward find */
629 #define BFIND -2 /* backward find */
630
631 rl_vi_char_search (count, key)
632 int count, key;
633 {
634 static char target;
635 static int orig_dir, dir;
636 int pos;
637
638 if (key == ';' || key == ',')
639 dir = (key == ';' ? orig_dir : -orig_dir);
640 else
641 {
642 target = rl_getc (in_stream);
643
644 switch (key)
645 {
646 case 't':
647 orig_dir = dir = FTO;
648 break;
649
650 case 'T':
651 orig_dir = dir = BTO;
652 break;
653
654 case 'f':
655 orig_dir = dir = FFIND;
656 break;
657
658 case 'F':
659 orig_dir = dir = BFIND;
660 break;
661 }
662 }
663
664 pos = rl_point;
665
666 if (dir < 0)
667 {
668 pos--;
669 do
670 {
671 if (the_line[pos] == target)
672 {
673 if (dir == BTO)
674 rl_point = pos + 1;
675 else
676 rl_point = pos;
677 return;
678 }
679 }
680 while (pos--);
681
682 if (pos < 0)
683 {
684 ding ();
685 return;
686 }
687 }
688 else
689 { /* dir > 0 */
690 pos++;
691 do
692 {
693 if (the_line[pos] == target)
694 {
695 if (dir == FTO)
696 rl_point = pos - 1;
697 else
698 rl_point = pos;
699 return;
700 }
701 }
702 while (++pos < rl_end);
703
704 if (pos >= (rl_end - 1))
705 ding ();
706 }
707 }
708
709 /* Match brackets */
710 rl_vi_match ()
711 {
712 int count = 1, brack, pos;
713
714 pos = rl_point;
715 if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0)
716 {
717 while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 &&
718 rl_point < rl_end - 1)
719 rl_forward (1);
720
721 if (brack <= 0)
722 {
723 rl_point = pos;
724 ding ();
725 return;
726 }
727 }
728
729 pos = rl_point;
730
731 if (brack < 0)
732 {
733 while (count)
734 {
735 if (--pos >= 0)
736 {
737 int b = rl_vi_bracktype (the_line[pos]);
738 if (b == -brack)
739 count--;
740 else if (b == brack)
741 count++;
742 }
743 else
744 {
745 ding ();
746 return;
747 }
748 }
749 }
750 else
751 { /* brack > 0 */
752 while (count)
753 {
754 if (++pos < rl_end)
755 {
756 int b = rl_vi_bracktype (the_line[pos]);
757 if (b == -brack)
758 count--;
759 else if (b == brack)
760 count++;
761 }
762 else
763 {
764 ding ();
765 return;
766 }
767 }
768 }
769 rl_point = pos;
770 }
771
772 int
773 rl_vi_bracktype (c)
774 int c;
775 {
776 switch (c)
777 {
778 case '(': return 1;
779 case ')': return -1;
780 case '[': return 2;
781 case ']': return -2;
782 case '{': return 3;
783 case '}': return -3;
784 default: return 0;
785 }
786 }
787
788 rl_vi_change_char ()
789 {
790 int c;
791
792 c = rl_getc (in_stream);
793
794 switch (c)
795 {
796 case '\033':
797 case CTRL('C'):
798 return;
799
800 default:
801 rl_begin_undo_group ();
802 rl_delete (1, c);
803 rl_insert (1, c);
804 rl_end_undo_group ();
805 break;
806 }
807 }
808
809 rl_vi_subst (count, key)
810 int count, key;
811 {
812 rl_begin_undo_group ();
813 vi_doing_insert = 1;
814
815 if (uppercase_p (key))
816 {
817 rl_beg_of_line ();
818 rl_kill_line (1);
819 }
820 else
821 rl_delete (1, key);
822
823 rl_vi_insertion_mode ();
824 }
825
826 rl_vi_overstrike (count, key)
827 int count, key;
828 {
829 int i;
830
831 if (vi_doing_insert == 0)
832 {
833 vi_doing_insert = 1;
834 rl_begin_undo_group ();
835 }
836
837 for (i = 0; i < count; i++)
838 {
839 vi_replace_count++;
840 rl_begin_undo_group ();
841
842 if (rl_point < rl_end)
843 {
844 rl_delete (1, key);
845 rl_insert (1, key);
846 }
847 else
848 rl_insert (1, key);
849
850 rl_end_undo_group ();
851 }
852 }
853
854 rl_vi_overstrike_delete (count)
855 int count;
856 {
857 int i, s;
858
859 for (i = 0; i < count; i++)
860 {
861 if (vi_replace_count == 0)
862 {
863 ding ();
864 break;
865 }
866 s = rl_point;
867
868 if (rl_do_undo ())
869 vi_replace_count--;
870
871 if (rl_point == s)
872 rl_backward (1);
873 }
874
875 if (vi_replace_count == 0 && vi_doing_insert)
876 {
877 rl_end_undo_group ();
878 rl_do_undo ();
879 vi_doing_insert = 0;
880 }
881 }
882
883 rl_vi_replace ()
884 {
885 int i;
886
887 vi_replace_count = 0;
888
889 vi_replace_map = rl_make_bare_keymap ();
890
891 for (i = ' '; i < 127; i++)
892 vi_replace_map[i].function = rl_vi_overstrike;
893
894 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
895 vi_replace_map[ESC].function = rl_vi_movement_mode;
896 vi_replace_map[RETURN].function = rl_newline;
897 vi_replace_map[NEWLINE].function = rl_newline;
898 keymap = vi_replace_map;
899 }
900
901 /*
902 * Try to complete the word we are standing on or the word that ends with
903 * the previous character. A space matches everything.
904 * Word delimiters are space and ;.
905 */
906 rl_vi_possible_completions()
907 {
908 int save_pos = rl_point;
909
910 if (!index (" ;", the_line[rl_point]))
911 {
912 while (!index(" ;", the_line[++rl_point]))
913 ;
914 }
915 else if (the_line[rl_point-1] == ';')
916 {
917 ding ();
918 return (0);
919 }
920
921 rl_possible_completions ();
922 rl_point = save_pos;
923
924 return (0);
925 }
This page took 0.049539 seconds and 4 git commands to generate.