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