Imported from ../bash-3.2.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   *nextkey = c;
890
891   if (!member (c, vi_motion))
892     {
893       if (_rl_digit_p (c))
894         {
895           save = rl_numeric_arg;
896           rl_numeric_arg = _rl_digit_value (c);
897           rl_explicit_arg = 1;
898           RL_SETSTATE (RL_STATE_NUMERICARG|RL_STATE_VIMOTION);
899           rl_digit_loop1 ();
900           RL_UNSETSTATE (RL_STATE_VIMOTION);
901           rl_numeric_arg *= save;
902           RL_SETSTATE(RL_STATE_MOREINPUT);
903           c = rl_read_key ();   /* real command */
904           RL_UNSETSTATE(RL_STATE_MOREINPUT);
905           *nextkey = c;
906         }
907       else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
908         {
909           rl_mark = rl_end;
910           rl_beg_of_line (1, c);
911           _rl_vi_last_motion = c;
912           return (0);
913         }
914       else
915         return (-1);
916     }
917
918   _rl_vi_last_motion = c;
919
920   /* Append a blank character temporarily so that the motion routines
921      work right at the end of the line. */
922   old_end = rl_end;
923   rl_line_buffer[rl_end++] = ' ';
924   rl_line_buffer[rl_end] = '\0';
925
926   _rl_dispatch (c, _rl_keymap);
927
928   /* Remove the blank that we added. */
929   rl_end = old_end;
930   rl_line_buffer[rl_end] = '\0';
931   if (rl_point > rl_end)
932     rl_point = rl_end;
933
934   /* No change in position means the command failed. */
935   if (rl_mark == rl_point)
936     return (-1);
937
938   /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
939      word.  If we are not at the end of the line, and we are on a
940      non-whitespace character, move back one (presumably to whitespace). */
941   if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
942       !whitespace (rl_line_buffer[rl_point]))
943     rl_point--;
944
945   /* If cw or cW, back up to the end of a word, so the behaviour of ce
946      or cE is the actual result.  Brute-force, no subtlety. */
947   if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
948     {
949       /* Don't move farther back than where we started. */
950       while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
951         rl_point--;
952
953       /* Posix.2 says that if cw or cW moves the cursor towards the end of
954          the line, the character under the cursor should be deleted. */
955       if (rl_point == rl_mark)
956         rl_point++;
957       else
958         {
959           /* Move past the end of the word so that the kill doesn't
960              remove the last letter of the previous word.  Only do this
961              if we are not at the end of the line. */
962           if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
963             rl_point++;
964         }
965     }
966
967   if (rl_mark < rl_point)
968     SWAP (rl_point, rl_mark);
969
970   return (0);
971 }
972
973 /* Process C as part of the current numeric argument.  Return -1 if the
974    argument should be aborted, 0 if we should not read any more chars, and
975    1 if we should continue to read chars. */
976 static int
977 _rl_vi_arg_dispatch (c)
978      int c;
979 {
980   int key;
981
982   key = c;
983   if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
984     {
985       rl_numeric_arg *= 4;
986       return 1;
987     }
988
989   c = UNMETA (c);
990
991   if (_rl_digit_p (c))
992     {
993       if (rl_explicit_arg)
994         rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
995       else
996         rl_numeric_arg = _rl_digit_value (c);
997       rl_explicit_arg = 1;
998       return 1;
999     }
1000   else
1001     {
1002       rl_clear_message ();
1003       rl_stuff_char (key);
1004       return 0;
1005     }
1006 }
1007
1008 /* A simplified loop for vi. Don't dispatch key at end.
1009    Don't recognize minus sign?
1010    Should this do rl_save_prompt/rl_restore_prompt? */
1011 static int
1012 rl_digit_loop1 ()
1013 {
1014   int c, r;
1015
1016   while (1)
1017     {
1018       if (_rl_arg_overflow ())
1019         return 1;
1020
1021       c = _rl_arg_getchar ();
1022
1023       r = _rl_vi_arg_dispatch (c);
1024       if (r <= 0)
1025         break;
1026     }
1027
1028   RL_UNSETSTATE(RL_STATE_NUMERICARG);
1029   return (0);
1030 }
1031
1032 int
1033 rl_vi_delete_to (count, key)
1034      int count, key;
1035 {
1036   int c;
1037
1038   if (_rl_uppercase_p (key))
1039     rl_stuff_char ('$');
1040   else if (vi_redoing)
1041     rl_stuff_char (_rl_vi_last_motion);
1042
1043   if (rl_vi_domove (key, &c))
1044     {
1045       rl_ding ();
1046       return -1;
1047     }
1048
1049   /* These are the motion commands that do not require adjusting the
1050      mark. */
1051   if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
1052     rl_mark++;
1053
1054   rl_kill_text (rl_point, rl_mark);
1055   return (0);
1056 }
1057
1058 int
1059 rl_vi_change_to (count, key)
1060      int count, key;
1061 {
1062   int c, start_pos;
1063
1064   if (_rl_uppercase_p (key))
1065     rl_stuff_char ('$');
1066   else if (vi_redoing)
1067     rl_stuff_char (_rl_vi_last_motion);
1068
1069   start_pos = rl_point;
1070
1071   if (rl_vi_domove (key, &c))
1072     {
1073       rl_ding ();
1074       return -1;
1075     }
1076
1077   /* These are the motion commands that do not require adjusting the
1078      mark.  c[wW] are handled by special-case code in rl_vi_domove(),
1079      and already leave the mark at the correct location. */
1080   if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
1081     rl_mark++;
1082
1083   /* The cursor never moves with c[wW]. */
1084   if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
1085     rl_point = start_pos;
1086
1087   if (vi_redoing)
1088     {
1089       if (vi_insert_buffer && *vi_insert_buffer)
1090         rl_begin_undo_group ();
1091       rl_delete_text (rl_point, rl_mark);
1092       if (vi_insert_buffer && *vi_insert_buffer)
1093         {
1094           rl_insert_text (vi_insert_buffer);
1095           rl_end_undo_group ();
1096         }
1097     }
1098   else
1099     {
1100       rl_begin_undo_group ();           /* to make the `u' command work */
1101       rl_kill_text (rl_point, rl_mark);
1102       /* `C' does not save the text inserted for undoing or redoing. */
1103       if (_rl_uppercase_p (key) == 0)
1104         _rl_vi_doing_insert = 1;
1105       rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign);
1106     }
1107
1108   return (0);
1109 }
1110
1111 int
1112 rl_vi_yank_to (count, key)
1113      int count, key;
1114 {
1115   int c, save;
1116
1117   save = rl_point;
1118   if (_rl_uppercase_p (key))
1119     rl_stuff_char ('$');
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. */
1129   if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
1130     rl_mark++;
1131
1132   rl_begin_undo_group ();
1133   rl_kill_text (rl_point, rl_mark);
1134   rl_end_undo_group ();
1135   rl_do_undo ();
1136   rl_point = save;
1137
1138   return (0);
1139 }
1140
1141 int
1142 rl_vi_rubout (count, key)
1143      int count, key;
1144 {
1145   int opoint;
1146
1147   if (count < 0)
1148     return (rl_vi_delete (-count, key));
1149
1150   if (rl_point == 0)
1151     {
1152       rl_ding ();
1153       return -1;
1154     }
1155
1156   opoint = rl_point;
1157   if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1158     rl_backward_char (count, key);
1159   else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1160     rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
1161   else
1162     rl_point -= count;
1163
1164   if (rl_point < 0)
1165     rl_point = 0;
1166
1167   rl_kill_text (rl_point, opoint);
1168   
1169   return (0);
1170 }
1171
1172 int
1173 rl_vi_delete (count, key)
1174      int count, key;
1175 {
1176   int end;
1177
1178   if (count < 0)
1179     return (rl_vi_rubout (-count, key));
1180
1181   if (rl_end == 0)
1182     {
1183       rl_ding ();
1184       return -1;
1185     }
1186
1187   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1188     end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
1189   else
1190     end = rl_point + count;
1191
1192   if (end >= rl_end)
1193     end = rl_end;
1194
1195   rl_kill_text (rl_point, end);
1196   
1197   if (rl_point > 0 && rl_point == rl_end)
1198     rl_backward_char (1, key);
1199
1200   return (0);
1201 }
1202
1203 int
1204 rl_vi_back_to_indent (count, key)
1205      int count, key;
1206 {
1207   rl_beg_of_line (1, key);
1208   while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1209     rl_point++;
1210   return (0);
1211 }
1212
1213 int
1214 rl_vi_first_print (count, key)
1215      int count, key;
1216 {
1217   return (rl_vi_back_to_indent (1, key));
1218 }
1219
1220 static int _rl_cs_dir, _rl_cs_orig_dir;
1221
1222 #if defined (READLINE_CALLBACKS)
1223 static int
1224 _rl_vi_callback_char_search (data)
1225      _rl_callback_generic_arg *data;
1226 {
1227 #if defined (HANDLE_MULTIBYTE)
1228   _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1229 #else
1230   RL_SETSTATE(RL_STATE_MOREINPUT);
1231   _rl_vi_last_search_char = rl_read_key ();
1232   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1233 #endif
1234
1235   _rl_callback_func = 0;
1236   _rl_want_redisplay = 1;
1237
1238 #if defined (HANDLE_MULTIBYTE)
1239   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen));
1240 #else
1241   return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char));
1242 #endif  
1243 }
1244 #endif
1245
1246 int
1247 rl_vi_char_search (count, key)
1248      int count, key;
1249 {
1250 #if defined (HANDLE_MULTIBYTE)
1251   static char *target;
1252   static int tlen;
1253 #else
1254   static char target;
1255 #endif
1256
1257   if (key == ';' || key == ',')
1258     _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir;
1259   else
1260     {
1261       switch (key)
1262         {
1263         case 't':
1264           _rl_cs_orig_dir = _rl_cs_dir = FTO;
1265           break;
1266
1267         case 'T':
1268           _rl_cs_orig_dir = _rl_cs_dir = BTO;
1269           break;
1270
1271         case 'f':
1272           _rl_cs_orig_dir = _rl_cs_dir = FFIND;
1273           break;
1274
1275         case 'F':
1276           _rl_cs_orig_dir = _rl_cs_dir = BFIND;
1277           break;
1278         }
1279
1280       if (vi_redoing)
1281         {
1282           /* set target and tlen below */
1283         }
1284 #if defined (READLINE_CALLBACKS)
1285       else if (RL_ISSTATE (RL_STATE_CALLBACK))
1286         {
1287           _rl_callback_data = _rl_callback_data_alloc (count);
1288           _rl_callback_data->i1 = _rl_cs_dir;
1289           _rl_callback_func = _rl_vi_callback_char_search;
1290           return (0);
1291         }
1292 #endif
1293       else
1294         {
1295 #if defined (HANDLE_MULTIBYTE)
1296           _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
1297 #else
1298           RL_SETSTATE(RL_STATE_MOREINPUT);
1299           _rl_vi_last_search_char = rl_read_key ();
1300           RL_UNSETSTATE(RL_STATE_MOREINPUT);
1301 #endif
1302         }
1303     }
1304
1305 #if defined (HANDLE_MULTIBYTE)
1306   target = _rl_vi_last_search_mbchar;
1307   tlen = _rl_vi_last_search_mblen;
1308 #else
1309   target = _rl_vi_last_search_char;
1310 #endif
1311
1312 #if defined (HANDLE_MULTIBYTE)
1313   return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen));
1314 #else
1315   return (_rl_char_search_internal (count, _rl_cs_dir, target));
1316 #endif
1317 }
1318
1319 /* Match brackets */
1320 int
1321 rl_vi_match (ignore, key)
1322      int ignore, key;
1323 {
1324   int count = 1, brack, pos, tmp, pre;
1325
1326   pos = rl_point;
1327   if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1328     {
1329       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1330         {
1331           while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1332             {
1333               pre = rl_point;
1334               rl_forward_char (1, key);
1335               if (pre == rl_point)
1336                 break;
1337             }
1338         }
1339       else
1340         while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1341                 rl_point < rl_end - 1)
1342           rl_forward_char (1, key);
1343
1344       if (brack <= 0)
1345         {
1346           rl_point = pos;
1347           rl_ding ();
1348           return -1;
1349         }
1350     }
1351
1352   pos = rl_point;
1353
1354   if (brack < 0)
1355     {
1356       while (count)
1357         {
1358           tmp = pos;
1359           if (MB_CUR_MAX == 1 || rl_byte_oriented)
1360             pos--;
1361           else
1362             {
1363               pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
1364               if (tmp == pos)
1365                 pos--;
1366             }
1367           if (pos >= 0)
1368             {
1369               int b = rl_vi_bracktype (rl_line_buffer[pos]);
1370               if (b == -brack)
1371                 count--;
1372               else if (b == brack)
1373                 count++;
1374             }
1375           else
1376             {
1377               rl_ding ();
1378               return -1;
1379             }
1380         }
1381     }
1382   else
1383     {                   /* brack > 0 */
1384       while (count)
1385         {
1386           if (MB_CUR_MAX == 1 || rl_byte_oriented)
1387             pos++;
1388           else
1389             pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
1390
1391           if (pos < rl_end)
1392             {
1393               int b = rl_vi_bracktype (rl_line_buffer[pos]);
1394               if (b == -brack)
1395                 count--;
1396               else if (b == brack)
1397                 count++;
1398             }
1399           else
1400             {
1401               rl_ding ();
1402               return -1;
1403             }
1404         }
1405     }
1406   rl_point = pos;
1407   return (0);
1408 }
1409
1410 int
1411 rl_vi_bracktype (c)
1412      int c;
1413 {
1414   switch (c)
1415     {
1416     case '(': return  1;
1417     case ')': return -1;
1418     case '[': return  2;
1419     case ']': return -2;
1420     case '{': return  3;
1421     case '}': return -3;
1422     default:  return  0;
1423     }
1424 }
1425
1426 static int
1427 _rl_vi_change_char (count, c, mb)
1428      int count, c;
1429      char *mb;
1430 {
1431   int p;
1432
1433   if (c == '\033' || c == CTRL ('C'))
1434     return -1;
1435
1436   rl_begin_undo_group ();
1437   while (count-- && rl_point < rl_end)
1438     {
1439       p = rl_point;
1440       rl_vi_delete (1, c);
1441       if (rl_point < p)         /* Did we retreat at EOL? */
1442         rl_point++;
1443 #if defined (HANDLE_MULTIBYTE)
1444       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1445         rl_insert_text (mb);
1446       else
1447 #endif
1448         _rl_insert_char (1, c);
1449     }
1450
1451   /* The cursor shall be left on the last character changed. */
1452   rl_backward_char (1, c);
1453
1454   rl_end_undo_group ();
1455
1456   return (0);
1457 }
1458
1459 static int
1460 _rl_vi_callback_getchar (mb, mlen)
1461      char *mb;
1462      int mlen;
1463 {
1464   int c;
1465
1466   RL_SETSTATE(RL_STATE_MOREINPUT);
1467   c = rl_read_key ();
1468   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1469
1470 #if defined (HANDLE_MULTIBYTE)
1471   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1472     c = _rl_read_mbstring (c, mb, mlen);
1473 #endif
1474
1475   return c;
1476 }
1477
1478 #if defined (READLINE_CALLBACKS)
1479 static int
1480 _rl_vi_callback_change_char (data)
1481      _rl_callback_generic_arg *data;
1482 {
1483   int c;
1484   char mb[MB_LEN_MAX];
1485
1486   _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1487
1488   _rl_callback_func = 0;
1489   _rl_want_redisplay = 1;
1490
1491   return (_rl_vi_change_char (data->count, c, mb));
1492 }
1493 #endif
1494
1495 int
1496 rl_vi_change_char (count, key)
1497      int count, key;
1498 {
1499   int c;
1500   char mb[MB_LEN_MAX];
1501
1502   if (vi_redoing)
1503     {
1504       c = _rl_vi_last_replacement;
1505       mb[0] = c;
1506       mb[1] = '\0';
1507     }
1508 #if defined (READLINE_CALLBACKS)
1509   else if (RL_ISSTATE (RL_STATE_CALLBACK))
1510     {
1511       _rl_callback_data = _rl_callback_data_alloc (count);
1512       _rl_callback_func = _rl_vi_callback_change_char;
1513       return (0);
1514     }
1515 #endif
1516   else
1517     _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX);
1518
1519   return (_rl_vi_change_char (count, c, mb));
1520 }
1521
1522 int
1523 rl_vi_subst (count, key)
1524      int count, key;
1525 {
1526   /* If we are redoing, rl_vi_change_to will stuff the last motion char */
1527   if (vi_redoing == 0)
1528     rl_stuff_char ((key == 'S') ? 'c' : 'l');   /* `S' == `cc', `s' == `cl' */
1529
1530   return (rl_vi_change_to (count, 'c'));
1531 }
1532
1533 int
1534 rl_vi_overstrike (count, key)
1535      int count, key;
1536 {
1537   if (_rl_vi_doing_insert == 0)
1538     {
1539       _rl_vi_doing_insert = 1;
1540       rl_begin_undo_group ();
1541     }
1542
1543   if (count > 0)
1544     {
1545       _rl_overwrite_char (count, key);
1546       vi_replace_count += count;
1547     }
1548
1549   return (0);
1550 }
1551
1552 int
1553 rl_vi_overstrike_delete (count, key)
1554      int count, key;
1555 {
1556   int i, s;
1557
1558   for (i = 0; i < count; i++)
1559     {
1560       if (vi_replace_count == 0)
1561         {
1562           rl_ding ();
1563           break;
1564         }
1565       s = rl_point;
1566
1567       if (rl_do_undo ())
1568         vi_replace_count--;
1569
1570       if (rl_point == s)
1571         rl_backward_char (1, key);
1572     }
1573
1574   if (vi_replace_count == 0 && _rl_vi_doing_insert)
1575     {
1576       rl_end_undo_group ();
1577       rl_do_undo ();
1578       _rl_vi_doing_insert = 0;
1579     }
1580   return (0);
1581 }
1582
1583 int
1584 rl_vi_replace (count, key)
1585      int count, key;
1586 {
1587   int i;
1588
1589   vi_replace_count = 0;
1590
1591   if (!vi_replace_map)
1592     {
1593       vi_replace_map = rl_make_bare_keymap ();
1594
1595       for (i = ' '; i < KEYMAP_SIZE; i++)
1596         vi_replace_map[i].function = rl_vi_overstrike;
1597
1598       vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1599       vi_replace_map[ESC].function = rl_vi_movement_mode;
1600       vi_replace_map[RETURN].function = rl_newline;
1601       vi_replace_map[NEWLINE].function = rl_newline;
1602
1603       /* If the normal vi insertion keymap has ^H bound to erase, do the
1604          same here.  Probably should remove the assignment to RUBOUT up
1605          there, but I don't think it will make a difference in real life. */
1606       if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1607           vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1608         vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1609
1610     }
1611   _rl_keymap = vi_replace_map;
1612   return (0);
1613 }
1614
1615 #if 0
1616 /* Try to complete the word we are standing on or the word that ends with
1617    the previous character.  A space matches everything.  Word delimiters are
1618    space and ;. */
1619 int
1620 rl_vi_possible_completions()
1621 {
1622   int save_pos = rl_point;
1623
1624   if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1625     {
1626       while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1627              rl_line_buffer[rl_point] != ';')
1628         rl_point++;
1629     }
1630   else if (rl_line_buffer[rl_point - 1] == ';')
1631     {
1632       rl_ding ();
1633       return (0);
1634     }
1635
1636   rl_possible_completions ();
1637   rl_point = save_pos;
1638
1639   return (0);
1640 }
1641 #endif
1642
1643 /* Functions to save and restore marks. */
1644 static int
1645 _rl_vi_set_mark ()
1646 {
1647   int ch;
1648
1649   RL_SETSTATE(RL_STATE_MOREINPUT);
1650   ch = rl_read_key ();
1651   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1652
1653   if (ch < 'a' || ch > 'z')
1654     {
1655       rl_ding ();
1656       return -1;
1657     }
1658   ch -= 'a';
1659   vi_mark_chars[ch] = rl_point;
1660   return 0;
1661 }
1662
1663 #if defined (READLINE_CALLBACKS)
1664 static int
1665 _rl_vi_callback_set_mark (data)
1666      _rl_callback_generic_arg *data;
1667 {
1668   _rl_callback_func = 0;
1669   _rl_want_redisplay = 1;
1670
1671   return (_rl_vi_set_mark ());
1672 }
1673 #endif
1674
1675 int
1676 rl_vi_set_mark (count, key)
1677      int count, key;
1678 {
1679 #if defined (READLINE_CALLBACKS)
1680   if (RL_ISSTATE (RL_STATE_CALLBACK))
1681     {
1682       _rl_callback_data = 0;
1683       _rl_callback_func = _rl_vi_callback_set_mark;
1684       return (0);
1685     }
1686 #endif
1687
1688   return (_rl_vi_set_mark ());
1689 }
1690
1691 static int
1692 _rl_vi_goto_mark ()
1693 {
1694   int ch;
1695
1696   RL_SETSTATE(RL_STATE_MOREINPUT);
1697   ch = rl_read_key ();
1698   RL_UNSETSTATE(RL_STATE_MOREINPUT);
1699
1700   if (ch == '`')
1701     {
1702       rl_point = rl_mark;
1703       return 0;
1704     }
1705   else if (ch < 'a' || ch > 'z')
1706     {
1707       rl_ding ();
1708       return -1;
1709     }
1710
1711   ch -= 'a';
1712   if (vi_mark_chars[ch] == -1)
1713     {
1714       rl_ding ();
1715       return -1;
1716     }
1717   rl_point = vi_mark_chars[ch];
1718   return 0;
1719 }
1720
1721 #if defined (READLINE_CALLBACKS)
1722 static int
1723 _rl_vi_callback_goto_mark (data)
1724      _rl_callback_generic_arg *data;
1725 {
1726   _rl_callback_func = 0;
1727   _rl_want_redisplay = 1;
1728
1729   return (_rl_vi_goto_mark ());
1730 }
1731 #endif
1732
1733 int
1734 rl_vi_goto_mark (count, key)
1735      int count, key;
1736 {
1737 #if defined (READLINE_CALLBACKS)
1738   if (RL_ISSTATE (RL_STATE_CALLBACK))
1739     {
1740       _rl_callback_data = 0;
1741       _rl_callback_func = _rl_vi_callback_goto_mark;
1742       return (0);
1743     }
1744 #endif
1745
1746   return (_rl_vi_goto_mark ());
1747 }
1748 #endif /* VI_MODE */