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