Bash-4.3 distribution sources and documentation
[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-2012 Free Software Foundation, Inc.
5
6    This file is part of the GNU Readline Library (Readline), a library
7    for reading lines of text with interactive input and history editing.      
8
9    Readline is free software: you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation, either version 3 of the License, or
12    (at your option) any later version.
13
14    Readline is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with Readline.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
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 _rl_vimotion_cxt *_rl_vimvcxt = 0;
69
70 /* Non-zero means enter insertion mode. */
71 static int _rl_vi_doing_insert;
72
73 /* Command keys which do movement for xxx_to commands. */
74 static const char * const vi_motion = " hl^$0ftFT;,%wbeWBE|`";
75
76 /* Keymap used for vi replace characters.  Created dynamically since
77    rarely used. */
78 static Keymap vi_replace_map;
79
80 /* The number of characters inserted in the last replace operation. */
81 static int vi_replace_count;
82
83 /* If non-zero, we have text inserted after a c[motion] command that put
84    us implicitly into insert mode.  Some people want this text to be
85    attached to the command so that it is `redoable' with `.'. */
86 static int vi_continued_command;
87 static char *vi_insert_buffer;
88 static int vi_insert_buffer_size;
89
90 static int _rl_vi_last_repeat = 1;
91 static int _rl_vi_last_arg_sign = 1;
92 static int _rl_vi_last_motion;
93 #if defined (HANDLE_MULTIBYTE)
94 static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
95 static int _rl_vi_last_search_mblen;
96 #else
97 static int _rl_vi_last_search_char;
98 #endif
99 static int _rl_vi_last_replacement;
100
101 static int _rl_vi_last_key_before_insert;
102
103 static int vi_redoing;
104
105 /* Text modification commands.  These are the `redoable' commands. */
106 static const char * const vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
107
108 /* Arrays for the saved marks. */
109 static int vi_mark_chars['z' - 'a' + 1];
110
111 static void _rl_vi_replace_insert PARAMS((int));
112 static void _rl_vi_save_replace PARAMS((void));
113 static void _rl_vi_stuff_insert PARAMS((int));
114 static void _rl_vi_save_insert PARAMS((UNDO_LIST *));
115
116 static void vi_save_insert_buffer PARAMS ((int, int));
117
118 static void _rl_vi_backup PARAMS((void));
119
120 static int _rl_vi_arg_dispatch PARAMS((int));
121 static int rl_digit_loop1 PARAMS((void));
122
123 static int _rl_vi_set_mark PARAMS((void));
124 static int _rl_vi_goto_mark PARAMS((void));
125
126 static void _rl_vi_append_forward PARAMS((int));
127
128 static int _rl_vi_callback_getchar PARAMS((char *, int));
129
130 #if defined (READLINE_CALLBACKS)
131 static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *));
132 static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *));
133 static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *));
134 static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *));
135 #endif
136
137 static int rl_domove_read_callback PARAMS((_rl_vimotion_cxt *));
138 static int rl_domove_motion_callback PARAMS((_rl_vimotion_cxt *));
139 static int rl_vi_domove_getchar PARAMS((_rl_vimotion_cxt *));
140
141 static int vi_change_dispatch PARAMS((_rl_vimotion_cxt *));
142 static int vi_delete_dispatch PARAMS((_rl_vimotion_cxt *));
143 static int vi_yank_dispatch PARAMS((_rl_vimotion_cxt *));
144
145 static int vidomove_dispatch PARAMS((_rl_vimotion_cxt *));
146
147 void
148 _rl_vi_initialize_line ()
149 {
150   register int i, n;
151
152   n = sizeof (vi_mark_chars) / sizeof (vi_mark_chars[0]);
153   for (i = 0; i < n; i++)
154     vi_mark_chars[i] = -1;
155
156   RL_UNSETSTATE(RL_STATE_VICMDONCE);
157 }
158
159 void
160 _rl_vi_reset_last ()
161 {
162   _rl_vi_last_command = 'i';
163   _rl_vi_last_repeat = 1;
164   _rl_vi_last_arg_sign = 1;
165   _rl_vi_last_motion = 0;
166 }
167
168 void
169 _rl_vi_set_last (key, repeat, sign)
170      int key, repeat, sign;
171 {
172   _rl_vi_last_command = key;
173   _rl_vi_last_repeat = repeat;
174   _rl_vi_last_arg_sign = sign;
175 }
176
177 /* A convenience function that calls _rl_vi_set_last to save the last command
178    information and enters insertion mode. */
179 void
180 rl_vi_start_inserting (key, repeat, sign)
181      int key, repeat, sign;
182 {
183   _rl_vi_set_last (key, repeat, sign);
184   rl_vi_insertion_mode (1, key);
185 }
186
187 /* Is the command C a VI mode text modification command? */
188 int
189 _rl_vi_textmod_command (c)
190      int c;
191 {
192   return (member (c, vi_textmod));
193 }
194
195 static void
196 _rl_vi_replace_insert (count)
197      int count;
198 {
199   int nchars;
200
201   nchars = strlen (vi_insert_buffer);
202
203   rl_begin_undo_group ();
204   while (count--)
205     /* nchars-1 to compensate for _rl_replace_text using `end+1' in call
206        to rl_delete_text */
207     _rl_replace_text (vi_insert_buffer, rl_point, rl_point+nchars-1);
208   rl_end_undo_group ();
209 }
210
211 static void
212 _rl_vi_stuff_insert (count)
213      int count;
214 {
215   rl_begin_undo_group ();
216   while (count--)
217     rl_insert_text (vi_insert_buffer);
218   rl_end_undo_group ();
219 }
220
221 /* Bound to `.'.  Called from command mode, so we know that we have to
222    redo a text modification command.  The default for _rl_vi_last_command
223    puts you back into insert mode. */
224 int
225 rl_vi_redo (count, c)
226      int count, c;
227 {
228   int r;
229
230   if (rl_explicit_arg == 0)
231     {
232       rl_numeric_arg = _rl_vi_last_repeat;
233       rl_arg_sign = _rl_vi_last_arg_sign;
234     }
235
236   r = 0;
237   vi_redoing = 1;
238   /* If we're redoing an insert with `i', stuff in the inserted text
239      and do not go into insertion mode. */
240   if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
241     {
242       _rl_vi_stuff_insert (count);
243       /* And back up point over the last character inserted. */
244       if (rl_point > 0)
245         _rl_vi_backup ();
246     }
247   else if (_rl_vi_last_command == 'R' && vi_insert_buffer && *vi_insert_buffer)
248     {
249       _rl_vi_replace_insert (count);
250       /* And back up point over the last character inserted. */
251       if (rl_point > 0)
252         _rl_vi_backup ();
253     }
254   /* Ditto for redoing an insert with `I', but move to the beginning of the
255      line like the `I' command does. */
256   else if (_rl_vi_last_command == 'I' && vi_insert_buffer && *vi_insert_buffer)
257     {
258       rl_beg_of_line (1, 'I');
259       _rl_vi_stuff_insert (count);
260       if (rl_point > 0)
261         _rl_vi_backup ();
262     }
263   /* Ditto for redoing an insert with `a', but move forward a character first
264      like the `a' command does. */
265   else if (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer)
266     {
267       _rl_vi_append_forward ('a');
268       _rl_vi_stuff_insert (count);
269       if (rl_point > 0)
270         _rl_vi_backup ();
271     }
272   /* Ditto for redoing an insert with `A', but move to the end of the line
273      like the `A' command does. */
274   else if (_rl_vi_last_command == 'A' && vi_insert_buffer && *vi_insert_buffer)
275     {
276       rl_end_of_line (1, 'A');
277       _rl_vi_stuff_insert (count);
278       if (rl_point > 0)
279         _rl_vi_backup ();
280     }
281   else
282     r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
283   vi_redoing = 0;
284
285   return (r);
286 }
287
288 /* A placeholder for further expansion. */
289 int
290 rl_vi_undo (count, key)
291      int count, key;
292 {
293   return (rl_undo_command (count, key));
294 }
295     
296 /* Yank the nth arg from the previous line into this line at point. */
297 int
298 rl_vi_yank_arg (count, key)
299      int count, key;
300 {
301   /* Readline thinks that the first word on a line is the 0th, while vi
302      thinks the first word on a line is the 1st.  Compensate. */
303   if (rl_explicit_arg)
304     rl_yank_nth_arg (count - 1, 0);
305   else
306     rl_yank_nth_arg ('$', 0);
307
308   return (0);
309 }
310
311 /* With an argument, move back that many history lines, else move to the
312    beginning of history. */
313 int
314 rl_vi_fetch_history (count, c)
315      int count, c;
316 {
317   int wanted;
318
319   /* Giving an argument of n means we want the nth command in the history
320      file.  The command number is interpreted the same way that the bash
321      `history' command does it -- that is, giving an argument count of 450
322      to this command would get the command listed as number 450 in the
323      output of `history'. */
324   if (rl_explicit_arg)
325     {
326       wanted = history_base + where_history () - count;
327       if (wanted <= 0)
328         rl_beginning_of_history (0, 0);
329       else
330         rl_get_previous_history (wanted, c);
331     }
332   else
333     rl_beginning_of_history (count, 0);
334   return (0);
335 }
336
337 /* Search again for the last thing searched for. */
338 int
339 rl_vi_search_again (count, key)
340      int count, key;
341 {
342   switch (key)
343     {
344     case 'n':
345       rl_noninc_reverse_search_again (count, key);
346       break;
347
348     case 'N':
349       rl_noninc_forward_search_again (count, key);
350       break;
351     }
352   return (0);
353 }
354
355 /* Do a vi style search. */
356 int
357 rl_vi_search (count, key)
358      int count, key;
359 {
360   switch (key)
361     {
362     case '?':
363       _rl_free_saved_history_line ();
364       rl_noninc_forward_search (count, key);
365       break;
366
367     case '/':
368       _rl_free_saved_history_line ();
369       rl_noninc_reverse_search (count, key);
370       break;
371
372     default:
373       rl_ding ();
374       break;
375     }
376   return (0);
377 }
378
379 /* Completion, from vi's point of view. */
380 int
381 rl_vi_complete (ignore, key)
382      int ignore, key;
383 {
384   if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
385     {
386       if (!whitespace (rl_line_buffer[rl_point + 1]))
387         rl_vi_end_word (1, 'E');
388       rl_point++;
389     }
390
391   if (key == '*')
392     rl_complete_internal ('*'); /* Expansion and replacement. */
393   else if (key == '=')
394     rl_complete_internal ('?'); /* List possible completions. */
395   else if (key == '\\')
396     rl_complete_internal (TAB); /* Standard Readline completion. */
397   else
398     rl_complete (0, key);
399
400   if (key == '*' || key == '\\')
401     rl_vi_start_inserting (key, 1, rl_arg_sign);
402
403   return (0);
404 }
405
406 /* Tilde expansion for vi mode. */
407 int
408 rl_vi_tilde_expand (ignore, key)
409      int ignore, key;
410 {
411   rl_tilde_expand (0, key);
412   rl_vi_start_inserting (key, 1, rl_arg_sign);
413   return (0);
414 }
415
416 /* Previous word in vi mode. */
417 int
418 rl_vi_prev_word (count, key)
419      int count, key;
420 {
421   if (count < 0)
422     return (rl_vi_next_word (-count, key));
423
424   if (rl_point == 0)
425     {
426       rl_ding ();
427       return (0);
428     }
429
430   if (_rl_uppercase_p (key))
431     rl_vi_bWord (count, key);
432   else
433     rl_vi_bword (count, key);
434
435   return (0);
436 }
437
438 /* Next word in vi mode. */
439 int
440 rl_vi_next_word (count, key)
441      int count, key;
442 {
443   if (count < 0)
444     return (rl_vi_prev_word (-count, key));
445
446   if (rl_point >= (rl_end - 1))
447     {
448       rl_ding ();
449       return (0);
450     }
451
452   if (_rl_uppercase_p (key))
453     rl_vi_fWord (count, key);
454   else
455     rl_vi_fword (count, key);
456   return (0);
457 }
458
459 /* Move to the end of the ?next? word. */
460 int
461 rl_vi_end_word (count, key)
462      int count, key;
463 {
464   if (count < 0)
465     {
466       rl_ding ();
467       return -1;
468     }
469
470   if (_rl_uppercase_p (key))
471     rl_vi_eWord (count, key);
472   else
473     rl_vi_eword (count, key);
474   return (0);
475 }
476
477 /* Move forward a word the way that 'W' does. */
478 int
479 rl_vi_fWord (count, ignore)
480      int count, ignore;
481 {
482   while (count-- && rl_point < (rl_end - 1))
483     {
484       /* Skip until whitespace. */
485       while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
486         rl_point++;
487
488       /* Now skip whitespace. */
489       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
490         rl_point++;
491     }
492   return (0);
493 }
494
495 int
496 rl_vi_bWord (count, ignore)
497      int count, ignore;
498 {
499   while (count-- && rl_point > 0)
500     {
501       /* If we are at the start of a word, move back to whitespace so
502          we will go back to the start of the previous word. */
503       if (!whitespace (rl_line_buffer[rl_point]) &&
504           whitespace (rl_line_buffer[rl_point - 1]))
505         rl_point--;
506
507       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
508         rl_point--;
509
510       if (rl_point > 0)
511         {
512           while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
513           rl_point++;
514         }
515     }
516   return (0);
517 }
518
519 int
520 rl_vi_eWord (count, ignore)
521      int count, ignore;
522 {
523   while (count-- && rl_point < (rl_end - 1))
524     {
525       if (!whitespace (rl_line_buffer[rl_point]))
526         rl_point++;
527
528       /* Move to the next non-whitespace character (to the start of the
529          next word). */
530       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
531         rl_point++;
532
533       if (rl_point && rl_point < rl_end)
534         {
535           /* Skip whitespace. */
536           while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
537             rl_point++;
538
539           /* Skip until whitespace. */
540           while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
541             rl_point++;
542
543           /* Move back to the last character of the word. */
544           rl_point--;
545         }
546     }
547   return (0);
548 }
549
550 int
551 rl_vi_fword (count, ignore)
552      int count, ignore;
553 {
554   while (count-- && rl_point < (rl_end - 1))
555     {
556       /* Move to white space (really non-identifer). */
557       if (_rl_isident (rl_line_buffer[rl_point]))
558         {
559           while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
560             rl_point++;
561         }
562       else /* if (!whitespace (rl_line_buffer[rl_point])) */
563         {
564           while (!_rl_isident (rl_line_buffer[rl_point]) &&
565                  !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
566             rl_point++;
567         }
568
569       /* Move past whitespace. */
570       while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
571         rl_point++;
572     }
573   return (0);
574 }
575
576 int
577 rl_vi_bword (count, ignore)
578      int count, ignore;
579 {
580   while (count-- && rl_point > 0)
581     {
582       int last_is_ident;
583
584       /* If we are at the start of a word, move back to whitespace
585          so we will go back to the start of the previous word. */
586       if (!whitespace (rl_line_buffer[rl_point]) &&
587           whitespace (rl_line_buffer[rl_point - 1]))
588         rl_point--;
589
590       /* If this character and the previous character are `opposite', move
591          back so we don't get messed up by the rl_point++ down there in
592          the while loop.  Without this code, words like `l;' screw up the
593          function. */
594       last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]);
595       if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
596           (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident))
597         rl_point--;
598
599       while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
600         rl_point--;
601
602       if (rl_point > 0)
603         {
604           if (_rl_isident (rl_line_buffer[rl_point]))
605             while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point]));
606           else
607             while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
608                    !whitespace (rl_line_buffer[rl_point]));
609           rl_point++;
610         }
611     }
612   return (0);
613 }
614
615 int
616 rl_vi_eword (count, ignore)
617      int count, ignore;
618 {
619   while (count-- && rl_point < rl_end - 1)
620     {
621       if (!whitespace (rl_line_buffer[rl_point]))
622         rl_point++;
623
624       while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
625         rl_point++;
626
627       if (rl_point < rl_end)
628         {
629           if (_rl_isident (rl_line_buffer[rl_point]))
630             while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point]));
631           else
632             while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
633                    && !whitespace (rl_line_buffer[rl_point]));
634         }
635       rl_point--;
636     }
637   return (0);
638 }
639
640 int
641 rl_vi_insert_beg (count, key)
642      int count, key;
643 {
644   rl_beg_of_line (1, key);
645   rl_vi_insert_mode (1, key);
646   return (0);
647 }
648
649 static void
650 _rl_vi_append_forward (key)
651      int key;
652 {
653   int point;
654
655   if (rl_point < rl_end)
656     {
657       if (MB_CUR_MAX == 1 || rl_byte_oriented)
658         rl_point++;
659       else
660         {
661           point = rl_point;
662 #if 0
663           rl_forward_char (1, key);
664 #else
665           rl_point = _rl_forward_char_internal (1);
666 #endif
667           if (point == rl_point)
668             rl_point = rl_end;
669         }
670     }
671 }
672
673 int
674 rl_vi_append_mode (count, key)
675      int count, key;
676 {
677   _rl_vi_append_forward (key);
678   rl_vi_start_inserting (key, 1, rl_arg_sign);
679   return (0);
680 }
681
682 int
683 rl_vi_append_eol (count, key)
684      int count, key;
685 {
686   rl_end_of_line (1, key);
687   rl_vi_append_mode (1, key);
688   return (0);
689 }
690
691 /* What to do in the case of C-d. */
692 int
693 rl_vi_eof_maybe (count, c)
694      int count, c;
695 {
696   return (rl_newline (1, '\n'));
697 }
698
699 /* Insertion mode stuff. */
700
701 /* Switching from one mode to the other really just involves
702    switching keymaps. */
703 int
704 rl_vi_insertion_mode (count, key)
705      int count, key;
706 {
707   _rl_keymap = vi_insertion_keymap;
708   _rl_vi_last_key_before_insert = key;
709   if (_rl_show_mode_in_prompt)
710     _rl_reset_prompt ();
711   return (0);
712 }
713
714 int
715 rl_vi_insert_mode (count, key)
716      int count, key;
717 {
718   rl_vi_start_inserting (key, 1, rl_arg_sign);
719   return (0);
720 }
721
722 static void
723 vi_save_insert_buffer (start, len)
724      int start, len;
725 {
726   /* Same code as _rl_vi_save_insert below */
727   if (len >= vi_insert_buffer_size)
728     {
729       vi_insert_buffer_size += (len + 32) - (len % 32);
730       vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size);
731     }
732   strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
733   vi_insert_buffer[len-1] = '\0';
734 }
735
736 static void
737 _rl_vi_save_replace ()
738 {
739   int len, start, end;
740   UNDO_LIST *up;
741
742   up = rl_undo_list;
743   if (up == 0 || up->what != UNDO_END || vi_replace_count <= 0)
744     {
745       if (vi_insert_buffer_size >= 1)
746         vi_insert_buffer[0] = '\0';
747       return;
748     }
749   /* Let's try it the quick and easy way for now.  This should essentially
750      accommodate every UNDO_INSERT and save the inserted text to
751      vi_insert_buffer */
752   end = rl_point;
753   start = end - vi_replace_count + 1;
754   len = vi_replace_count + 1;
755
756   vi_save_insert_buffer (start, len);  
757 }
758
759 static void
760 _rl_vi_save_insert (up)
761       UNDO_LIST *up;
762 {
763   int len, start, end;
764
765   if (up == 0 || up->what != UNDO_INSERT)
766     {
767       if (vi_insert_buffer_size >= 1)
768         vi_insert_buffer[0] = '\0';
769       return;
770     }
771
772   start = up->start;
773   end = up->end;
774   len = end - start + 1;
775
776   vi_save_insert_buffer (start, len);
777 }
778     
779 void
780 _rl_vi_done_inserting ()
781 {
782   if (_rl_vi_doing_insert)
783     {
784       /* The `C', `s', and `S' commands set this. */
785       rl_end_undo_group ();
786       /* Now, the text between rl_undo_list->next->start and
787          rl_undo_list->next->end is what was inserted while in insert
788          mode.  It gets copied to VI_INSERT_BUFFER because it depends
789          on absolute indices into the line which may change (though they
790          probably will not). */
791       _rl_vi_doing_insert = 0;
792       if (_rl_vi_last_key_before_insert == 'R')
793         _rl_vi_save_replace ();         /* Half the battle */
794       else
795         _rl_vi_save_insert (rl_undo_list->next);
796       vi_continued_command = 1;
797     }
798   else
799     {
800       if (rl_undo_list && (_rl_vi_last_key_before_insert == 'i' ||
801                            _rl_vi_last_key_before_insert == 'a' ||
802                            _rl_vi_last_key_before_insert == 'I' ||
803                            _rl_vi_last_key_before_insert == 'A'))
804         _rl_vi_save_insert (rl_undo_list);
805       /* XXX - Other keys probably need to be checked. */
806       else if (_rl_vi_last_key_before_insert == 'C')
807         rl_end_undo_group ();
808       while (_rl_undo_group_level > 0)
809         rl_end_undo_group ();
810       vi_continued_command = 0;
811     }
812 }
813
814 int
815 rl_vi_movement_mode (count, key)
816      int count, key;
817 {
818   if (rl_point > 0)
819     rl_backward_char (1, key);
820
821   _rl_keymap = vi_movement_keymap;
822   _rl_vi_done_inserting ();
823
824   /* This is how POSIX.2 says `U' should behave -- everything up until the
825      first time you go into command mode should not be undone. */
826   if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0)
827     rl_free_undo_list ();
828
829   if (_rl_show_mode_in_prompt)
830     _rl_reset_prompt ();
831
832   RL_SETSTATE (RL_STATE_VICMDONCE);
833   return (0);
834 }
835
836 int
837 rl_vi_arg_digit (count, c)
838      int count, c;
839 {
840   if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
841     return (rl_beg_of_line (1, c));
842   else
843     return (rl_digit_argument (count, c));
844 }
845
846 /* Change the case of the next COUNT characters. */
847 #if defined (HANDLE_MULTIBYTE)
848 static int
849 _rl_vi_change_mbchar_case (count)
850      int count;
851 {
852   wchar_t wc;
853   char mb[MB_LEN_MAX+1];
854   int mlen, p;
855   size_t m;
856   mbstate_t ps;
857
858   memset (&ps, 0, sizeof (mbstate_t));
859   if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0)
860     count--;
861   while (count-- && rl_point < rl_end)
862     {
863       m = mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
864       if (MB_INVALIDCH (m))
865         wc = (wchar_t)rl_line_buffer[rl_point];
866       else if (MB_NULLWCH (m))
867         wc = L'\0';
868       if (iswupper (wc))
869         wc = towlower (wc);
870       else if (iswlower (wc))
871         wc = towupper (wc);
872       else
873         {
874           /* Just skip over chars neither upper nor lower case */
875           rl_forward_char (1, 0);
876           continue;
877         }
878
879       /* Vi is kind of strange here. */
880       if (wc)
881         {
882           p = rl_point;
883           mlen = wcrtomb (mb, wc, &ps);
884           if (mlen >= 0)
885             mb[mlen] = '\0';
886           rl_begin_undo_group ();
887           rl_vi_delete (1, 0);
888           if (rl_point < p)     /* Did we retreat at EOL? */
889             rl_point++; /* XXX - should we advance more than 1 for mbchar? */
890           rl_insert_text (mb);
891           rl_end_undo_group ();
892           rl_vi_check ();
893         }
894       else
895         rl_forward_char (1, 0);
896     }
897
898   return 0;
899 }
900 #endif
901
902 int
903 rl_vi_change_case (count, ignore)
904      int count, ignore;
905 {
906   int c, p;
907
908   /* Don't try this on an empty line. */
909   if (rl_point >= rl_end)
910     return (0);
911
912   c = 0;
913 #if defined (HANDLE_MULTIBYTE)
914   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
915     return (_rl_vi_change_mbchar_case (count));
916 #endif
917
918   while (count-- && rl_point < rl_end)
919     {
920       if (_rl_uppercase_p (rl_line_buffer[rl_point]))
921         c = _rl_to_lower (rl_line_buffer[rl_point]);
922       else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
923         c = _rl_to_upper (rl_line_buffer[rl_point]);
924       else
925         {
926           /* Just skip over characters neither upper nor lower case. */
927           rl_forward_char (1, c);
928           continue;
929         }
930
931       /* Vi is kind of strange here. */
932       if (c)
933         {
934           p = rl_point;
935           rl_begin_undo_group ();
936           rl_vi_delete (1, c);
937           if (rl_point < p)     /* Did we retreat at EOL? */
938             rl_point++;
939           _rl_insert_char (1, c);
940           rl_end_undo_group ();
941           rl_vi_check ();
942         }
943       else
944         rl_forward_char (1, c);
945     }
946   return (0);
947 }
948
949 int
950 rl_vi_put (count, key)
951      int count, key;
952 {
953   if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
954     rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
955
956   while (count--)
957     rl_yank (1, key);
958
959   rl_backward_char (1, key);
960   return (0);
961 }
962
963 static void
964 _rl_vi_backup ()
965 {
966   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
967     rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
968   else
969     rl_point--;
970 }
971
972 int
973 rl_vi_check ()
974 {
975   if (rl_point && rl_point == rl_end)
976     {
977       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
978         rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
979       else
980         rl_point--;
981     }
982   return (0);
983 }
984
985 int
986 rl_vi_column (count, key)
987      int count, key;
988 {
989   if (count > rl_end)
990     rl_end_of_line (1, key);
991   else
992     rl_point = count - 1;
993   return (0);
994 }
995
996 /* Process C as part of the current numeric argument.  Return -1 if the
997    argument should be aborted, 0 if we should not read any more chars, and
998    1 if we should continue to read chars. */
999 static int
1000 _rl_vi_arg_dispatch (c)
1001      int c;
1002 {
1003   int key;
1004
1005   key = c;
1006   if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
1007     {
1008       rl_numeric_arg *= 4;
1009       return 1;
1010     }
1011
1012   c = UNMETA (c);
1013
1014   if (_rl_digit_p (c))
1015     {
1016       if (rl_explicit_arg)
1017         rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
1018       else
1019         rl_numeric_arg = _rl_digit_value (c);
1020       rl_explicit_arg = 1;
1021       return 1;         /* keep going */
1022     }
1023   else
1024     {
1025       rl_clear_message ();
1026       rl_stuff_char (key);
1027       return 0;         /* done */
1028     }
1029 }
1030
1031 /* A simplified loop for vi. Don't dispatch key at end.
1032    Don't recognize minus sign?
1033    Should this do rl_save_prompt/rl_restore_prompt? */
1034 static int
1035 rl_digit_loop1 ()
1036 {
1037   int c, r;
1038
1039   while (1)
1040     {
1041       if (_rl_arg_overflow ())
1042         return 1;
1043
1044       c = _rl_arg_getchar ();
1045
1046       r = _rl_vi_arg_dispatch (c);
1047       if (r <= 0)
1048         break;
1049     }
1050
1051   RL_UNSETSTATE(RL_STATE_NUMERICARG);
1052   return (0);
1053 }
1054
1055 static void
1056 _rl_mvcxt_init (m, op, key)
1057      _rl_vimotion_cxt *m;
1058      int op, key;
1059 {
1060   m->op = op;
1061   m->state = m->flags = 0;
1062   m->ncxt = 0;
1063   m->numeric_arg = -1;
1064   m->start = rl_point;
1065   m->end = rl_end;
1066   m->key = key;
1067   m->motion = -1;
1068 }
1069
1070 static _rl_vimotion_cxt *
1071 _rl_mvcxt_alloc (op, key)
1072      int op, key;
1073 {
1074   _rl_vimotion_cxt *m;
1075
1076   m = xmalloc (sizeof (_rl_vimotion_cxt));
1077   _rl_mvcxt_init (m, op, key);
1078   return m;
1079 }
1080
1081 static void
1082 _rl_mvcxt_dispose (m)
1083      _rl_vimotion_cxt *m;
1084 {
1085   xfree (m);
1086 }
1087
1088 static int
1089 rl_domove_motion_callback (m)
1090      _rl_vimotion_cxt *m;
1091 {
1092   int c, save, r;
1093   int old_end;
1094
1095   _rl_vi_last_motion = c = m->motion;
1096
1097   /* Append a blank character temporarily so that the motion routines
1098      work right at the end of the line. */
1099   old_end = rl_end;
1100   rl_line_buffer[rl_end++] = ' ';
1101   rl_line_buffer[rl_end] = '\0';
1102
1103   _rl_dispatch (c, _rl_keymap);
1104
1105   /* Remove the blank that we added. */
1106   rl_end = old_end;
1107   rl_line_buffer[rl_end] = '\0';
1108   if (rl_point > rl_end)
1109     rl_point = rl_end;
1110
1111   /* No change in position means the command failed. */
1112   if (rl_mark == rl_point)
1113     return (-1);
1114
1115   /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
1116      word.  If we are not at the end of the line, and we are on a
1117      non-whitespace character, move back one (presumably to whitespace). */
1118   if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
1119       !whitespace (rl_line_buffer[rl_point]))
1120     rl_point--;
1121
1122   /* If cw or cW, back up to the end of a word, so the behaviour of ce
1123      or cE is the actual result.  Brute-force, no subtlety. */
1124   if (m->key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
1125     {
1126       /* Don't move farther back than where we started. */
1127       while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
1128         rl_point--;
1129
1130       /* Posix.2 says that if cw or cW moves the cursor towards the end of
1131          the line, the character under the cursor should be deleted. */
1132       if (rl_point == rl_mark)
1133         rl_point++;
1134       else
1135         {
1136           /* Move past the end of the word so that the kill doesn't
1137              remove the last letter of the previous word.  Only do this
1138              if we are not at the end of the line. */
1139           if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
1140             rl_point++;
1141         }
1142     }
1143
1144   if (rl_mark < rl_point)
1145     SWAP (rl_point, rl_mark);
1146
1147 #if defined (READLINE_CALLBACKS)
1148   if (RL_ISSTATE (RL_STATE_CALLBACK))
1149     (*rl_redisplay_function)();         /* make sure motion is displayed */
1150 #endif
1151
1152   r = vidomove_dispatch (m);
1153
1154   return (r);
1155 }
1156
1157 #define RL_VIMOVENUMARG()       (RL_ISSTATE (RL_STATE_VIMOTION) && RL_ISSTATE (RL_STATE_NUMERICARG))
1158
1159 static int
1160 rl_domove_read_callback (m)
1161      _rl_vimotion_cxt *m;
1162 {
1163   int c, save;
1164
1165   c = m->motion;
1166
1167   if (member (c, vi_motion))
1168     {
1169 #if defined (READLINE_CALLBACKS)
1170       /* If we just read a vi-mode motion command numeric argument, turn off
1171          the `reading numeric arg' state */
1172       if (RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG())
1173         RL_UNSETSTATE (RL_STATE_NUMERICARG);
1174 #endif
1175       /* Should do everything, including turning off RL_STATE_VIMOTION */
1176       return (rl_domove_motion_callback (m));
1177     }
1178   else if (m->key == c && (m->key == 'd' || m->key == 'y' || m->key == 'c'))
1179     {
1180       rl_mark = rl_end;
1181       rl_beg_of_line (1, c);
1182       _rl_vi_last_motion = c;
1183       RL_UNSETSTATE (RL_STATE_VIMOTION);
1184       return (vidomove_dispatch (m));
1185     }
1186 #if defined (READLINE_CALLBACKS)
1187   /* XXX - these need to handle rl_universal_argument bindings */
1188   /* Reading vi motion char continuing numeric argument */
1189   else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_VIMOVENUMARG())
1190     {
1191       return (_rl_vi_arg_dispatch (c));
1192     }
1193   /* Readine vi motion char starting numeric argument */
1194   else if (_rl_digit_p (c) && RL_ISSTATE (RL_STATE_CALLBACK) && RL_ISSTATE (RL_STATE_VIMOTION) && (RL_ISSTATE (RL_STATE_NUMERICARG) == 0))
1195     {
1196       RL_SETSTATE (RL_STATE_NUMERICARG);
1197       return (_rl_vi_arg_dispatch (c));
1198     }
1199 #endif
1200   else if (_rl_digit_p (c))
1201     {
1202       /* This code path taken when not in callback mode */
1203       save = rl_numeric_arg;
1204       rl_numeric_arg = _rl_digit_value (c);
1205       rl_explicit_arg = 1;
1206       RL_SETSTATE (RL_STATE_NUMERICARG);
1207       rl_digit_loop1 ();
1208       rl_numeric_arg *= save;
1209       c = rl_vi_domove_getchar (m);
1210       if (c < 0)
1211         {
1212           m->motion = 0;
1213           return -1;
1214         }
1215       m->motion = c;
1216       return (rl_domove_motion_callback (m));
1217     }
1218   else
1219     {
1220       RL_UNSETSTATE (RL_STATE_VIMOTION);
1221       RL_UNSETSTATE (RL_STATE_NUMERICARG);
1222       return (1);
1223     }
1224 }
1225
1226 static int
1227 rl_vi_domove_getchar (m)
1228      _rl_vimotion_cxt *m;
1229 {
1230   int c;
1231
1232   RL_SETSTATE(RL_STATE_MOREINPUT);
1233   c = rl_read_key ();
1234   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1235
1236   return c;
1237 }
1238
1239 #if defined (READLINE_CALLBACKS)
1240 int
1241 _rl_vi_domove_callback (m)
1242      _rl_vimotion_cxt *m;
1243 {
1244   int c, r;
1245
1246   m->motion = c = rl_vi_domove_getchar (m);
1247   /* XXX - what to do if this returns -1?  Should we return 1 for eof to
1248      callback code? */
1249   r = rl_domove_read_callback (m);
1250
1251   return ((r == 0) ? r : 1);    /* normalize return values */
1252 }
1253 #endif
1254
1255 /* This code path taken when not in callback mode. */
1256 int
1257 rl_vi_domove (x, ignore)
1258      int x, *ignore;
1259 {
1260   int r;
1261   _rl_vimotion_cxt *m;
1262
1263   m = _rl_vimvcxt;
1264   *ignore = m->motion = rl_vi_domove_getchar (m);
1265
1266   if (m->motion < 0)
1267     {
1268       m->motion = 0;
1269       return -1;
1270     }
1271
1272   return (rl_domove_read_callback (m));
1273 }
1274
1275 static int
1276 vi_delete_dispatch (m)
1277      _rl_vimotion_cxt *m;
1278 {
1279   /* These are the motion commands that do not require adjusting the
1280      mark. */
1281   if (((strchr (" l|h^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1282       (rl_mark < rl_end))
1283     rl_mark++;
1284
1285   rl_kill_text (rl_point, rl_mark);
1286   return (0);
1287 }
1288
1289 int
1290 rl_vi_delete_to (count, key)
1291      int count, key;
1292 {
1293   int c, r;
1294
1295   _rl_vimvcxt = _rl_mvcxt_alloc (VIM_DELETE, key);
1296   _rl_vimvcxt->start = rl_point;
1297
1298   rl_mark = rl_point;
1299   if (_rl_uppercase_p (key))
1300     {
1301       _rl_vimvcxt->motion = '$';
1302       r = rl_domove_motion_callback (_rl_vimvcxt);
1303     }
1304   else if (vi_redoing && _rl_vi_last_motion != 'd')     /* `dd' is special */
1305     {
1306       _rl_vimvcxt->motion = _rl_vi_last_motion;
1307       r = rl_domove_motion_callback (_rl_vimvcxt);
1308     }
1309   else if (vi_redoing)          /* handle redoing `dd' here */
1310     {
1311       _rl_vimvcxt->motion = _rl_vi_last_motion;
1312       rl_mark = rl_end;
1313       rl_beg_of_line (1, key);
1314       RL_UNSETSTATE (RL_STATE_VIMOTION);
1315       r = vidomove_dispatch (_rl_vimvcxt);
1316     }
1317 #if defined (READLINE_CALLBACKS)
1318   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1319     {
1320       RL_SETSTATE (RL_STATE_VIMOTION);
1321       return (0);
1322     }
1323 #endif
1324   else
1325     r = rl_vi_domove (key, &c);
1326
1327   if (r < 0)
1328     {
1329       rl_ding ();
1330       r = -1;
1331     }
1332
1333   _rl_mvcxt_dispose (_rl_vimvcxt);
1334   _rl_vimvcxt = 0;
1335
1336   return r;
1337 }
1338
1339 static int
1340 vi_change_dispatch (m)
1341      _rl_vimotion_cxt *m;
1342 {
1343   /* These are the motion commands that do not require adjusting the
1344      mark.  c[wW] are handled by special-case code in rl_vi_domove(),
1345      and already leave the mark at the correct location. */
1346   if (((strchr (" l|hwW^0bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1347       (rl_mark < rl_end))
1348     rl_mark++;
1349
1350   /* The cursor never moves with c[wW]. */
1351   if ((_rl_to_upper (m->motion) == 'W') && rl_point < m->start)
1352     rl_point = m->start;
1353
1354   if (vi_redoing)
1355     {
1356       if (vi_insert_buffer && *vi_insert_buffer)
1357         rl_begin_undo_group ();
1358       rl_delete_text (rl_point, rl_mark);
1359       if (vi_insert_buffer && *vi_insert_buffer)
1360         {
1361           rl_insert_text (vi_insert_buffer);
1362           rl_end_undo_group ();
1363         }
1364     }
1365   else
1366     {
1367       rl_begin_undo_group ();           /* to make the `u' command work */
1368       rl_kill_text (rl_point, rl_mark);
1369       /* `C' does not save the text inserted for undoing or redoing. */
1370       if (_rl_uppercase_p (m->key) == 0)
1371         _rl_vi_doing_insert = 1;
1372       /* XXX -- TODO -- use m->numericarg? */
1373       rl_vi_start_inserting (m->key, rl_numeric_arg, rl_arg_sign);
1374     }
1375
1376   return (0);
1377 }
1378
1379 int
1380 rl_vi_change_to (count, key)
1381      int count, key;
1382 {
1383   int c, r;
1384
1385   _rl_vimvcxt = _rl_mvcxt_alloc (VIM_CHANGE, key);
1386   _rl_vimvcxt->start = rl_point;
1387
1388   rl_mark = rl_point;
1389   if (_rl_uppercase_p (key))
1390     {
1391       _rl_vimvcxt->motion = '$';
1392       r = rl_domove_motion_callback (_rl_vimvcxt);
1393     }
1394   else if (vi_redoing && _rl_vi_last_motion != 'c')     /* `cc' is special */
1395     {
1396       _rl_vimvcxt->motion = _rl_vi_last_motion;
1397       r = rl_domove_motion_callback (_rl_vimvcxt);
1398     }
1399   else if (vi_redoing)          /* handle redoing `cc' here */
1400     {
1401       _rl_vimvcxt->motion = _rl_vi_last_motion;
1402       rl_mark = rl_end;
1403       rl_beg_of_line (1, key);
1404       RL_UNSETSTATE (RL_STATE_VIMOTION);
1405       r = vidomove_dispatch (_rl_vimvcxt);
1406     }
1407 #if defined (READLINE_CALLBACKS)
1408   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1409     {
1410       RL_SETSTATE (RL_STATE_VIMOTION);
1411       return (0);
1412     }
1413 #endif
1414   else
1415     r = rl_vi_domove (key, &c);
1416
1417   if (r < 0)
1418     {
1419       rl_ding ();
1420       r = -1;   /* normalize return value */
1421     }
1422
1423   _rl_mvcxt_dispose (_rl_vimvcxt);
1424   _rl_vimvcxt = 0;
1425
1426   return r;
1427 }
1428
1429 static int
1430 vi_yank_dispatch (m)
1431      _rl_vimotion_cxt *m;
1432 {
1433   /* These are the motion commands that do not require adjusting the
1434      mark. */
1435   if (((strchr (" l|h^0%bBFT`", m->motion) == 0) && (rl_point >= m->start)) &&
1436       (rl_mark < rl_end))
1437     rl_mark++;
1438
1439   rl_begin_undo_group ();
1440   rl_kill_text (rl_point, rl_mark);
1441   rl_end_undo_group ();
1442   rl_do_undo ();
1443   rl_point = m->start;
1444
1445   return (0);
1446 }
1447
1448 int
1449 rl_vi_yank_to (count, key)
1450      int count, key;
1451 {
1452   int c, r;
1453
1454   _rl_vimvcxt = _rl_mvcxt_alloc (VIM_YANK, key);
1455   _rl_vimvcxt->start = rl_point;
1456
1457   rl_mark = rl_point;
1458   if (_rl_uppercase_p (key))
1459     {
1460       _rl_vimvcxt->motion = '$';
1461       r = rl_domove_motion_callback (_rl_vimvcxt);
1462     }
1463   else if (vi_redoing && _rl_vi_last_motion != 'y')     /* `yy' is special */
1464     {
1465       _rl_vimvcxt->motion = _rl_vi_last_motion;
1466       r = rl_domove_motion_callback (_rl_vimvcxt);
1467     }
1468   else if (vi_redoing)                  /* handle redoing `yy' here */
1469     {
1470       _rl_vimvcxt->motion = _rl_vi_last_motion;
1471       rl_mark = rl_end;
1472       rl_beg_of_line (1, key);
1473       RL_UNSETSTATE (RL_STATE_VIMOTION);
1474       r = vidomove_dispatch (_rl_vimvcxt);
1475     }
1476 #if defined (READLINE_CALLBACKS)
1477   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1478     {
1479       RL_SETSTATE (RL_STATE_VIMOTION);
1480       return (0);
1481     }
1482 #endif
1483   else
1484     r = rl_vi_domove (key, &c);
1485
1486   if (r < 0)
1487     {
1488       rl_ding ();
1489       r = -1;
1490     }
1491
1492   _rl_mvcxt_dispose (_rl_vimvcxt);
1493   _rl_vimvcxt = 0;
1494
1495   return r;
1496 }
1497
1498 static int
1499 vidomove_dispatch (m)
1500      _rl_vimotion_cxt *m;
1501 {
1502   int r;
1503
1504   switch (m->op)
1505     {
1506     case VIM_DELETE:
1507       r = vi_delete_dispatch (m);
1508       break;
1509     case VIM_CHANGE:
1510       r = vi_change_dispatch (m);
1511       break;
1512     case VIM_YANK:
1513       r = vi_yank_dispatch (m);
1514       break;
1515     default:
1516       _rl_errmsg ("vidomove_dispatch: unknown operator %d", m->op);
1517       r = 1;
1518       break;
1519     }
1520
1521   RL_UNSETSTATE (RL_STATE_VIMOTION);
1522   return r;
1523 }
1524
1525 int
1526 rl_vi_rubout (count, key)
1527      int count, key;
1528 {
1529   int opoint;
1530
1531   if (count < 0)
1532     return (rl_vi_delete (-count, key));
1533
1534   if (rl_point == 0)
1535     {
1536       rl_ding ();
1537       return -1;
1538     }
1539
1540   opoint = rl_point;
1541   if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1542     rl_backward_char (count, key);
1543   else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1544     rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1545   else
1546     rl_point -= count;
1547
1548   if (rl_point < 0)
1549     rl_point = 0;
1550
1551   rl_kill_text (rl_point, opoint);
1552   
1553   return (0);
1554 }
1555
1556 int
1557 rl_vi_delete (count, key)
1558      int count, key;
1559 {
1560   int end;
1561
1562   if (count < 0)
1563     return (rl_vi_rubout (-count, key));
1564
1565   if (rl_end == 0)
1566     {
1567       rl_ding ();
1568       return -1;
1569     }
1570
1571   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1572     end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1573   else
1574     end = rl_point + count;
1575
1576   if (end >= rl_end)
1577     end = rl_end;
1578
1579   rl_kill_text (rl_point, end);
1580   
1581   if (rl_point > 0 && rl_point == rl_end)
1582     rl_backward_char (1, key);
1583
1584   return (0);
1585 }
1586
1587 int
1588 rl_vi_back_to_indent (count, key)
1589      int count, key;
1590 {
1591   rl_beg_of_line (1, key);
1592   while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1593     rl_point++;
1594   return (0);
1595 }
1596
1597 int
1598 rl_vi_first_print (count, key)
1599      int count, key;
1600 {
1601   return (rl_vi_back_to_indent (1, key));
1602 }
1603
1604 static int _rl_cs_dir, _rl_cs_orig_dir;
1605
1606 #if defined (READLINE_CALLBACKS)
1607 static int
1608 _rl_vi_callback_char_search (data)
1609      _rl_callback_generic_arg *data;
1610 {
1611   int c;
1612 #if defined (HANDLE_MULTIBYTE)
1613   c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1614 #else
1615   RL_SETSTATE(RL_STATE_MOREINPUT);
1616   c = rl_read_key ();
1617   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1618 #endif
1619
1620   if (c <= 0)
1621     return -1;
1622
1623 #if !defined (HANDLE_MULTIBYTE)
1624   _rl_vi_last_search_char = c;
1625 #endif
1626
1627   _rl_callback_func = 0;
1628   _rl_want_redisplay = 1;
1629
1630 #if defined (HANDLE_MULTIBYTE)
1631   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen));
1632 #else
1633   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char));
1634 #endif  
1635 }
1636 #endif
1637
1638 int
1639 rl_vi_char_search (count, key)
1640      int count, key;
1641 {
1642   int c;
1643 #if defined (HANDLE_MULTIBYTE)
1644   static char *target;
1645   static int tlen;
1646 #else
1647   static char target;
1648 #endif
1649
1650   if (key == ';' || key == ',')
1651     {
1652       if (_rl_cs_orig_dir == 0)
1653         return -1;
1654 #if defined (HANDLE_MULTIBYTE)
1655       if (_rl_vi_last_search_mblen == 0)
1656         return -1;
1657 #else
1658       if (_rl_vi_last_search_char == 0)
1659         return -1;
1660 #endif
1661       _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir;
1662     }
1663   else
1664     {
1665       switch (key)
1666         {
1667         case 't':
1668           _rl_cs_orig_dir = _rl_cs_dir = FTO;
1669           break;
1670
1671         case 'T':
1672           _rl_cs_orig_dir = _rl_cs_dir = BTO;
1673           break;
1674
1675         case 'f':
1676           _rl_cs_orig_dir = _rl_cs_dir = FFIND;
1677           break;
1678
1679         case 'F':
1680           _rl_cs_orig_dir = _rl_cs_dir = BFIND;
1681           break;
1682         }
1683
1684       if (vi_redoing)
1685         {
1686           /* set target and tlen below */
1687         }
1688 #if defined (READLINE_CALLBACKS)
1689       else if (RL_ISSTATE (RL_STATE_CALLBACK))
1690         {
1691           _rl_callback_data = _rl_callback_data_alloc (count);
1692           _rl_callback_data->i1 = _rl_cs_dir;
1693           _rl_callback_func = _rl_vi_callback_char_search;
1694           return (0);
1695         }
1696 #endif
1697       else
1698         {
1699 #if defined (HANDLE_MULTIBYTE)
1700           c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1701           if (c <= 0)
1702             return -1;
1703           _rl_vi_last_search_mblen = c;
1704 #else
1705           RL_SETSTATE(RL_STATE_MOREINPUT);
1706           c = rl_read_key ();
1707           RL_UNSETSTATE(RL_STATE_MOREINPUT);
1708           if (c < 0)
1709             return -1;
1710           _rl_vi_last_search_char = c;
1711 #endif
1712         }
1713     }
1714
1715 #if defined (HANDLE_MULTIBYTE)
1716   target = _rl_vi_last_search_mbchar;
1717   tlen = _rl_vi_last_search_mblen;
1718 #else
1719   target = _rl_vi_last_search_char;
1720 #endif
1721
1722 #if defined (HANDLE_MULTIBYTE)
1723   return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen));
1724 #else
1725   return (_rl_char_search_internal (count, _rl_cs_dir, target));
1726 #endif
1727 }
1728
1729 /* Match brackets */
1730 int
1731 rl_vi_match (ignore, key)
1732      int ignore, key;
1733 {
1734   int count = 1, brack, pos, tmp, pre;
1735
1736   pos = rl_point;
1737   if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1738     {
1739       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1740         {
1741           while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1742             {
1743               pre = rl_point;
1744               rl_forward_char (1, key);
1745               if (pre == rl_point)
1746                 break;
1747             }
1748         }
1749       else
1750         while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1751                 rl_point < rl_end - 1)
1752           rl_forward_char (1, key);
1753
1754       if (brack <= 0)
1755         {
1756           rl_point = pos;
1757           rl_ding ();
1758           return -1;
1759         }
1760     }
1761
1762   pos = rl_point;
1763
1764   if (brack < 0)
1765     {
1766       while (count)
1767         {
1768           tmp = pos;
1769           if (MB_CUR_MAX == 1 || rl_byte_oriented)
1770             pos--;
1771           else
1772             {
1773               pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1774               if (tmp == pos)
1775                 pos--;
1776             }
1777           if (pos >= 0)
1778             {
1779               int b = rl_vi_bracktype (rl_line_buffer[pos]);
1780               if (b == -brack)
1781                 count--;
1782               else if (b == brack)
1783                 count++;
1784             }
1785           else
1786             {
1787               rl_ding ();
1788               return -1;
1789             }
1790         }
1791     }
1792   else
1793     {                   /* brack > 0 */
1794       while (count)
1795         {
1796           if (MB_CUR_MAX == 1 || rl_byte_oriented)
1797             pos++;
1798           else
1799             pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
1800
1801           if (pos < rl_end)
1802             {
1803               int b = rl_vi_bracktype (rl_line_buffer[pos]);
1804               if (b == -brack)
1805                 count--;
1806               else if (b == brack)
1807                 count++;
1808             }
1809           else
1810             {
1811               rl_ding ();
1812               return -1;
1813             }
1814         }
1815     }
1816   rl_point = pos;
1817   return (0);
1818 }
1819
1820 int
1821 rl_vi_bracktype (c)
1822      int c;
1823 {
1824   switch (c)
1825     {
1826     case '(': return  1;
1827     case ')': return -1;
1828     case '[': return  2;
1829     case ']': return -2;
1830     case '{': return  3;
1831     case '}': return -3;
1832     default:  return  0;
1833     }
1834 }
1835
1836 static int
1837 _rl_vi_change_char (count, c, mb)
1838      int count, c;
1839      char *mb;
1840 {
1841   int p;
1842
1843   if (c == '\033' || c == CTRL ('C'))
1844     return -1;
1845
1846   rl_begin_undo_group ();
1847   while (count-- && rl_point < rl_end)
1848     {
1849       p = rl_point;
1850       rl_vi_delete (1, c);
1851       if (rl_point < p)         /* Did we retreat at EOL? */
1852         rl_point++;
1853 #if defined (HANDLE_MULTIBYTE)
1854       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1855         rl_insert_text (mb);
1856       else
1857 #endif
1858         _rl_insert_char (1, c);
1859     }
1860
1861   /* The cursor shall be left on the last character changed. */
1862   rl_backward_char (1, c);
1863
1864   rl_end_undo_group ();
1865
1866   return (0);
1867 }
1868
1869 static int
1870 _rl_vi_callback_getchar (mb, mlen)
1871      char *mb;
1872      int mlen;
1873 {
1874   int c;
1875
1876   RL_SETSTATE(RL_STATE_MOREINPUT);
1877   c = rl_read_key ();
1878   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1879
1880   if (c < 0)
1881     return -1;
1882
1883 #if defined (HANDLE_MULTIBYTE)
1884   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1885     c = _rl_read_mbstring (c, mb, mlen);
1886 #endif
1887
1888   return c;
1889 }
1890
1891 #if defined (READLINE_CALLBACKS)
1892 static int
1893 _rl_vi_callback_change_char (data)
1894      _rl_callback_generic_arg *data;
1895 {
1896   int c;
1897   char mb[MB_LEN_MAX];
1898
1899   _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1900
1901   if (c < 0)
1902     return -1;
1903
1904   _rl_callback_func = 0;
1905   _rl_want_redisplay = 1;
1906
1907   return (_rl_vi_change_char (data->count, c, mb));
1908 }
1909 #endif
1910
1911 int
1912 rl_vi_change_char (count, key)
1913      int count, key;
1914 {
1915   int c;
1916   char mb[MB_LEN_MAX];
1917
1918   if (vi_redoing)
1919     {
1920       c = _rl_vi_last_replacement;
1921       mb[0] = c;
1922       mb[1] = '\0';
1923     }
1924 #if defined (READLINE_CALLBACKS)
1925   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1926     {
1927       _rl_callback_data = _rl_callback_data_alloc (count);
1928       _rl_callback_func = _rl_vi_callback_change_char;
1929       return (0);
1930     }
1931 #endif
1932   else
1933     _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1934
1935   if (c < 0)
1936     return -1;
1937
1938   return (_rl_vi_change_char (count, c, mb));
1939 }
1940
1941 int
1942 rl_vi_subst (count, key)
1943      int count, key;
1944 {
1945   /* If we are redoing, rl_vi_change_to will stuff the last motion char */
1946   if (vi_redoing == 0)
1947     rl_stuff_char ((key == 'S') ? 'c' : 'l');   /* `S' == `cc', `s' == `cl' */
1948
1949   return (rl_vi_change_to (count, 'c'));
1950 }
1951
1952 int
1953 rl_vi_overstrike (count, key)
1954      int count, key;
1955 {
1956   if (_rl_vi_doing_insert == 0)
1957     {
1958       _rl_vi_doing_insert = 1;
1959       rl_begin_undo_group ();
1960     }
1961
1962   if (count > 0)
1963     {
1964       _rl_overwrite_char (count, key);
1965       vi_replace_count += count;
1966     }
1967
1968   return (0);
1969 }
1970
1971 int
1972 rl_vi_overstrike_delete (count, key)
1973      int count, key;
1974 {
1975   int i, s;
1976
1977   for (i = 0; i < count; i++)
1978     {
1979       if (vi_replace_count == 0)
1980         {
1981           rl_ding ();
1982           break;
1983         }
1984       s = rl_point;
1985
1986       if (rl_do_undo ())
1987         vi_replace_count--;
1988
1989       if (rl_point == s)
1990         rl_backward_char (1, key);
1991     }
1992
1993   if (vi_replace_count == 0 && _rl_vi_doing_insert)
1994     {
1995       rl_end_undo_group ();
1996       rl_do_undo ();
1997       _rl_vi_doing_insert = 0;
1998     }
1999   return (0);
2000 }
2001
2002 int
2003 rl_vi_replace (count, key)
2004      int count, key;
2005 {
2006   int i;
2007
2008   vi_replace_count = 0;
2009
2010   if (vi_replace_map == 0)
2011     {
2012       vi_replace_map = rl_make_bare_keymap ();
2013
2014       for (i = 0; i < ' '; i++)
2015         if (vi_insertion_keymap[i].type == ISFUNC)
2016           vi_replace_map[i].function = vi_insertion_keymap[i].function;
2017
2018       for (i = ' '; i < KEYMAP_SIZE; i++)
2019         vi_replace_map[i].function = rl_vi_overstrike;
2020
2021       vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
2022
2023       /* Make sure these are what we want. */
2024       vi_replace_map[ESC].function = rl_vi_movement_mode;
2025       vi_replace_map[RETURN].function = rl_newline;
2026       vi_replace_map[NEWLINE].function = rl_newline;
2027
2028       /* If the normal vi insertion keymap has ^H bound to erase, do the
2029          same here.  Probably should remove the assignment to RUBOUT up
2030          there, but I don't think it will make a difference in real life. */
2031       if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
2032           vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
2033         vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
2034
2035     }
2036
2037   rl_vi_start_inserting (key, 1, rl_arg_sign);
2038
2039   _rl_vi_last_key_before_insert = key;
2040   _rl_keymap = vi_replace_map;
2041
2042   return (0);
2043 }
2044
2045 #if 0
2046 /* Try to complete the word we are standing on or the word that ends with
2047    the previous character.  A space matches everything.  Word delimiters are
2048    space and ;. */
2049 int
2050 rl_vi_possible_completions()
2051 {
2052   int save_pos = rl_point;
2053
2054   if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
2055     {
2056       while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
2057              rl_line_buffer[rl_point] != ';')
2058         rl_point++;
2059     }
2060   else if (rl_line_buffer[rl_point - 1] == ';')
2061     {
2062       rl_ding ();
2063       return (0);
2064     }
2065
2066   rl_possible_completions ();
2067   rl_point = save_pos;
2068
2069   return (0);
2070 }
2071 #endif
2072
2073 /* Functions to save and restore marks. */
2074 static int
2075 _rl_vi_set_mark ()
2076 {
2077   int ch;
2078
2079   RL_SETSTATE(RL_STATE_MOREINPUT);
2080   ch = rl_read_key ();
2081   RL_UNSETSTATE(RL_STATE_MOREINPUT);
2082
2083   if (ch < 0 || ch < 'a' || ch > 'z')   /* make test against 0 explicit */
2084     {
2085       rl_ding ();
2086       return -1;
2087     }
2088   ch -= 'a';
2089   vi_mark_chars[ch] = rl_point;
2090   return 0;
2091 }
2092
2093 #if defined (READLINE_CALLBACKS)
2094 static int
2095 _rl_vi_callback_set_mark (data)
2096      _rl_callback_generic_arg *data;
2097 {
2098   _rl_callback_func = 0;
2099   _rl_want_redisplay = 1;
2100
2101   return (_rl_vi_set_mark ());
2102 }
2103 #endif
2104
2105 int
2106 rl_vi_set_mark (count, key)
2107      int count, key;
2108 {
2109 #if defined (READLINE_CALLBACKS)
2110   if (RL_ISSTATE (RL_STATE_CALLBACK))
2111     {
2112       _rl_callback_data = 0;
2113       _rl_callback_func = _rl_vi_callback_set_mark;
2114       return (0);
2115     }
2116 #endif
2117
2118   return (_rl_vi_set_mark ());
2119 }
2120
2121 static int
2122 _rl_vi_goto_mark ()
2123 {
2124   int ch;
2125
2126   RL_SETSTATE(RL_STATE_MOREINPUT);
2127   ch = rl_read_key ();
2128   RL_UNSETSTATE(RL_STATE_MOREINPUT);
2129
2130   if (ch == '`')
2131     {
2132       rl_point = rl_mark;
2133       return 0;
2134     }
2135   else if (ch < 0 || ch < 'a' || ch > 'z')      /* make test against 0 explicit */
2136     {
2137       rl_ding ();
2138       return -1;
2139     }
2140
2141   ch -= 'a';
2142   if (vi_mark_chars[ch] == -1)
2143     {
2144       rl_ding ();
2145       return -1;
2146     }
2147   rl_point = vi_mark_chars[ch];
2148   return 0;
2149 }
2150
2151 #if defined (READLINE_CALLBACKS)
2152 static int
2153 _rl_vi_callback_goto_mark (data)
2154      _rl_callback_generic_arg *data;
2155 {
2156   _rl_callback_func = 0;
2157   _rl_want_redisplay = 1;
2158
2159   return (_rl_vi_goto_mark ());
2160 }
2161 #endif
2162
2163 int
2164 rl_vi_goto_mark (count, key)
2165      int count, key;
2166 {
2167 #if defined (READLINE_CALLBACKS)
2168   if (RL_ISSTATE (RL_STATE_CALLBACK))
2169     {
2170       _rl_callback_data = 0;
2171       _rl_callback_func = _rl_vi_callback_goto_mark;
2172       return (0);
2173     }
2174 #endif
2175
2176   return (_rl_vi_goto_mark ());
2177 }
2178 #endif /* VI_MODE */