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