Added ansidecl.h
[deliverable/binutils-gdb.git] / readline / vi_mode.c
CommitLineData
bd5635a1
RP
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 `?'. */
14static char *vi_last_search = (char *)NULL;
15static int vi_histpos;
16
17/* Non-zero means enter insertion mode. */
18int vi_doing_insert = 0;
19
20/* *** UNCLEAN *** */
21/* Command keys which do movement for xxx_to commands. */
22static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
23
24/* Keymap used for vi replace characters. Created dynamically since
25 rarely used. */
26static Keymap vi_replace_map = (Keymap)NULL;
27
28/* The number of characters inserted in the last replace operation. */
29static vi_replace_count = 0;
30
31/* Yank the nth arg from the previous line into this line at point. */
32rl_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. */
39rl_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. */
55rl_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
135rl_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. */
172rl_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. */
191rl_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. */
207rl_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. */
223rl_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. */
239rl_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
254rl_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
266rl_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
277rl_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
299rl_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
317rl_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
336rl_vi_insert_beg ()
337{
338 rl_beg_of_line ();
339 rl_vi_insertion_mode ();
340 return 0;
341}
342
343rl_vi_append_mode ()
344{
345 if (rl_point < rl_end)
346 rl_point += 1;
347 rl_vi_insertion_mode ();
348 return 0;
349}
350
351rl_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. */
359rl_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. */
369rl_vi_insertion_mode ()
370{
371 keymap = vi_insertion_keymap;
372}
373
374rl_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
383vi_done_inserting ()
384{
385 if (vi_doing_insert)
386 {
387 rl_end_undo_group ();
388 vi_doing_insert = 0;
389 }
390}
391
392rl_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 */
402rl_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
425rl_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
435rl_vi_check ()
436{
437 if (rl_point && rl_point == rl_end)
438 rl_point--;
439}
440
441rl_vi_column (count)
442{
443 if (count > rl_end)
444 rl_end_of_line ();
445 else
446 rl_point = count - 1;
447}
448
449int
450rl_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? */
495rl_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
527rl_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
547rl_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
570rl_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
591rl_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 */
604rl_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
612rl_vi_first_print ()
613{
614 rl_back_to_indent ();
615}
616
617rl_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
631rl_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 */
710rl_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
772int
773rl_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
788rl_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
809rl_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
826rl_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
854rl_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
883rl_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 */
906rl_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.077669 seconds and 4 git commands to generate.