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