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