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