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