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