Imported from ../bash-2.01.1.tar.gz.
[platform/upstream/bash.git] / lib / 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) 1987, 1989, 1992 Free Software Foundation, Inc.
5
6    This file is part of the GNU Readline Library, a library for
7    reading lines of text with interactive input and history editing.
8
9    The GNU Readline Library is free software; you can redistribute it
10    and/or modify it under the terms of the GNU General Public License
11    as published by the Free Software Foundation; either version 1, or
12    (at your option) any later version.
13
14    The GNU Readline Library is distributed in the hope that it will be
15    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    The GNU General Public License is often shipped with GNU software, and
20    is generally kept in a file called COPYING or LICENSE.  If you do not
21    have a copy of the license, write to the Free Software Foundation,
22    675 Mass Ave, Cambridge, MA 02139, USA. */
23 #define READLINE_LIBRARY
24
25 /* **************************************************************** */
26 /*                                                                  */
27 /*                      VI Emulation Mode                           */
28 /*                                                                  */
29 /* **************************************************************** */
30 #include "rlconf.h"
31
32 #if defined (VI_MODE)
33
34 #if defined (HAVE_CONFIG_H)
35 #  include <config.h>
36 #endif
37
38 #include <sys/types.h>
39
40 #if defined (HAVE_STDLIB_H)
41 #  include <stdlib.h>
42 #else
43 #  include "ansi_stdlib.h"
44 #endif /* HAVE_STDLIB_H */
45
46 #if defined (HAVE_UNISTD_H)
47 #  include <unistd.h>
48 #endif
49
50 #include <stdio.h>
51
52 /* Some standard library routines. */
53 #include "rldefs.h"
54 #include "readline.h"
55 #include "history.h"
56
57 #ifndef _rl_digit_p
58 #define _rl_digit_p(c)  ((c) >= '0' && (c) <= '9')
59 #endif
60
61 #ifndef _rl_digit_value
62 #define _rl_digit_value(c) ((c) - '0')
63 #endif
64
65 #ifndef member
66 #define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
67 #endif
68
69 #ifndef isident
70 #define isident(c) ((_rl_pure_alphabetic (c) || _rl_digit_p (c) || c == '_'))
71 #endif
72
73 #ifndef exchange
74 #define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0)
75 #endif
76
77 extern char *xmalloc (), *xrealloc ();
78
79 /* Variables imported from readline.c */
80 extern int rl_point, rl_end, rl_mark, rl_done;
81 extern FILE *rl_instream;
82 extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg;
83 extern Keymap _rl_keymap;
84 extern char *rl_prompt;
85 extern char *rl_line_buffer;
86 extern int rl_arg_sign;
87
88 extern int _rl_doing_an_undo;
89 extern int _rl_undo_group_level;
90
91 extern void _rl_dispatch ();
92 extern int _rl_char_search_internal ();
93
94 extern void rl_extend_line_buffer ();
95 extern int rl_vi_check ();
96
97 /* Non-zero means enter insertion mode. */
98 static int _rl_vi_doing_insert;
99
100 /* Command keys which do movement for xxx_to commands. */
101 static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
102
103 /* Keymap used for vi replace characters.  Created dynamically since
104    rarely used. */
105 static Keymap vi_replace_map;
106
107 /* The number of characters inserted in the last replace operation. */
108 static int vi_replace_count;
109
110 /* If non-zero, we have text inserted after a c[motion] command that put
111    us implicitly into insert mode.  Some people want this text to be
112    attached to the command so that it is `redoable' with `.'. */
113 static int vi_continued_command;
114 static char *vi_insert_buffer;
115 static int vi_insert_buffer_size;
116
117 static int _rl_vi_last_command = 'i';   /* default `.' puts you in insert mode */
118 static int _rl_vi_last_repeat = 1;
119 static int _rl_vi_last_arg_sign = 1;
120 static int _rl_vi_last_motion;
121 static int _rl_vi_last_search_char;
122 static int _rl_vi_last_replacement;
123
124 static int _rl_vi_last_key_before_insert;
125
126 static int vi_redoing;
127
128 /* Text modification commands.  These are the `redoable' commands. */
129 static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
130
131 /* Arrays for the saved marks. */
132 static int vi_mark_chars[27];
133
134 static int rl_digit_loop1 ();
135
136 void
137 _rl_vi_initialize_line ()
138 {
139   register int i;
140
141   for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
142     vi_mark_chars[i] = -1;
143 }
144
145 void
146 _rl_vi_reset_last ()
147 {
148   _rl_vi_last_command = 'i';
149   _rl_vi_last_repeat = 1;
150   _rl_vi_last_arg_sign = 1;
151   _rl_vi_last_motion = 0;
152 }
153
154 void
155 _rl_vi_set_last (key, repeat, sign)
156      int key, repeat, sign;
157 {
158   _rl_vi_last_command = key;
159   _rl_vi_last_repeat = repeat;
160   _rl_vi_last_arg_sign = sign;
161 }
162
163 /* Is the command C a VI mode text modification command? */
164 int
165 _rl_vi_textmod_command (c)
166      int c;
167 {
168   return (member (c, vi_textmod));
169 }
170
171 static void
172 _rl_vi_stuff_insert (count)
173      int count;
174 {
175   rl_begin_undo_group ();
176   while (count--)
177     rl_insert_text (vi_insert_buffer);
178   rl_end_undo_group ();
179 }
180
181 /* Bound to `.'.  Called from command mode, so we know that we have to
182    redo a text modification command.  The default for _rl_vi_last_command
183    puts you back into insert mode. */
184 int
185 rl_vi_redo (count, c)
186      int count, c;
187 {
188   if (!rl_explicit_arg)
189     {
190       rl_numeric_arg = _rl_vi_last_repeat;
191       rl_arg_sign = _rl_vi_last_arg_sign;
192     }
193
194   vi_redoing = 1;
195   /* If we're redoing an insert with `i', stuff in the inserted text
196      and do not go into insertion mode. */
197   if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
198     {
199       _rl_vi_stuff_insert (count);
200       /* And back up point over the last character inserted. */
201       if (rl_point > 0)
202         rl_point--;
203     }
204   else
205     _rl_dispatch (_rl_vi_last_command, _rl_keymap);
206   vi_redoing = 0;
207
208   return (0);
209 }
210
211 /* A placeholder for further expansion. */
212 int
213 rl_vi_undo (count, key)
214      int count, key;
215 {
216   return (rl_undo_command (count, key));
217 }
218     
219 /* Yank the nth arg from the previous line into this line at point. */
220 int
221 rl_vi_yank_arg (count, key)
222      int count, key;
223 {
224   /* Readline thinks that the first word on a line is the 0th, while vi
225      thinks the first word on a line is the 1st.  Compensate. */
226   if (rl_explicit_arg)
227     rl_yank_nth_arg (count - 1, 0);
228   else
229     rl_yank_nth_arg ('$', 0);
230
231   return (0);
232 }
233
234 /* With an argument, move back that many history lines, else move to the
235    beginning of history. */
236 int
237 rl_vi_fetch_history (count, c)
238      int count, c;
239 {
240   int wanted;
241
242   /* Giving an argument of n means we want the nth command in the history
243      file.  The command number is interpreted the same way that the bash
244      `history' command does it -- that is, giving an argument count of 450
245      to this command would get the command listed as number 450 in the
246      output of `history'. */
247   if (rl_explicit_arg)
248     {
249       wanted = history_base + where_history () - count;
250       if (wanted <= 0)
251         rl_beginning_of_history (0, 0);
252       else
253         rl_get_previous_history (wanted, c);
254     }
255   else
256     rl_beginning_of_history (count, 0);
257   return (0);
258 }
259
260 /* Search again for the last thing searched for. */
261 int
262 rl_vi_search_again (count, key)
263      int count, key;
264 {
265   switch (key)
266     {
267     case 'n':
268       rl_noninc_reverse_search_again (count, key);
269       break;
270
271     case 'N':
272       rl_noninc_forward_search_again (count, key);
273       break;
274     }
275   return (0);
276 }
277
278 /* Do a vi style search. */
279 int
280 rl_vi_search (count, key)
281      int count, key;
282 {
283   switch (key)
284     {
285     case '?':
286       rl_noninc_forward_search (count, key);
287       break;
288
289     case '/':
290       rl_noninc_reverse_search (count, key);
291       break;
292
293     default:
294       ding ();
295       break;
296     }
297   return (0);
298 }
299
300 /* Completion, from vi's point of view. */
301 int
302 rl_vi_complete (ignore, key)
303      int ignore, key;
304 {
305   if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
306     {
307       if (!whitespace (rl_line_buffer[rl_point + 1]))
308         rl_vi_end_word (1, 'E');
309       rl_point++;
310     }
311
312   if (key == '*')
313     rl_complete_internal ('*'); /* Expansion and replacement. */
314   else if (key == '=')
315     rl_complete_internal ('?'); /* List possible completions. */
316   else if (key == '\\')
317     rl_complete_internal (TAB); /* Standard Readline completion. */
318   else
319     rl_complete (0, key);
320
321   if (key == '*' || key == '\\')
322     {
323       _rl_vi_set_last (key, 1, rl_arg_sign);
324       rl_vi_insertion_mode (1, key);
325     }
326   return (0);
327 }
328
329 /* Tilde expansion for vi mode. */
330 int
331 rl_vi_tilde_expand (ignore, key)
332      int ignore, key;
333 {
334   rl_tilde_expand (0, key);
335   _rl_vi_set_last (key, 1, rl_arg_sign);        /* XXX */
336   rl_vi_insertion_mode (1, key);
337   return (0);
338 }
339
340 /* Previous word in vi mode. */
341 int
342 rl_vi_prev_word (count, key)
343      int count, key;
344 {
345   if (count < 0)
346     return (rl_vi_next_word (-count, key));
347
348   if (rl_point == 0)
349     {
350       ding ();
351       return (0);
352     }
353
354   if (_rl_uppercase_p (key))
355     rl_vi_bWord (count);
356   else
357     rl_vi_bword (count);
358
359   return (0);
360 }
361
362 /* Next word in vi mode. */
363 int
364 rl_vi_next_word (count, key)
365      int count, key;
366 {
367   if (count < 0)
368     return (rl_vi_prev_word (-count, key));
369
370   if (rl_point >= (rl_end - 1))
371     {
372       ding ();
373       return (0);
374     }
375
376   if (_rl_uppercase_p (key))
377     rl_vi_fWord (count);
378   else
379     rl_vi_fword (count);
380   return (0);
381 }
382
383 /* Move to the end of the ?next? word. */
384 int
385 rl_vi_end_word (count, key)
386      int count, key;
387 {
388   if (count < 0)
389     {
390       ding ();
391       return -1;
392     }
393
394   if (_rl_uppercase_p (key))
395     rl_vi_eWord (count);
396   else
397     rl_vi_eword (count);
398   return (0);
399 }
400
401 /* Move forward a word the way that 'W' does. */
402 int
403 rl_vi_fWord (count)
404      int count;
405 {
406   while (count-- && rl_point < (rl_end - 1))
407     {
408       /* Skip until whitespace. */
409       while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
410         rl_point++;
411
412       /* Now skip whitespace. */
413       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
414         rl_point++;
415     }
416   return (0);
417 }
418
419 int
420 rl_vi_bWord (count)
421      int count;
422 {
423   while (count-- && rl_point > 0)
424     {
425       /* If we are at the start of a word, move back to whitespace so
426          we will go back to the start of the previous word. */
427       if (!whitespace (rl_line_buffer[rl_point]) &&
428           whitespace (rl_line_buffer[rl_point - 1]))
429         rl_point--;
430
431       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
432         rl_point--;
433
434       if (rl_point > 0)
435         {
436           while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
437           rl_point++;
438         }
439     }
440   return (0);
441 }
442
443 int
444 rl_vi_eWord (count)
445      int count;
446 {
447   while (count-- && rl_point < (rl_end - 1))
448     {
449       if (!whitespace (rl_line_buffer[rl_point]))
450         rl_point++;
451
452       /* Move to the next non-whitespace character (to the start of the
453          next word). */
454       while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
455
456       if (rl_point && rl_point < rl_end)
457         {
458           /* Skip whitespace. */
459           while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
460             rl_point++;
461
462           /* Skip until whitespace. */
463           while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
464             rl_point++;
465
466           /* Move back to the last character of the word. */
467           rl_point--;
468         }
469     }
470   return (0);
471 }
472
473 int
474 rl_vi_fword (count)
475      int count;
476 {
477   while (count-- && rl_point < (rl_end - 1))
478     {
479       /* Move to white space (really non-identifer). */
480       if (isident (rl_line_buffer[rl_point]))
481         {
482           while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
483             rl_point++;
484         }
485       else /* if (!whitespace (rl_line_buffer[rl_point])) */
486         {
487           while (!isident (rl_line_buffer[rl_point]) &&
488                  !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
489             rl_point++;
490         }
491
492       /* Move past whitespace. */
493       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
494         rl_point++;
495     }
496   return (0);
497 }
498
499 int
500 rl_vi_bword (count)
501      int count;
502 {
503   while (count-- && rl_point > 0)
504     {
505       int last_is_ident;
506
507       /* If we are at the start of a word, move back to whitespace
508          so we will go back to the start of the previous word. */
509       if (!whitespace (rl_line_buffer[rl_point]) &&
510           whitespace (rl_line_buffer[rl_point - 1]))
511         rl_point--;
512
513       /* If this character and the previous character are `opposite', move
514          back so we don't get messed up by the rl_point++ down there in
515          the while loop.  Without this code, words like `l;' screw up the
516          function. */
517       last_is_ident = isident (rl_line_buffer[rl_point - 1]);
518       if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
519           (!isident (rl_line_buffer[rl_point]) && last_is_ident))
520         rl_point--;
521
522       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
523         rl_point--;
524
525       if (rl_point > 0)
526         {
527           if (isident (rl_line_buffer[rl_point]))
528             while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
529           else
530             while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
531                    !whitespace (rl_line_buffer[rl_point]));
532           rl_point++;
533         }
534     }
535   return (0);
536 }
537
538 int
539 rl_vi_eword (count)
540      int count;
541 {
542   while (count-- && rl_point < rl_end - 1)
543     {
544       if (!whitespace (rl_line_buffer[rl_point]))
545         rl_point++;
546
547       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
548         rl_point++;
549
550       if (rl_point < rl_end)
551         {
552           if (isident (rl_line_buffer[rl_point]))
553             while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
554           else
555             while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
556                    && !whitespace (rl_line_buffer[rl_point]));
557         }
558       rl_point--;
559     }
560   return (0);
561 }
562
563 int
564 rl_vi_insert_beg (count, key)
565      int count, key;
566 {
567   rl_beg_of_line (1, key);
568   rl_vi_insertion_mode (1, key);
569   return (0);
570 }
571
572 int
573 rl_vi_append_mode (count, key)
574      int count, key;
575 {
576   if (rl_point < rl_end)
577     rl_point++;
578   rl_vi_insertion_mode (1, key);
579   return (0);
580 }
581
582 int
583 rl_vi_append_eol (count, key)
584      int count, key;
585 {
586   rl_end_of_line (1, key);
587   rl_vi_append_mode (1, key);
588   return (0);
589 }
590
591 /* What to do in the case of C-d. */
592 int
593 rl_vi_eof_maybe (count, c)
594      int count, c;
595 {
596   return (rl_newline (1, '\n'));
597 }
598
599 /* Insertion mode stuff. */
600
601 /* Switching from one mode to the other really just involves
602    switching keymaps. */
603 int
604 rl_vi_insertion_mode (count, key)
605      int count, key;
606 {
607   _rl_keymap = vi_insertion_keymap;
608   _rl_vi_last_key_before_insert = key;
609   return (0);
610 }
611
612 static void
613 _rl_vi_save_insert (up)
614       UNDO_LIST *up;
615 {
616   int len, start, end;
617
618   start = up->start;
619   end = up->end;
620   len = end - start + 1;
621   if (len >= vi_insert_buffer_size)
622     {
623       vi_insert_buffer_size += (len + 32) - (len % 32);
624       vi_insert_buffer = xrealloc (vi_insert_buffer, vi_insert_buffer_size);
625     }
626   strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
627   vi_insert_buffer[len-1] = '\0';
628 }
629     
630 void
631 _rl_vi_done_inserting ()
632 {
633   if (_rl_vi_doing_insert)
634     {
635       rl_end_undo_group ();
636       /* Now, the text between rl_undo_list->next->start and
637          rl_undo_list->next->end is what was inserted while in insert
638          mode.  It gets copied to VI_INSERT_BUFFER because it depends
639          on absolute indices into the line which may change (though they
640          probably will not). */
641       _rl_vi_doing_insert = 0;
642       _rl_vi_save_insert (rl_undo_list->next);
643       vi_continued_command = 1;
644     }
645   else
646     {
647       if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list)
648         _rl_vi_save_insert (rl_undo_list);
649       /* XXX - Other keys probably need to be checked. */
650       else if (_rl_vi_last_key_before_insert == 'C')
651         rl_end_undo_group ();
652       while (_rl_undo_group_level > 0)
653         rl_end_undo_group ();
654       vi_continued_command = 0;
655     }
656 }
657
658 int
659 rl_vi_movement_mode (count, key)
660      int count, key;
661 {
662   if (rl_point > 0)
663     rl_backward (1, key);
664
665   _rl_keymap = vi_movement_keymap;
666   _rl_vi_done_inserting ();
667   return (0);
668 }
669
670 int
671 rl_vi_arg_digit (count, c)
672      int count, c;
673 {
674   if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
675     return (rl_beg_of_line (1, c));
676   else
677     return (rl_digit_argument (count, c));
678 }
679
680 int
681 rl_vi_change_case (count, ignore)
682      int count, ignore;
683 {
684   char c = 0;
685
686   /* Don't try this on an empty line. */
687   if (rl_point >= rl_end)
688     return (0);
689
690   while (count-- && rl_point < rl_end)
691     {
692       if (_rl_uppercase_p (rl_line_buffer[rl_point]))
693         c = _rl_to_lower (rl_line_buffer[rl_point]);
694       else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
695         c = _rl_to_upper (rl_line_buffer[rl_point]);
696       else
697         {
698           /* Just skip over characters neither upper nor lower case. */
699           rl_forward (1, c);
700           continue;
701         }
702
703       /* Vi is kind of strange here. */
704       if (c)
705         {
706           rl_begin_undo_group ();
707           rl_delete (1, c);
708           rl_insert (1, c);
709           rl_end_undo_group ();
710           rl_vi_check ();
711         }
712       else
713         rl_forward (1, c);
714     }
715   return (0);
716 }
717
718 int
719 rl_vi_put (count, key)
720      int count, key;
721 {
722   if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
723     rl_point++;
724
725   rl_yank ();
726   rl_backward (1, key);
727   return (0);
728 }
729
730 int
731 rl_vi_check ()
732 {
733   if (rl_point && rl_point == rl_end)
734     rl_point--;
735   return (0);
736 }
737
738 int
739 rl_vi_column (count, key)
740      int count, key;
741 {
742   if (count > rl_end)
743     rl_end_of_line (1, key);
744   else
745     rl_point = count - 1;
746   return (0);
747 }
748
749 int
750 rl_vi_domove (key, nextkey)
751      int key, *nextkey;
752 {
753   int c, save;
754   int old_end;
755
756   rl_mark = rl_point;
757   c = rl_read_key ();
758   *nextkey = c;
759
760   if (!member (c, vi_motion))
761     {
762       if (_rl_digit_p (c))
763         {
764           save = rl_numeric_arg;
765           rl_numeric_arg = _rl_digit_value (c);
766           rl_digit_loop1 ();
767           rl_numeric_arg *= save;
768           c = rl_read_key ();   /* real command */
769           *nextkey = c;
770         }
771       else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
772         {
773           rl_mark = rl_end;
774           rl_beg_of_line (1, c);
775           _rl_vi_last_motion = c;
776           return (0);
777         }
778       else
779         return (-1);
780     }
781
782   _rl_vi_last_motion = c;
783
784   /* Append a blank character temporarily so that the motion routines
785      work right at the end of the line. */
786   old_end = rl_end;
787   rl_line_buffer[rl_end++] = ' ';
788   rl_line_buffer[rl_end] = '\0';
789
790   _rl_dispatch (c, _rl_keymap);
791
792   /* Remove the blank that we added. */
793   rl_end = old_end;
794   rl_line_buffer[rl_end] = '\0';
795   if (rl_point > rl_end)
796     rl_point = rl_end;
797
798   /* No change in position means the command failed. */
799   if (rl_mark == rl_point)
800     return (-1);
801
802   /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
803      word.  If we are not at the end of the line, and we are on a
804      non-whitespace character, move back one (presumably to whitespace). */
805   if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
806       !whitespace (rl_line_buffer[rl_point]))
807     rl_point--;
808
809   /* If cw or cW, back up to the end of a word, so the behaviour of ce
810      or cE is the actual result.  Brute-force, no subtlety. */
811   if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
812     {
813       /* Don't move farther back than where we started. */
814       while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
815         rl_point--;
816
817       /* Posix.2 says that if cw or cW moves the cursor towards the end of
818          the line, the character under the cursor should be deleted. */
819       if (rl_point == rl_mark)
820         rl_point++;
821       else
822         {
823           /* Move past the end of the word so that the kill doesn't
824              remove the last letter of the previous word.  Only do this
825              if we are not at the end of the line. */
826           if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
827             rl_point++;
828         }
829     }
830
831   if (rl_mark < rl_point)
832     exchange (rl_point, rl_mark);
833
834   return (0);
835 }
836
837 /* A simplified loop for vi. Don't dispatch key at end.
838    Don't recognize minus sign? */
839 static int
840 rl_digit_loop1 ()
841 {
842   int key, c;
843
844   while (1)
845     {
846       rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
847       key = c = rl_read_key ();
848
849       if (_rl_keymap[c].type == ISFUNC &&
850           _rl_keymap[c].function == rl_universal_argument)
851         {
852           rl_numeric_arg *= 4;
853           continue;
854         }
855
856       c = UNMETA (c);
857       if (_rl_digit_p (c))
858         {
859           if (rl_explicit_arg)
860             rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
861           else
862             rl_numeric_arg = _rl_digit_value (c);
863           rl_explicit_arg = 1;
864         }
865       else
866         {
867           rl_clear_message ();
868           rl_stuff_char (key);
869           break;
870         }
871     }
872   return (0);
873 }
874
875 int
876 rl_vi_delete_to (count, key)
877      int count, key;
878 {
879   int c;
880
881   if (_rl_uppercase_p (key))
882     rl_stuff_char ('$');
883   else if (vi_redoing)
884     rl_stuff_char (_rl_vi_last_motion);
885
886   if (rl_vi_domove (key, &c))
887     {
888       ding ();
889       return -1;
890     }
891
892   /* These are the motion commands that do not require adjusting the
893      mark. */
894   if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
895     rl_mark++;
896
897   rl_kill_text (rl_point, rl_mark);
898   return (0);
899 }
900
901 int
902 rl_vi_change_to (count, key)
903      int count, key;
904 {
905   int c, start_pos;
906
907   if (_rl_uppercase_p (key))
908     rl_stuff_char ('$');
909   else if (vi_redoing)
910     rl_stuff_char (_rl_vi_last_motion);
911
912   start_pos = rl_point;
913
914   if (rl_vi_domove (key, &c))
915     {
916       ding ();
917       return -1;
918     }
919
920   /* These are the motion commands that do not require adjusting the
921      mark.  c[wW] are handled by special-case code in rl_vi_domove(),
922      and already leave the mark at the correct location. */
923   if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
924     rl_mark++;
925
926   /* The cursor never moves with c[wW]. */
927   if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
928     rl_point = start_pos;
929
930   if (vi_redoing)
931     {
932       if (vi_insert_buffer && *vi_insert_buffer)
933         rl_begin_undo_group ();
934       rl_delete_text (rl_point, rl_mark);
935       if (vi_insert_buffer && *vi_insert_buffer)
936         {
937           rl_insert_text (vi_insert_buffer);
938           rl_end_undo_group ();
939         }
940     }
941   else
942     {
943       rl_begin_undo_group ();           /* to make the `u' command work */
944       rl_kill_text (rl_point, rl_mark);
945       /* `C' does not save the text inserted for undoing or redoing. */
946       if (_rl_uppercase_p (key) == 0)
947         _rl_vi_doing_insert = 1;
948       _rl_vi_set_last (key, count, rl_arg_sign);
949       rl_vi_insertion_mode (1, key);
950     }
951
952   return (0);
953 }
954
955 int
956 rl_vi_yank_to (count, key)
957      int count, key;
958 {
959   int c, save = rl_point;
960
961   if (_rl_uppercase_p (key))
962     rl_stuff_char ('$');
963
964   if (rl_vi_domove (key, &c))
965     {
966       ding ();
967       return -1;
968     }
969
970   /* These are the motion commands that do not require adjusting the
971      mark. */
972   if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
973     rl_mark++;
974
975   rl_begin_undo_group ();
976   rl_kill_text (rl_point, rl_mark);
977   rl_end_undo_group ();
978   rl_do_undo ();
979   rl_point = save;
980
981   return (0);
982 }
983
984 int
985 rl_vi_delete (count, key)
986      int count, key;
987 {
988   int end;
989
990   if (rl_end == 0)
991     {
992       ding ();
993       return -1;
994     }
995
996   end = rl_point + count;
997
998   if (end >= rl_end)
999     end = rl_end;
1000
1001   rl_kill_text (rl_point, end);
1002   
1003   if (rl_point > 0 && rl_point == rl_end)
1004     rl_backward (1, key);
1005   return (0);
1006 }
1007
1008 int
1009 rl_vi_back_to_indent (count, key)
1010      int count, key;
1011 {
1012   rl_beg_of_line (1, key);
1013   while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1014     rl_point++;
1015   return (0);
1016 }
1017
1018 int
1019 rl_vi_first_print (count, key)
1020      int count, key;
1021 {
1022   return (rl_vi_back_to_indent (1, key));
1023 }
1024
1025 int
1026 rl_vi_char_search (count, key)
1027      int count, key;
1028 {
1029   static char target;
1030   static int orig_dir, dir;
1031
1032   if (key == ';' || key == ',')
1033     dir = key == ';' ? orig_dir : -orig_dir;
1034   else
1035     {
1036       if (vi_redoing)
1037         target = _rl_vi_last_search_char;
1038       else
1039         _rl_vi_last_search_char = target = rl_getc (rl_instream);
1040
1041       switch (key)
1042         {
1043         case 't':
1044           orig_dir = dir = FTO;
1045           break;
1046
1047         case 'T':
1048           orig_dir = dir = BTO;
1049           break;
1050
1051         case 'f':
1052           orig_dir = dir = FFIND;
1053           break;
1054
1055         case 'F':
1056           orig_dir = dir = BFIND;
1057           break;
1058         }
1059     }
1060
1061   return (_rl_char_search_internal (count, dir, target));
1062 }
1063
1064 /* Match brackets */
1065 int
1066 rl_vi_match (ignore, key)
1067      int ignore, key;
1068 {
1069   int count = 1, brack, pos;
1070
1071   pos = rl_point;
1072   if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1073     {
1074       while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1075              rl_point < rl_end - 1)
1076         rl_forward (1, key);
1077
1078       if (brack <= 0)
1079         {
1080           rl_point = pos;
1081           ding ();
1082           return -1;
1083         }
1084     }
1085
1086   pos = rl_point;
1087
1088   if (brack < 0)
1089     {
1090       while (count)
1091         {
1092           if (--pos >= 0)
1093             {
1094               int b = rl_vi_bracktype (rl_line_buffer[pos]);
1095               if (b == -brack)
1096                 count--;
1097               else if (b == brack)
1098                 count++;
1099             }
1100           else
1101             {
1102               ding ();
1103               return -1;
1104             }
1105         }
1106     }
1107   else
1108     {                   /* brack > 0 */
1109       while (count)
1110         {
1111           if (++pos < rl_end)
1112             {
1113               int b = rl_vi_bracktype (rl_line_buffer[pos]);
1114               if (b == -brack)
1115                 count--;
1116               else if (b == brack)
1117                 count++;
1118             }
1119           else
1120             {
1121               ding ();
1122               return -1;
1123             }
1124         }
1125     }
1126   rl_point = pos;
1127   return (0);
1128 }
1129
1130 int
1131 rl_vi_bracktype (c)
1132      int c;
1133 {
1134   switch (c)
1135     {
1136     case '(': return  1;
1137     case ')': return -1;
1138     case '[': return  2;
1139     case ']': return -2;
1140     case '{': return  3;
1141     case '}': return -3;
1142     default:  return  0;
1143     }
1144 }
1145
1146 int
1147 rl_vi_change_char (count, key)
1148      int count, key;
1149 {
1150   int c;
1151
1152   if (vi_redoing)
1153     c = _rl_vi_last_replacement;
1154   else
1155     _rl_vi_last_replacement = c = rl_getc (rl_instream);
1156
1157   if (c == '\033' || c == CTRL ('C'))
1158     return -1;
1159
1160   while (count-- && rl_point < rl_end)
1161     {
1162       rl_begin_undo_group ();
1163
1164       rl_delete (1, c);
1165       rl_insert (1, c);
1166       if (count == 0)
1167         rl_backward (1, c);
1168
1169       rl_end_undo_group ();
1170     }
1171   return (0);
1172 }
1173
1174 int
1175 rl_vi_subst (count, key)
1176      int count, key;
1177 {
1178   rl_begin_undo_group ();
1179
1180   if (_rl_uppercase_p (key))
1181     {
1182       rl_beg_of_line (1, key);
1183       rl_kill_line (1, key);
1184     }
1185   else
1186     rl_delete_text (rl_point, rl_point+count);
1187
1188   rl_end_undo_group ();
1189
1190   _rl_vi_set_last (key, count, rl_arg_sign);
1191
1192   if (vi_redoing)
1193     {
1194       int o = _rl_doing_an_undo;
1195
1196       _rl_doing_an_undo = 1;
1197       if (vi_insert_buffer && *vi_insert_buffer)
1198         rl_insert_text (vi_insert_buffer);
1199       _rl_doing_an_undo = o;
1200     }
1201   else
1202     {
1203       rl_begin_undo_group ();
1204       _rl_vi_doing_insert = 1;
1205       rl_vi_insertion_mode (1, key);
1206     }
1207
1208   return (0);
1209 }
1210
1211 int
1212 rl_vi_overstrike (count, key)
1213      int count, key;
1214 {
1215   int i;
1216
1217   if (_rl_vi_doing_insert == 0)
1218     {
1219       _rl_vi_doing_insert = 1;
1220       rl_begin_undo_group ();
1221     }
1222
1223   for (i = 0; i < count; i++)
1224     {
1225       vi_replace_count++;
1226       rl_begin_undo_group ();
1227
1228       if (rl_point < rl_end)
1229         {
1230           rl_delete (1, key);
1231           rl_insert (1, key);
1232         }
1233       else
1234         rl_insert (1, key);
1235
1236       rl_end_undo_group ();
1237     }
1238   return (0);
1239 }
1240
1241 int
1242 rl_vi_overstrike_delete (count, key)
1243      int count, key;
1244 {
1245   int i, s;
1246
1247   for (i = 0; i < count; i++)
1248     {
1249       if (vi_replace_count == 0)
1250         {
1251           ding ();
1252           break;
1253         }
1254       s = rl_point;
1255
1256       if (rl_do_undo ())
1257         vi_replace_count--;
1258
1259       if (rl_point == s)
1260         rl_backward (1, key);
1261     }
1262
1263   if (vi_replace_count == 0 && _rl_vi_doing_insert)
1264     {
1265       rl_end_undo_group ();
1266       rl_do_undo ();
1267       _rl_vi_doing_insert = 0;
1268     }
1269   return (0);
1270 }
1271
1272 int
1273 rl_vi_replace (count, key)
1274      int count, key;
1275 {
1276   int i;
1277
1278   vi_replace_count = 0;
1279
1280   if (!vi_replace_map)
1281     {
1282       vi_replace_map = rl_make_bare_keymap ();
1283
1284       for (i = ' '; i < KEYMAP_SIZE; i++)
1285         vi_replace_map[i].function = rl_vi_overstrike;
1286
1287       vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1288       vi_replace_map[ESC].function = rl_vi_movement_mode;
1289       vi_replace_map[RETURN].function = rl_newline;
1290       vi_replace_map[NEWLINE].function = rl_newline;
1291
1292       /* If the normal vi insertion keymap has ^H bound to erase, do the
1293          same here.  Probably should remove the assignment to RUBOUT up
1294          there, but I don't think it will make a difference in real life. */
1295       if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1296           vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1297         vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1298
1299     }
1300   _rl_keymap = vi_replace_map;
1301   return (0);
1302 }
1303
1304 #if 0
1305 /* Try to complete the word we are standing on or the word that ends with
1306    the previous character.  A space matches everything.  Word delimiters are
1307    space and ;. */
1308 int
1309 rl_vi_possible_completions()
1310 {
1311   int save_pos = rl_point;
1312
1313   if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1314     {
1315       while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1316              rl_line_buffer[rl_point] != ';')
1317         rl_point++;
1318     }
1319   else if (rl_line_buffer[rl_point - 1] == ';')
1320     {
1321       ding ();
1322       return (0);
1323     }
1324
1325   rl_possible_completions ();
1326   rl_point = save_pos;
1327
1328   return (0);
1329 }
1330 #endif
1331
1332 /* Functions to save and restore marks. */
1333 int
1334 rl_vi_set_mark (count, key)
1335      int count, key;
1336 {
1337   int ch;
1338
1339   ch = rl_read_key ();
1340   if (_rl_lowercase_p (ch) == 0)
1341     {
1342       ding ();
1343       return -1;
1344     }
1345   ch -= 'a';
1346   vi_mark_chars[ch] = rl_point;
1347   return 0;
1348 }
1349
1350 int
1351 rl_vi_goto_mark (count, key)
1352      int count, key;
1353 {
1354   int ch;
1355
1356   ch = rl_read_key ();
1357   if (ch == '`')
1358     {
1359       rl_point = rl_mark;
1360       return 0;
1361     }
1362   else if (_rl_lowercase_p (ch) == 0)
1363     {
1364       ding ();
1365       return -1;
1366     }
1367
1368   ch -= 'a';
1369   if (vi_mark_chars[ch] == -1)
1370     {
1371       ding ();
1372       return -1;
1373     }
1374   rl_point = vi_mark_chars[ch];
1375   return 0;
1376 }
1377
1378 #endif /* VI_MODE */