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