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