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