This commit was generated by cvs2svn to track changes on a CVS vendor
[deliverable/binutils-gdb.git] / readline / vi_mode.c
1 /* vi_mode.c -- A vi emulation mode for Bash.
2 Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */
3
4 /* Copyright (C) 1988, 1991 Free Software Foundation, Inc.
5
6 This file is part of the GNU Readline Library (the Library), a set of
7 routines for providing Emacs style line input to programs that ask
8 for it.
9
10 The Library is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 1, or (at your option)
13 any later version.
14
15 The Library is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 The GNU General Public License is often shipped with GNU software, and
21 is generally kept in a file called COPYING or LICENSE. If you do not
22 have a copy of the license, write to the Free Software Foundation,
23 675 Mass Ave, Cambridge, MA 02139, USA. */
24 \f
25 /* **************************************************************** */
26 /* */
27 /* VI Emulation Mode */
28 /* */
29 /* **************************************************************** */
30 #if defined (VI_MODE)
31
32 #include <stdio.h>
33
34 #if defined (__GNUC__)
35 # define alloca __builtin_alloca
36 #else
37 # if defined (sparc) || defined (HAVE_ALLOCA_H)
38 # include <alloca.h>
39 # endif
40 #endif
41
42 /* Some standard library routines. */
43 #include "readline.h"
44 #include "history.h"
45
46 #ifndef digit
47 #define digit(c) ((c) >= '0' && (c) <= '9')
48 #endif
49
50 #ifndef isletter
51 #define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
52 #endif
53
54 #ifndef digit_value
55 #define digit_value(c) ((c) - '0')
56 #endif
57
58 #ifndef member
59 #define member(c, s) ((c) ? index ((s), (c)) : 0)
60 #endif
61
62 #ifndef isident
63 #define isident(c) ((isletter(c) || digit(c) || c == '_'))
64 #endif
65
66 #ifndef exchange
67 #define exchange(x, y) {int temp = x; x = y; y = temp;}
68 #endif
69
70 /* Variables imported from readline.c */
71 extern int rl_point, rl_end, rl_mark, rl_done;
72 extern FILE *rl_instream;
73 extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg;
74 extern Keymap keymap;
75 extern char *rl_prompt;
76 extern char *rl_line_buffer;
77 extern int rl_arg_sign;
78
79 extern char *xmalloc (), *xrealloc ();
80 extern void rl_extend_line_buffer ();
81
82 /* Last string searched for from `/' or `?'. */
83 static char *vi_last_search = (char *)NULL;
84 static int vi_histpos;
85
86 /* Non-zero means enter insertion mode. */
87 int vi_doing_insert = 0;
88
89 /* String inserted into the line by rl_vi_comment (). */
90 char *rl_vi_comment_begin = (char *)NULL;
91
92 /* *** UNCLEAN *** */
93 /* Command keys which do movement for xxx_to commands. */
94 static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
95
96 /* Keymap used for vi replace characters. Created dynamically since
97 rarely used. */
98 static Keymap vi_replace_map = (Keymap)NULL;
99
100 /* The number of characters inserted in the last replace operation. */
101 static int vi_replace_count = 0;
102
103 /* Yank the nth arg from the previous line into this line at point. */
104 rl_vi_yank_arg (count)
105 int count;
106 {
107 /* Readline thinks that the first word on a line is the 0th, while vi
108 thinks the first word on a line is the 1st. Compensate. */
109 if (rl_explicit_arg)
110 rl_yank_nth_arg (count - 1, 0);
111 else
112 rl_yank_nth_arg ('$', 0);
113 }
114
115 /* With an argument, move back that many history lines, else move to the
116 beginning of history. */
117 rl_vi_fetch_history (count, c)
118 int count, c;
119 {
120 extern int rl_explicit_arg;
121 int current = where_history ();
122
123 /* Giving an argument of n means we want the nth command in the history
124 file. The command number is interpreted the same way that the bash
125 `history' command does it -- that is, giving an argument count of 450
126 to this command would get the command listed as number 450 in the
127 output of `history'. */
128 if (rl_explicit_arg)
129 {
130 int wanted = history_base + current - count;
131 if (wanted <= 0)
132 rl_beginning_of_history (0, 0);
133 else
134 rl_get_previous_history (wanted);
135 }
136 else
137 rl_beginning_of_history (count, 0);
138 }
139
140 /* Search again for the last thing searched for. */
141 rl_vi_search_again (ignore, key)
142 int ignore, key;
143 {
144 switch (key)
145 {
146 case 'n':
147 rl_vi_dosearch (vi_last_search, -1);
148 break;
149
150 case 'N':
151 rl_vi_dosearch (vi_last_search, 1);
152 break;
153 }
154 }
155
156 /* Do a vi style search. */
157 rl_vi_search (count, key)
158 int count, key;
159 {
160 int dir, c, save_pos;
161 char *p;
162
163 switch (key)
164 {
165 case '?':
166 dir = 1;
167 break;
168
169 case '/':
170 dir = -1;
171 break;
172
173 default:
174 ding ();
175 return;
176 }
177
178 vi_histpos = where_history ();
179 maybe_save_line ();
180 save_pos = rl_point;
181
182 /* Reuse the line input buffer to read the search string. */
183 rl_line_buffer[0] = 0;
184 rl_end = rl_point = 0;
185 p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0));
186
187 sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key);
188
189 rl_message (p, 0, 0);
190
191 while (c = rl_read_key ())
192 {
193 switch (c)
194 {
195 case CTRL('H'):
196 case RUBOUT:
197 if (rl_point == 0)
198 {
199 maybe_unsave_line ();
200 rl_clear_message ();
201 rl_point = save_pos;
202 return;
203 }
204
205 case CTRL('W'):
206 case CTRL('U'):
207 rl_dispatch (c, keymap);
208 break;
209
210 case ESC:
211 case RETURN:
212 case NEWLINE:
213 goto dosearch;
214 break;
215
216 case CTRL('C'):
217 maybe_unsave_line ();
218 rl_clear_message ();
219 rl_point = 0;
220 ding ();
221 return;
222
223 default:
224 rl_insert (1, c);
225 break;
226 }
227 rl_redisplay ();
228 }
229 dosearch:
230 if (vi_last_search)
231 free (vi_last_search);
232
233 vi_last_search = savestring (rl_line_buffer);
234 rl_vi_dosearch (rl_line_buffer, dir);
235 }
236
237 /* Search for STRING in the history list. DIR is < 0 for searching
238 backwards. POS is an absolute index into the history list at
239 which point to begin searching. If the first character of STRING
240 is `^', the string must match a prefix of a history line, otherwise
241 a full substring match is performed. */
242 static int
243 vi_history_search_pos (string, dir, pos)
244 char *string;
245 int dir, pos;
246 {
247 int ret, old = where_history ();
248
249 history_set_pos (pos);
250
251 if (*string == '^')
252 ret = history_search_prefix (string + 1, dir);
253 else
254 ret = history_search (string, dir);
255
256 if (ret == -1)
257 {
258 history_set_pos (old);
259 return (-1);
260 }
261
262 ret = where_history ();
263 history_set_pos (old);
264 return ret;
265 }
266
267 rl_vi_dosearch (string, dir)
268 char *string;
269 int dir;
270 {
271 int old, save = vi_histpos;
272 HIST_ENTRY *h;
273
274 if (string == 0 || *string == 0 || vi_histpos < 0)
275 {
276 ding ();
277 return;
278 }
279
280 if ((save = vi_history_search_pos (string, dir, vi_histpos + dir)) == -1)
281 {
282 maybe_unsave_line ();
283 rl_clear_message ();
284 rl_point = 0;
285 ding ();
286 return;
287 }
288
289 vi_histpos = save;
290
291 old = where_history ();
292 history_set_pos (vi_histpos);
293 h = current_history ();
294 history_set_pos (old);
295
296 {
297 int line_len = strlen (h->line);
298
299 if (line_len >= rl_line_buffer_len)
300 rl_extend_line_buffer (line_len);
301 strcpy (rl_line_buffer, h->line);
302 }
303
304 rl_undo_list = (UNDO_LIST *)h->data;
305 rl_end = strlen (rl_line_buffer);
306 rl_point = 0;
307 rl_clear_message ();
308 }
309
310 /* Completion, from vi's point of view. */
311 rl_vi_complete (ignore, key)
312 int ignore, key;
313 {
314 if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
315 {
316 if (!whitespace (rl_line_buffer[rl_point + 1]))
317 rl_vi_end_word (1, 'E');
318 rl_point++;
319 }
320
321 if (key == '*')
322 rl_complete_internal ('*'); /* Expansion and replacement. */
323 else if (key == '=')
324 rl_complete_internal ('?'); /* List possible completions. */
325 else if (key == '\\')
326 rl_complete_internal (TAB); /* Standard Readline completion. */
327 else
328 rl_complete (0, key);
329 }
330
331 /* Previous word in vi mode. */
332 rl_vi_prev_word (count, key)
333 int count, key;
334 {
335 if (count < 0)
336 {
337 rl_vi_next_word (-count, key);
338 return;
339 }
340
341 if (rl_point == 0)
342 {
343 ding ();
344 return;
345 }
346
347 if (uppercase_p (key))
348 rl_vi_bWord (count);
349 else
350 rl_vi_bword (count);
351 }
352
353 /* Next word in vi mode. */
354 rl_vi_next_word (count, key)
355 int count;
356 {
357 if (count < 0)
358 {
359 rl_vi_prev_word (-count, key);
360 return;
361 }
362
363 if (rl_point >= (rl_end - 1))
364 {
365 ding ();
366 return;
367 }
368
369 if (uppercase_p (key))
370 rl_vi_fWord (count);
371 else
372 rl_vi_fword (count);
373 }
374
375 /* Move to the end of the ?next? word. */
376 rl_vi_end_word (count, key)
377 int count, key;
378 {
379 if (count < 0)
380 {
381 ding ();
382 return;
383 }
384
385 if (uppercase_p (key))
386 rl_vi_eWord (count);
387 else
388 rl_vi_eword (count);
389 }
390
391 /* Move forward a word the way that 'W' does. */
392 rl_vi_fWord (count)
393 int count;
394 {
395 while (count-- && rl_point < (rl_end - 1))
396 {
397 /* Skip until whitespace. */
398 while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
399 rl_point++;
400
401 /* Now skip whitespace. */
402 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
403 rl_point++;
404 }
405 }
406
407 rl_vi_bWord (count)
408 int count;
409 {
410 while (count-- && rl_point > 0)
411 {
412 /* If we are at the start of a word, move back to whitespace so
413 we will go back to the start of the previous word. */
414 if (!whitespace (rl_line_buffer[rl_point]) &&
415 whitespace (rl_line_buffer[rl_point - 1]))
416 rl_point--;
417
418 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
419 rl_point--;
420
421 if (rl_point > 0)
422 {
423 while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
424 rl_point++;
425 }
426 }
427 }
428
429 rl_vi_eWord (count)
430 int count;
431 {
432 while (count-- && rl_point < (rl_end - 1))
433 {
434 if (!whitespace (rl_line_buffer[rl_point]))
435 rl_point++;
436
437 /* Move to the next non-whitespace character (to the start of the
438 next word). */
439 while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
440
441 if (rl_point && rl_point < rl_end)
442 {
443 /* Skip whitespace. */
444 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
445 rl_point++;
446
447 /* Skip until whitespace. */
448 while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
449 rl_point++;
450
451 /* Move back to the last character of the word. */
452 rl_point--;
453 }
454 }
455 }
456
457 rl_vi_fword (count)
458 int count;
459 {
460 while (count-- && rl_point < (rl_end - 1))
461 {
462 /* Move to white space (really non-identifer). */
463 if (isident (rl_line_buffer[rl_point]))
464 {
465 while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
466 rl_point++;
467 }
468 else /* if (!whitespace (rl_line_buffer[rl_point])) */
469 {
470 while (!isident (rl_line_buffer[rl_point]) &&
471 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
472 rl_point++;
473 }
474
475 /* Move past whitespace. */
476 while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
477 rl_point++;
478 }
479 }
480
481 rl_vi_bword (count)
482 int count;
483 {
484 while (count-- && rl_point > 0)
485 {
486 int last_is_ident;
487
488 /* If we are at the start of a word, move back to whitespace
489 so we will go back to the start of the previous word. */
490 if (!whitespace (rl_line_buffer[rl_point]) &&
491 whitespace (rl_line_buffer[rl_point - 1]))
492 rl_point--;
493
494 /* If this character and the previous character are `opposite', move
495 back so we don't get messed up by the rl_point++ down there in
496 the while loop. Without this code, words like `l;' screw up the
497 function. */
498 last_is_ident = isident (rl_line_buffer[rl_point - 1]);
499 if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
500 (!isident (rl_line_buffer[rl_point]) && last_is_ident))
501 rl_point--;
502
503 while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
504 rl_point--;
505
506 if (rl_point > 0)
507 {
508 if (isident (rl_line_buffer[rl_point]))
509 while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
510 else
511 while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
512 !whitespace (rl_line_buffer[rl_point]));
513 rl_point++;
514 }
515 }
516 }
517
518 rl_vi_eword (count)
519 int count;
520 {
521 while (count-- && rl_point < rl_end - 1)
522 {
523 if (!whitespace (rl_line_buffer[rl_point]))
524 rl_point++;
525
526 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
527 rl_point++;
528
529 if (rl_point < rl_end)
530 {
531 if (isident (rl_line_buffer[rl_point]))
532 while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
533 else
534 while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
535 && !whitespace (rl_line_buffer[rl_point]));
536 }
537 rl_point--;
538 }
539 }
540
541 rl_vi_insert_beg ()
542 {
543 rl_beg_of_line ();
544 rl_vi_insertion_mode ();
545 return 0;
546 }
547
548 rl_vi_append_mode ()
549 {
550 if (rl_point < rl_end)
551 rl_point += 1;
552 rl_vi_insertion_mode ();
553 return 0;
554 }
555
556 rl_vi_append_eol ()
557 {
558 rl_end_of_line ();
559 rl_vi_append_mode ();
560 return 0;
561 }
562
563 /* What to do in the case of C-d. */
564 rl_vi_eof_maybe (count, c)
565 int count, c;
566 {
567 rl_newline (1, '\n');
568 }
569
570 /* Insertion mode stuff. */
571
572 /* Switching from one mode to the other really just involves
573 switching keymaps. */
574 rl_vi_insertion_mode ()
575 {
576 keymap = vi_insertion_keymap;
577 }
578
579 rl_vi_movement_mode ()
580 {
581 if (rl_point > 0)
582 rl_backward (1);
583
584 keymap = vi_movement_keymap;
585 vi_done_inserting ();
586 }
587
588 vi_done_inserting ()
589 {
590 if (vi_doing_insert)
591 {
592 rl_end_undo_group ();
593 vi_doing_insert = 0;
594 }
595 }
596
597 rl_vi_arg_digit (count, c)
598 int count, c;
599 {
600 if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
601 rl_beg_of_line ();
602 else
603 rl_digit_argument (count, c);
604 }
605
606 rl_vi_change_case (count, ignore)
607 int count, ignore;
608 {
609 char c = 0;
610
611 /* Don't try this on an empty line. */
612 if (rl_point >= rl_end)
613 return;
614
615 while (count-- && rl_point < rl_end)
616 {
617 if (uppercase_p (rl_line_buffer[rl_point]))
618 c = to_lower (rl_line_buffer[rl_point]);
619 else if (lowercase_p (rl_line_buffer[rl_point]))
620 c = to_upper (rl_line_buffer[rl_point]);
621
622 /* Vi is kind of strange here. */
623 if (c)
624 {
625 rl_begin_undo_group ();
626 rl_delete (1, c);
627 rl_insert (1, c);
628 rl_end_undo_group ();
629 rl_vi_check ();
630 }
631 else
632 rl_forward (1);
633 }
634 }
635
636 rl_vi_put (count, key)
637 int count, key;
638 {
639 if (!uppercase_p (key) && (rl_point + 1 <= rl_end))
640 rl_point++;
641
642 rl_yank ();
643 rl_backward (1);
644 }
645
646 rl_vi_check ()
647 {
648 if (rl_point && rl_point == rl_end)
649 rl_point--;
650 }
651
652 rl_vi_column (count)
653 {
654 if (count > rl_end)
655 rl_end_of_line ();
656 else
657 rl_point = count - 1;
658 }
659
660 int
661 rl_vi_domove (key, nextkey)
662 int key, *nextkey;
663 {
664 int c, save;
665 int old_end, added_blank;
666
667 added_blank = 0;
668
669 rl_mark = rl_point;
670 c = rl_read_key ();
671 *nextkey = c;
672
673 if (!member (c, vi_motion))
674 {
675 if (digit (c))
676 {
677 save = rl_numeric_arg;
678 rl_numeric_arg = digit_value (c);
679 rl_digit_loop1 ();
680 rl_numeric_arg *= save;
681 c = rl_read_key (); /* real command */
682 *nextkey = c;
683 }
684 else if ((key == 'd' && c == 'd') ||
685 (key == 'y' && c == 'y') ||
686 (key == 'c' && c == 'c'))
687 {
688 rl_mark = rl_end;
689 rl_beg_of_line ();
690 return (0);
691 }
692 else
693 return (-1);
694 }
695
696 /* Append a blank character temporarily so that the motion routines
697 work right at the end of the line. */
698 old_end = rl_end;
699 rl_line_buffer[rl_end++] = ' '; /* This looks pretty bogus to me??? */
700 rl_line_buffer[rl_end] = '\0';
701 added_blank++;
702
703 rl_dispatch (c, keymap);
704
705 /* Remove the blank that we added. */
706 rl_end = old_end;
707 rl_line_buffer[rl_end] = '\0';
708 if (rl_point > rl_end)
709 rl_point = rl_end - 1;
710
711 /* No change in position means the command failed. */
712 if (rl_mark == rl_point)
713 return (-1);
714
715 /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
716 word. If we are not at the end of the line, and we are on a
717 non-whitespace character, move back one (presumably to whitespace). */
718 if ((c == 'w' || c == 'W') && (rl_point < rl_end) &&
719 !whitespace (rl_line_buffer[rl_point]))
720 rl_point--;
721
722 /* If cw or cW, back up to the end of a word, so the behaviour of ce
723 or cE is the actual result. Brute-force, no subtlety. Do the same
724 thing for dw or dW. */
725 if (key == 'c' && (to_upper (c) == 'W'))
726 {
727 while (rl_point && whitespace (rl_line_buffer[rl_point]))
728 rl_point--;
729 }
730
731 if (rl_mark < rl_point)
732 exchange (rl_point, rl_mark);
733
734 return (0);
735 }
736
737 /* A simplified loop for vi. Don't dispatch key at end.
738 Don't recognize minus sign? */
739 rl_digit_loop1 ()
740 {
741 int key, c;
742
743 while (1)
744 {
745 rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
746 key = c = rl_read_key ();
747
748 if (keymap[c].type == ISFUNC &&
749 keymap[c].function == rl_universal_argument)
750 {
751 rl_numeric_arg *= 4;
752 continue;
753 }
754
755 c = UNMETA (c);
756 if (numeric (c))
757 {
758 if (rl_explicit_arg)
759 rl_numeric_arg = (rl_numeric_arg * 10) + digit_value (c);
760 else
761 rl_numeric_arg = digit_value (c);
762 rl_explicit_arg = 1;
763 }
764 else
765 {
766 rl_clear_message ();
767 rl_stuff_char (key);
768 break;
769 }
770 }
771 }
772
773 rl_vi_delete_to (count, key)
774 int count, key;
775 {
776 int c;
777
778 if (uppercase_p (key))
779 rl_stuff_char ('$');
780
781 if (rl_vi_domove (key, &c))
782 {
783 ding ();
784 return;
785 }
786
787 if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end)
788 rl_mark++;
789
790 rl_kill_text (rl_point, rl_mark);
791 }
792
793 rl_vi_change_to (count, key)
794 int count, key;
795 {
796 int c;
797
798 if (uppercase_p (key))
799 rl_stuff_char ('$');
800
801 if (rl_vi_domove (key, &c))
802 {
803 ding ();
804 return;
805 }
806
807 if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end)
808 rl_mark++;
809
810 rl_begin_undo_group ();
811 vi_doing_insert = 1;
812 rl_kill_text (rl_point, rl_mark);
813 rl_vi_insertion_mode ();
814 }
815
816 rl_vi_yank_to (count, key)
817 int count, key;
818 {
819 int c, save = rl_point;
820
821 if (uppercase_p (key))
822 rl_stuff_char ('$');
823
824 if (rl_vi_domove (key, &c))
825 {
826 ding ();
827 return;
828 }
829
830 if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end)
831 rl_mark++;
832
833 rl_begin_undo_group ();
834 rl_kill_text (rl_point, rl_mark);
835 rl_end_undo_group ();
836 rl_do_undo ();
837 rl_point = save;
838 }
839
840 rl_vi_delete (count)
841 {
842 int end;
843
844 if (rl_end == 0)
845 {
846 ding ();
847 return;
848 }
849
850 end = rl_point + count;
851
852 if (end >= rl_end)
853 end = rl_end;
854
855 rl_kill_text (rl_point, end);
856
857 if (rl_point > 0 && rl_point == rl_end)
858 rl_backward (1);
859 }
860
861 /* Turn the current line into a comment in shell history.
862 A K*rn shell style function. */
863 rl_vi_comment ()
864 {
865 rl_beg_of_line ();
866
867 if (rl_vi_comment_begin != (char *)NULL)
868 rl_insert_text (rl_vi_comment_begin);
869 else
870 rl_insert_text (": "); /* Default. */
871
872 rl_redisplay ();
873 rl_newline (1, '\010');
874 }
875
876 rl_vi_first_print ()
877 {
878 rl_back_to_indent ();
879 }
880
881 rl_back_to_indent (ignore1, ignore2)
882 int ignore1, ignore2;
883 {
884 rl_beg_of_line ();
885 while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
886 rl_point++;
887 }
888
889 /* NOTE: it is necessary that opposite directions are inverses */
890 #define FTO 1 /* forward to */
891 #define BTO -1 /* backward to */
892 #define FFIND 2 /* forward find */
893 #define BFIND -2 /* backward find */
894
895 rl_vi_char_search (count, key)
896 int count, key;
897 {
898 static char target;
899 static int orig_dir, dir;
900 int pos;
901
902 if (key == ';' || key == ',')
903 dir = (key == ';' ? orig_dir : -orig_dir);
904 else
905 {
906 target = rl_getc (rl_instream);
907
908 switch (key)
909 {
910 case 't':
911 orig_dir = dir = FTO;
912 break;
913
914 case 'T':
915 orig_dir = dir = BTO;
916 break;
917
918 case 'f':
919 orig_dir = dir = FFIND;
920 break;
921
922 case 'F':
923 orig_dir = dir = BFIND;
924 break;
925 }
926 }
927
928 pos = rl_point;
929
930 while (count--)
931 {
932 if (dir < 0)
933 {
934 if (pos == 0)
935 {
936 ding ();
937 return;
938 }
939
940 pos--;
941 do
942 {
943 if (rl_line_buffer[pos] == target)
944 {
945 if (dir == BTO)
946 rl_point = pos + 1;
947 else
948 rl_point = pos;
949 break;
950 }
951 }
952 while (pos--);
953
954 if (pos < 0)
955 {
956 ding ();
957 return;
958 }
959 }
960 else
961 { /* dir > 0 */
962 if (pos >= rl_end)
963 {
964 ding ();
965 return;
966 }
967
968 pos++;
969 do
970 {
971 if (rl_line_buffer[pos] == target)
972 {
973 if (dir == FTO)
974 rl_point = pos - 1;
975 else
976 rl_point = pos;
977 break;
978 }
979 }
980 while (++pos < rl_end);
981
982 if (pos >= (rl_end - 1))
983 {
984 ding ();
985 return;
986 }
987 }
988 }
989 }
990
991 /* Match brackets */
992 rl_vi_match ()
993 {
994 int count = 1, brack, pos;
995
996 pos = rl_point;
997 if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
998 {
999 while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1000 rl_point < rl_end - 1)
1001 rl_forward (1);
1002
1003 if (brack <= 0)
1004 {
1005 rl_point = pos;
1006 ding ();
1007 return;
1008 }
1009 }
1010
1011 pos = rl_point;
1012
1013 if (brack < 0)
1014 {
1015 while (count)
1016 {
1017 if (--pos >= 0)
1018 {
1019 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1020 if (b == -brack)
1021 count--;
1022 else if (b == brack)
1023 count++;
1024 }
1025 else
1026 {
1027 ding ();
1028 return;
1029 }
1030 }
1031 }
1032 else
1033 { /* brack > 0 */
1034 while (count)
1035 {
1036 if (++pos < rl_end)
1037 {
1038 int b = rl_vi_bracktype (rl_line_buffer[pos]);
1039 if (b == -brack)
1040 count--;
1041 else if (b == brack)
1042 count++;
1043 }
1044 else
1045 {
1046 ding ();
1047 return;
1048 }
1049 }
1050 }
1051 rl_point = pos;
1052 }
1053
1054 int
1055 rl_vi_bracktype (c)
1056 int c;
1057 {
1058 switch (c)
1059 {
1060 case '(': return 1;
1061 case ')': return -1;
1062 case '[': return 2;
1063 case ']': return -2;
1064 case '{': return 3;
1065 case '}': return -3;
1066 default: return 0;
1067 }
1068 }
1069
1070 rl_vi_change_char (count, key)
1071 int count, key;
1072 {
1073 int c;
1074
1075 c = rl_getc (rl_instream);
1076
1077 if (c == '\033' || c == CTRL ('C'))
1078 return;
1079
1080 while (count-- && rl_point < rl_end)
1081 {
1082 rl_begin_undo_group ();
1083
1084 rl_delete (1, c);
1085 rl_insert (1, c);
1086 if (count == 0)
1087 rl_backward (1);
1088
1089 rl_end_undo_group ();
1090 }
1091 }
1092
1093 rl_vi_subst (count, key)
1094 int count, key;
1095 {
1096 rl_begin_undo_group ();
1097 vi_doing_insert = 1;
1098
1099 if (uppercase_p (key))
1100 {
1101 rl_beg_of_line ();
1102 rl_kill_line (1);
1103 }
1104 else
1105 rl_delete (count, key);
1106
1107 rl_vi_insertion_mode ();
1108 }
1109
1110 rl_vi_overstrike (count, key)
1111 int count, key;
1112 {
1113 int i;
1114
1115 if (vi_doing_insert == 0)
1116 {
1117 vi_doing_insert = 1;
1118 rl_begin_undo_group ();
1119 }
1120
1121 for (i = 0; i < count; i++)
1122 {
1123 vi_replace_count++;
1124 rl_begin_undo_group ();
1125
1126 if (rl_point < rl_end)
1127 {
1128 rl_delete (1, key);
1129 rl_insert (1, key);
1130 }
1131 else
1132 rl_insert (1, key);
1133
1134 rl_end_undo_group ();
1135 }
1136 }
1137
1138 rl_vi_overstrike_delete (count)
1139 int count;
1140 {
1141 int i, s;
1142
1143 for (i = 0; i < count; i++)
1144 {
1145 if (vi_replace_count == 0)
1146 {
1147 ding ();
1148 break;
1149 }
1150 s = rl_point;
1151
1152 if (rl_do_undo ())
1153 vi_replace_count--;
1154
1155 if (rl_point == s)
1156 rl_backward (1);
1157 }
1158
1159 if (vi_replace_count == 0 && vi_doing_insert)
1160 {
1161 rl_end_undo_group ();
1162 rl_do_undo ();
1163 vi_doing_insert = 0;
1164 }
1165 }
1166
1167 rl_vi_replace (count, key)
1168 int count, key;
1169 {
1170 int i;
1171
1172 vi_replace_count = 0;
1173
1174 if (!vi_replace_map)
1175 {
1176 vi_replace_map = rl_make_bare_keymap ();
1177
1178 for (i = ' '; i < 127; i++)
1179 vi_replace_map[i].function = rl_vi_overstrike;
1180
1181 vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1182 vi_replace_map[ESC].function = rl_vi_movement_mode;
1183 vi_replace_map[RETURN].function = rl_newline;
1184 vi_replace_map[NEWLINE].function = rl_newline;
1185
1186 /* If the normal vi insertion keymap has ^H bound to erase, do the
1187 same here. Probably should remove the assignment to RUBOUT up
1188 there, but I don't think it will make a difference in real life. */
1189 if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1190 vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1191 vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1192
1193 }
1194 keymap = vi_replace_map;
1195 }
1196
1197 /*
1198 * Try to complete the word we are standing on or the word that ends with
1199 * the previous character. A space matches everything.
1200 * Word delimiters are space and ;.
1201 */
1202 rl_vi_possible_completions()
1203 {
1204 int save_pos = rl_point;
1205
1206 if (!index (" ;", rl_line_buffer[rl_point]))
1207 {
1208 while (!index(" ;", rl_line_buffer[++rl_point]))
1209 ;
1210 }
1211 else if (rl_line_buffer[rl_point-1] == ';')
1212 {
1213 ding ();
1214 return (0);
1215 }
1216
1217 rl_possible_completions ();
1218 rl_point = save_pos;
1219
1220 return (0);
1221 }
1222
1223 #endif /* VI_MODE */
This page took 0.083218 seconds and 5 git commands to generate.