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