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