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