vi_mode.c revision 35486
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, 1989, 1992 Free Software Foundation, Inc.
5
6   This file is part of the GNU Readline Library, a library for
7   reading lines of text with interactive input and history editing.
8
9   The GNU Readline Library is free software; you can redistribute it
10   and/or modify it under the terms of the GNU General Public License
11   as published by the Free Software Foundation; either version 1, or
12   (at your option) any later version.
13
14   The GNU Readline Library is distributed in the hope that it will be
15   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   The GNU General Public License is often shipped with GNU software, and
20   is generally kept in a file called COPYING or LICENSE.  If you do not
21   have a copy of the license, write to the Free Software Foundation,
22   675 Mass Ave, Cambridge, MA 02139, USA. */
23#define READLINE_LIBRARY
24
25/* **************************************************************** */
26/*								    */
27/*			VI Emulation Mode			    */
28/*								    */
29/* **************************************************************** */
30#include "rlconf.h"
31
32#if defined (VI_MODE)
33
34#if defined (HAVE_CONFIG_H)
35#  include <config.h>
36#endif
37
38#include <sys/types.h>
39
40#if defined (HAVE_STDLIB_H)
41#  include <stdlib.h>
42#else
43#  include "ansi_stdlib.h"
44#endif /* HAVE_STDLIB_H */
45
46#if defined (HAVE_UNISTD_H)
47#  include <unistd.h>
48#endif
49
50#include <stdio.h>
51
52/* Some standard library routines. */
53#include "rldefs.h"
54#include "readline.h"
55#include "history.h"
56
57#ifndef _rl_digit_p
58#define _rl_digit_p(c)  ((c) >= '0' && (c) <= '9')
59#endif
60
61#ifndef _rl_digit_value
62#define _rl_digit_value(c) ((c) - '0')
63#endif
64
65#ifndef member
66#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
67#endif
68
69#ifndef isident
70#define isident(c) ((_rl_pure_alphabetic (c) || _rl_digit_p (c) || c == '_'))
71#endif
72
73#ifndef exchange
74#define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0)
75#endif
76
77extern char *xmalloc (), *xrealloc ();
78
79/* Variables imported from readline.c */
80extern int rl_point, rl_end, rl_mark, rl_done;
81extern FILE *rl_instream;
82extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg;
83extern Keymap _rl_keymap;
84extern char *rl_prompt;
85extern char *rl_line_buffer;
86extern int rl_arg_sign;
87
88extern int _rl_doing_an_undo;
89extern int _rl_undo_group_level;
90
91extern void _rl_dispatch ();
92extern int _rl_char_search_internal ();
93
94extern void rl_extend_line_buffer ();
95extern int rl_vi_check ();
96
97/* Non-zero means enter insertion mode. */
98static int _rl_vi_doing_insert;
99
100/* Command keys which do movement for xxx_to commands. */
101static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
102
103/* Keymap used for vi replace characters.  Created dynamically since
104   rarely used. */
105static Keymap vi_replace_map;
106
107/* The number of characters inserted in the last replace operation. */
108static int vi_replace_count;
109
110/* If non-zero, we have text inserted after a c[motion] command that put
111   us implicitly into insert mode.  Some people want this text to be
112   attached to the command so that it is `redoable' with `.'. */
113static int vi_continued_command;
114static char *vi_insert_buffer;
115static int vi_insert_buffer_size;
116
117static int _rl_vi_last_command = 'i';	/* default `.' puts you in insert mode */
118static int _rl_vi_last_repeat = 1;
119static int _rl_vi_last_arg_sign = 1;
120static int _rl_vi_last_motion;
121static int _rl_vi_last_search_char;
122static int _rl_vi_last_replacement;
123
124static int _rl_vi_last_key_before_insert;
125
126static int vi_redoing;
127
128/* Text modification commands.  These are the `redoable' commands. */
129static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
130
131/* Arrays for the saved marks. */
132static int vi_mark_chars[27];
133
134static int rl_digit_loop1 ();
135
136void
137_rl_vi_initialize_line ()
138{
139  register int i;
140
141  for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
142    vi_mark_chars[i] = -1;
143}
144
145void
146_rl_vi_reset_last ()
147{
148  _rl_vi_last_command = 'i';
149  _rl_vi_last_repeat = 1;
150  _rl_vi_last_arg_sign = 1;
151  _rl_vi_last_motion = 0;
152}
153
154void
155_rl_vi_set_last (key, repeat, sign)
156     int key, repeat, sign;
157{
158  _rl_vi_last_command = key;
159  _rl_vi_last_repeat = repeat;
160  _rl_vi_last_arg_sign = sign;
161}
162
163/* Is the command C a VI mode text modification command? */
164int
165_rl_vi_textmod_command (c)
166     int c;
167{
168  return (member (c, vi_textmod));
169}
170
171static void
172_rl_vi_stuff_insert (count)
173     int count;
174{
175  rl_begin_undo_group ();
176  while (count--)
177    rl_insert_text (vi_insert_buffer);
178  rl_end_undo_group ();
179}
180
181/* Bound to `.'.  Called from command mode, so we know that we have to
182   redo a text modification command.  The default for _rl_vi_last_command
183   puts you back into insert mode. */
184int
185rl_vi_redo (count, c)
186     int count, c;
187{
188  if (!rl_explicit_arg)
189    {
190      rl_numeric_arg = _rl_vi_last_repeat;
191      rl_arg_sign = _rl_vi_last_arg_sign;
192    }
193
194  vi_redoing = 1;
195  /* If we're redoing an insert with `i', stuff in the inserted text
196     and do not go into insertion mode. */
197  if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
198    {
199      _rl_vi_stuff_insert (count);
200      /* And back up point over the last character inserted. */
201      if (rl_point > 0)
202	rl_point--;
203    }
204  else
205    _rl_dispatch (_rl_vi_last_command, _rl_keymap);
206  vi_redoing = 0;
207
208  return (0);
209}
210
211/* A placeholder for further expansion. */
212int
213rl_vi_undo (count, key)
214     int count, key;
215{
216  return (rl_undo_command (count, key));
217}
218
219/* Yank the nth arg from the previous line into this line at point. */
220int
221rl_vi_yank_arg (count, key)
222     int count, key;
223{
224  /* Readline thinks that the first word on a line is the 0th, while vi
225     thinks the first word on a line is the 1st.  Compensate. */
226  if (rl_explicit_arg)
227    rl_yank_nth_arg (count - 1, 0);
228  else
229    rl_yank_nth_arg ('$', 0);
230
231  return (0);
232}
233
234/* With an argument, move back that many history lines, else move to the
235   beginning of history. */
236int
237rl_vi_fetch_history (count, c)
238     int count, c;
239{
240  int wanted;
241
242  /* Giving an argument of n means we want the nth command in the history
243     file.  The command number is interpreted the same way that the bash
244     `history' command does it -- that is, giving an argument count of 450
245     to this command would get the command listed as number 450 in the
246     output of `history'. */
247  if (rl_explicit_arg)
248    {
249      wanted = history_base + where_history () - count;
250      if (wanted <= 0)
251        rl_beginning_of_history (0, 0);
252      else
253        rl_get_previous_history (wanted, c);
254    }
255  else
256    rl_beginning_of_history (count, 0);
257  return (0);
258}
259
260/* Search again for the last thing searched for. */
261int
262rl_vi_search_again (count, key)
263     int count, key;
264{
265  switch (key)
266    {
267    case 'n':
268      rl_noninc_reverse_search_again (count, key);
269      break;
270
271    case 'N':
272      rl_noninc_forward_search_again (count, key);
273      break;
274    }
275  return (0);
276}
277
278/* Do a vi style search. */
279int
280rl_vi_search (count, key)
281     int count, key;
282{
283  switch (key)
284    {
285    case '?':
286      rl_noninc_forward_search (count, key);
287      break;
288
289    case '/':
290      rl_noninc_reverse_search (count, key);
291      break;
292
293    default:
294      ding ();
295      break;
296    }
297  return (0);
298}
299
300/* Completion, from vi's point of view. */
301int
302rl_vi_complete (ignore, key)
303     int ignore, key;
304{
305  if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
306    {
307      if (!whitespace (rl_line_buffer[rl_point + 1]))
308	rl_vi_end_word (1, 'E');
309      rl_point++;
310    }
311
312  if (key == '*')
313    rl_complete_internal ('*');	/* Expansion and replacement. */
314  else if (key == '=')
315    rl_complete_internal ('?');	/* List possible completions. */
316  else if (key == '\\')
317    rl_complete_internal (TAB);	/* Standard Readline completion. */
318  else
319    rl_complete (0, key);
320
321  if (key == '*' || key == '\\')
322    {
323      _rl_vi_set_last (key, 1, rl_arg_sign);
324      rl_vi_insertion_mode (1, key);
325    }
326  return (0);
327}
328
329/* Tilde expansion for vi mode. */
330int
331rl_vi_tilde_expand (ignore, key)
332     int ignore, key;
333{
334  rl_tilde_expand (0, key);
335  _rl_vi_set_last (key, 1, rl_arg_sign);	/* XXX */
336  rl_vi_insertion_mode (1, key);
337  return (0);
338}
339
340/* Previous word in vi mode. */
341int
342rl_vi_prev_word (count, key)
343     int count, key;
344{
345  if (count < 0)
346    return (rl_vi_next_word (-count, key));
347
348  if (rl_point == 0)
349    {
350      ding ();
351      return (0);
352    }
353
354  if (_rl_uppercase_p (key))
355    rl_vi_bWord (count);
356  else
357    rl_vi_bword (count);
358
359  return (0);
360}
361
362/* Next word in vi mode. */
363int
364rl_vi_next_word (count, key)
365     int count, key;
366{
367  if (count < 0)
368    return (rl_vi_prev_word (-count, key));
369
370  if (rl_point >= (rl_end - 1))
371    {
372      ding ();
373      return (0);
374    }
375
376  if (_rl_uppercase_p (key))
377    rl_vi_fWord (count);
378  else
379    rl_vi_fword (count);
380  return (0);
381}
382
383/* Move to the end of the ?next? word. */
384int
385rl_vi_end_word (count, key)
386     int count, key;
387{
388  if (count < 0)
389    {
390      ding ();
391      return -1;
392    }
393
394  if (_rl_uppercase_p (key))
395    rl_vi_eWord (count);
396  else
397    rl_vi_eword (count);
398  return (0);
399}
400
401/* Move forward a word the way that 'W' does. */
402int
403rl_vi_fWord (count)
404     int count;
405{
406  while (count-- && rl_point < (rl_end - 1))
407    {
408      /* Skip until whitespace. */
409      while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
410	rl_point++;
411
412      /* Now skip whitespace. */
413      while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
414	rl_point++;
415    }
416  return (0);
417}
418
419int
420rl_vi_bWord (count)
421     int count;
422{
423  while (count-- && rl_point > 0)
424    {
425      /* If we are at the start of a word, move back to whitespace so
426	 we will go back to the start of the previous word. */
427      if (!whitespace (rl_line_buffer[rl_point]) &&
428	  whitespace (rl_line_buffer[rl_point - 1]))
429	rl_point--;
430
431      while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
432	rl_point--;
433
434      if (rl_point > 0)
435	{
436	  while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
437	  rl_point++;
438	}
439    }
440  return (0);
441}
442
443int
444rl_vi_eWord (count)
445     int count;
446{
447  while (count-- && rl_point < (rl_end - 1))
448    {
449      if (!whitespace (rl_line_buffer[rl_point]))
450	rl_point++;
451
452      /* Move to the next non-whitespace character (to the start of the
453	 next word). */
454      while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
455
456      if (rl_point && rl_point < rl_end)
457	{
458	  /* Skip whitespace. */
459	  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
460	    rl_point++;
461
462	  /* Skip until whitespace. */
463	  while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
464	    rl_point++;
465
466	  /* Move back to the last character of the word. */
467	  rl_point--;
468	}
469    }
470  return (0);
471}
472
473int
474rl_vi_fword (count)
475     int count;
476{
477  while (count-- && rl_point < (rl_end - 1))
478    {
479      /* Move to white space (really non-identifer). */
480      if (isident (rl_line_buffer[rl_point]))
481	{
482	  while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
483	    rl_point++;
484	}
485      else /* if (!whitespace (rl_line_buffer[rl_point])) */
486	{
487	  while (!isident (rl_line_buffer[rl_point]) &&
488		 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
489	    rl_point++;
490	}
491
492      /* Move past whitespace. */
493      while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
494	rl_point++;
495    }
496  return (0);
497}
498
499int
500rl_vi_bword (count)
501     int count;
502{
503  while (count-- && rl_point > 0)
504    {
505      int last_is_ident;
506
507      /* If we are at the start of a word, move back to whitespace
508	 so we will go back to the start of the previous word. */
509      if (!whitespace (rl_line_buffer[rl_point]) &&
510	  whitespace (rl_line_buffer[rl_point - 1]))
511	rl_point--;
512
513      /* If this character and the previous character are `opposite', move
514	 back so we don't get messed up by the rl_point++ down there in
515	 the while loop.  Without this code, words like `l;' screw up the
516	 function. */
517      last_is_ident = isident (rl_line_buffer[rl_point - 1]);
518      if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
519	  (!isident (rl_line_buffer[rl_point]) && last_is_ident))
520	rl_point--;
521
522      while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
523	rl_point--;
524
525      if (rl_point > 0)
526	{
527	  if (isident (rl_line_buffer[rl_point]))
528	    while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
529	  else
530	    while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
531		   !whitespace (rl_line_buffer[rl_point]));
532	  rl_point++;
533	}
534    }
535  return (0);
536}
537
538int
539rl_vi_eword (count)
540     int count;
541{
542  while (count-- && rl_point < rl_end - 1)
543    {
544      if (!whitespace (rl_line_buffer[rl_point]))
545	rl_point++;
546
547      while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
548	rl_point++;
549
550      if (rl_point < rl_end)
551	{
552	  if (isident (rl_line_buffer[rl_point]))
553	    while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
554	  else
555	    while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
556		   && !whitespace (rl_line_buffer[rl_point]));
557	}
558      rl_point--;
559    }
560  return (0);
561}
562
563int
564rl_vi_insert_beg (count, key)
565     int count, key;
566{
567  rl_beg_of_line (1, key);
568  rl_vi_insertion_mode (1, key);
569  return (0);
570}
571
572int
573rl_vi_append_mode (count, key)
574     int count, key;
575{
576  if (rl_point < rl_end)
577    rl_point++;
578  rl_vi_insertion_mode (1, key);
579  return (0);
580}
581
582int
583rl_vi_append_eol (count, key)
584     int count, key;
585{
586  rl_end_of_line (1, key);
587  rl_vi_append_mode (1, key);
588  return (0);
589}
590
591/* What to do in the case of C-d. */
592int
593rl_vi_eof_maybe (count, c)
594     int count, c;
595{
596  return (rl_newline (1, '\n'));
597}
598
599/* Insertion mode stuff. */
600
601/* Switching from one mode to the other really just involves
602   switching keymaps. */
603int
604rl_vi_insertion_mode (count, key)
605     int count, key;
606{
607  _rl_keymap = vi_insertion_keymap;
608  _rl_vi_last_key_before_insert = key;
609  return (0);
610}
611
612static void
613_rl_vi_save_insert (up)
614      UNDO_LIST *up;
615{
616  int len, start, end;
617
618  if (up == 0)
619    {
620      if (vi_insert_buffer_size >= 1)
621	vi_insert_buffer[0] = '\0';
622      return;
623    }
624
625  start = up->start;
626  end = up->end;
627  len = end - start + 1;
628  if (len >= vi_insert_buffer_size)
629    {
630      vi_insert_buffer_size += (len + 32) - (len % 32);
631      vi_insert_buffer = xrealloc (vi_insert_buffer, vi_insert_buffer_size);
632    }
633  strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
634  vi_insert_buffer[len-1] = '\0';
635}
636
637void
638_rl_vi_done_inserting ()
639{
640  if (_rl_vi_doing_insert)
641    {
642      rl_end_undo_group ();
643      /* Now, the text between rl_undo_list->next->start and
644	 rl_undo_list->next->end is what was inserted while in insert
645	 mode.  It gets copied to VI_INSERT_BUFFER because it depends
646	 on absolute indices into the line which may change (though they
647	 probably will not). */
648      _rl_vi_doing_insert = 0;
649      _rl_vi_save_insert (rl_undo_list->next);
650      vi_continued_command = 1;
651    }
652  else
653    {
654      if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list)
655        _rl_vi_save_insert (rl_undo_list);
656      /* XXX - Other keys probably need to be checked. */
657      else if (_rl_vi_last_key_before_insert == 'C')
658	rl_end_undo_group ();
659      while (_rl_undo_group_level > 0)
660	rl_end_undo_group ();
661      vi_continued_command = 0;
662    }
663}
664
665int
666rl_vi_movement_mode (count, key)
667     int count, key;
668{
669  if (rl_point > 0)
670    rl_backward (1, key);
671
672  _rl_keymap = vi_movement_keymap;
673  _rl_vi_done_inserting ();
674  return (0);
675}
676
677int
678rl_vi_arg_digit (count, c)
679     int count, c;
680{
681  if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
682    return (rl_beg_of_line (1, c));
683  else
684    return (rl_digit_argument (count, c));
685}
686
687int
688rl_vi_change_case (count, ignore)
689     int count, ignore;
690{
691  char c = 0;
692
693  /* Don't try this on an empty line. */
694  if (rl_point >= rl_end)
695    return (0);
696
697  while (count-- && rl_point < rl_end)
698    {
699      if (_rl_uppercase_p (rl_line_buffer[rl_point]))
700	c = _rl_to_lower (rl_line_buffer[rl_point]);
701      else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
702	c = _rl_to_upper (rl_line_buffer[rl_point]);
703      else
704	{
705	  /* Just skip over characters neither upper nor lower case. */
706	  rl_forward (1, c);
707	  continue;
708	}
709
710      /* Vi is kind of strange here. */
711      if (c)
712	{
713	  rl_begin_undo_group ();
714	  rl_delete (1, c);
715	  rl_insert (1, c);
716	  rl_end_undo_group ();
717	  rl_vi_check ();
718        }
719      else
720	rl_forward (1, c);
721    }
722  return (0);
723}
724
725int
726rl_vi_put (count, key)
727     int count, key;
728{
729  if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
730    rl_point++;
731
732  rl_yank ();
733  rl_backward (1, key);
734  return (0);
735}
736
737int
738rl_vi_check ()
739{
740  if (rl_point && rl_point == rl_end)
741    rl_point--;
742  return (0);
743}
744
745int
746rl_vi_column (count, key)
747     int count, key;
748{
749  if (count > rl_end)
750    rl_end_of_line (1, key);
751  else
752    rl_point = count - 1;
753  return (0);
754}
755
756int
757rl_vi_domove (key, nextkey)
758     int key, *nextkey;
759{
760  int c, save;
761  int old_end;
762
763  rl_mark = rl_point;
764  c = rl_read_key ();
765  *nextkey = c;
766
767  if (!member (c, vi_motion))
768    {
769      if (_rl_digit_p (c))
770	{
771	  save = rl_numeric_arg;
772	  rl_numeric_arg = _rl_digit_value (c);
773	  rl_digit_loop1 ();
774	  rl_numeric_arg *= save;
775	  c = rl_read_key ();	/* real command */
776	  *nextkey = c;
777	}
778      else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
779	{
780	  rl_mark = rl_end;
781	  rl_beg_of_line (1, c);
782	  _rl_vi_last_motion = c;
783	  return (0);
784	}
785      else
786	return (-1);
787    }
788
789  _rl_vi_last_motion = c;
790
791  /* Append a blank character temporarily so that the motion routines
792     work right at the end of the line. */
793  old_end = rl_end;
794  rl_line_buffer[rl_end++] = ' ';
795  rl_line_buffer[rl_end] = '\0';
796
797  _rl_dispatch (c, _rl_keymap);
798
799  /* Remove the blank that we added. */
800  rl_end = old_end;
801  rl_line_buffer[rl_end] = '\0';
802  if (rl_point > rl_end)
803    rl_point = rl_end;
804
805  /* No change in position means the command failed. */
806  if (rl_mark == rl_point)
807    return (-1);
808
809  /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
810     word.  If we are not at the end of the line, and we are on a
811     non-whitespace character, move back one (presumably to whitespace). */
812  if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
813      !whitespace (rl_line_buffer[rl_point]))
814    rl_point--;
815
816  /* If cw or cW, back up to the end of a word, so the behaviour of ce
817     or cE is the actual result.  Brute-force, no subtlety. */
818  if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
819    {
820      /* Don't move farther back than where we started. */
821      while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
822	rl_point--;
823
824      /* Posix.2 says that if cw or cW moves the cursor towards the end of
825	 the line, the character under the cursor should be deleted. */
826      if (rl_point == rl_mark)
827        rl_point++;
828      else
829	{
830	  /* Move past the end of the word so that the kill doesn't
831	     remove the last letter of the previous word.  Only do this
832	     if we are not at the end of the line. */
833	  if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
834	    rl_point++;
835	}
836    }
837
838  if (rl_mark < rl_point)
839    exchange (rl_point, rl_mark);
840
841  return (0);
842}
843
844/* A simplified loop for vi. Don't dispatch key at end.
845   Don't recognize minus sign? */
846static int
847rl_digit_loop1 ()
848{
849  int key, c;
850
851  while (1)
852    {
853      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
854      key = c = rl_read_key ();
855
856      if (_rl_keymap[c].type == ISFUNC &&
857	  _rl_keymap[c].function == rl_universal_argument)
858	{
859	  rl_numeric_arg *= 4;
860	  continue;
861	}
862
863      c = UNMETA (c);
864      if (_rl_digit_p (c))
865	{
866	  if (rl_explicit_arg)
867	    rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
868	  else
869	    rl_numeric_arg = _rl_digit_value (c);
870	  rl_explicit_arg = 1;
871	}
872      else
873	{
874	  rl_clear_message ();
875	  rl_stuff_char (key);
876	  break;
877	}
878    }
879  return (0);
880}
881
882int
883rl_vi_delete_to (count, key)
884     int count, key;
885{
886  int c;
887
888  if (_rl_uppercase_p (key))
889    rl_stuff_char ('$');
890  else if (vi_redoing)
891    rl_stuff_char (_rl_vi_last_motion);
892
893  if (rl_vi_domove (key, &c))
894    {
895      ding ();
896      return -1;
897    }
898
899  /* These are the motion commands that do not require adjusting the
900     mark. */
901  if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
902    rl_mark++;
903
904  rl_kill_text (rl_point, rl_mark);
905  return (0);
906}
907
908int
909rl_vi_change_to (count, key)
910     int count, key;
911{
912  int c, start_pos;
913
914  if (_rl_uppercase_p (key))
915    rl_stuff_char ('$');
916  else if (vi_redoing)
917    rl_stuff_char (_rl_vi_last_motion);
918
919  start_pos = rl_point;
920
921  if (rl_vi_domove (key, &c))
922    {
923      ding ();
924      return -1;
925    }
926
927  /* These are the motion commands that do not require adjusting the
928     mark.  c[wW] are handled by special-case code in rl_vi_domove(),
929     and already leave the mark at the correct location. */
930  if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
931    rl_mark++;
932
933  /* The cursor never moves with c[wW]. */
934  if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
935    rl_point = start_pos;
936
937  if (vi_redoing)
938    {
939      if (vi_insert_buffer && *vi_insert_buffer)
940	rl_begin_undo_group ();
941      rl_delete_text (rl_point, rl_mark);
942      if (vi_insert_buffer && *vi_insert_buffer)
943	{
944	  rl_insert_text (vi_insert_buffer);
945	  rl_end_undo_group ();
946	}
947    }
948  else
949    {
950      rl_begin_undo_group ();		/* to make the `u' command work */
951      rl_kill_text (rl_point, rl_mark);
952      /* `C' does not save the text inserted for undoing or redoing. */
953      if (_rl_uppercase_p (key) == 0)
954        _rl_vi_doing_insert = 1;
955      _rl_vi_set_last (key, count, rl_arg_sign);
956      rl_vi_insertion_mode (1, key);
957    }
958
959  return (0);
960}
961
962int
963rl_vi_yank_to (count, key)
964     int count, key;
965{
966  int c, save = rl_point;
967
968  if (_rl_uppercase_p (key))
969    rl_stuff_char ('$');
970
971  if (rl_vi_domove (key, &c))
972    {
973      ding ();
974      return -1;
975    }
976
977  /* These are the motion commands that do not require adjusting the
978     mark. */
979  if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
980    rl_mark++;
981
982  rl_begin_undo_group ();
983  rl_kill_text (rl_point, rl_mark);
984  rl_end_undo_group ();
985  rl_do_undo ();
986  rl_point = save;
987
988  return (0);
989}
990
991int
992rl_vi_delete (count, key)
993     int count, key;
994{
995  int end;
996
997  if (rl_end == 0)
998    {
999      ding ();
1000      return -1;
1001    }
1002
1003  end = rl_point + count;
1004
1005  if (end >= rl_end)
1006    end = rl_end;
1007
1008  rl_kill_text (rl_point, end);
1009
1010  if (rl_point > 0 && rl_point == rl_end)
1011    rl_backward (1, key);
1012  return (0);
1013}
1014
1015int
1016rl_vi_back_to_indent (count, key)
1017     int count, key;
1018{
1019  rl_beg_of_line (1, key);
1020  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1021    rl_point++;
1022  return (0);
1023}
1024
1025int
1026rl_vi_first_print (count, key)
1027     int count, key;
1028{
1029  return (rl_vi_back_to_indent (1, key));
1030}
1031
1032int
1033rl_vi_char_search (count, key)
1034     int count, key;
1035{
1036  static char target;
1037  static int orig_dir, dir;
1038
1039  if (key == ';' || key == ',')
1040    dir = key == ';' ? orig_dir : -orig_dir;
1041  else
1042    {
1043      if (vi_redoing)
1044	target = _rl_vi_last_search_char;
1045      else
1046	_rl_vi_last_search_char = target = rl_getc (rl_instream);
1047
1048      switch (key)
1049        {
1050        case 't':
1051          orig_dir = dir = FTO;
1052          break;
1053
1054        case 'T':
1055          orig_dir = dir = BTO;
1056          break;
1057
1058        case 'f':
1059          orig_dir = dir = FFIND;
1060          break;
1061
1062        case 'F':
1063          orig_dir = dir = BFIND;
1064          break;
1065        }
1066    }
1067
1068  return (_rl_char_search_internal (count, dir, target));
1069}
1070
1071/* Match brackets */
1072int
1073rl_vi_match (ignore, key)
1074     int ignore, key;
1075{
1076  int count = 1, brack, pos;
1077
1078  pos = rl_point;
1079  if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1080    {
1081      while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1082	     rl_point < rl_end - 1)
1083	rl_forward (1, key);
1084
1085      if (brack <= 0)
1086	{
1087	  rl_point = pos;
1088	  ding ();
1089	  return -1;
1090	}
1091    }
1092
1093  pos = rl_point;
1094
1095  if (brack < 0)
1096    {
1097      while (count)
1098	{
1099	  if (--pos >= 0)
1100	    {
1101	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
1102	      if (b == -brack)
1103		count--;
1104	      else if (b == brack)
1105		count++;
1106	    }
1107	  else
1108	    {
1109	      ding ();
1110	      return -1;
1111	    }
1112	}
1113    }
1114  else
1115    {			/* brack > 0 */
1116      while (count)
1117	{
1118	  if (++pos < rl_end)
1119	    {
1120	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
1121	      if (b == -brack)
1122		count--;
1123	      else if (b == brack)
1124		count++;
1125	    }
1126	  else
1127	    {
1128	      ding ();
1129	      return -1;
1130	    }
1131	}
1132    }
1133  rl_point = pos;
1134  return (0);
1135}
1136
1137int
1138rl_vi_bracktype (c)
1139     int c;
1140{
1141  switch (c)
1142    {
1143    case '(': return  1;
1144    case ')': return -1;
1145    case '[': return  2;
1146    case ']': return -2;
1147    case '{': return  3;
1148    case '}': return -3;
1149    default:  return  0;
1150    }
1151}
1152
1153int
1154rl_vi_change_char (count, key)
1155     int count, key;
1156{
1157  int c;
1158
1159  if (vi_redoing)
1160    c = _rl_vi_last_replacement;
1161  else
1162    _rl_vi_last_replacement = c = rl_getc (rl_instream);
1163
1164  if (c == '\033' || c == CTRL ('C'))
1165    return -1;
1166
1167  while (count-- && rl_point < rl_end)
1168    {
1169      rl_begin_undo_group ();
1170
1171      rl_delete (1, c);
1172      rl_insert (1, c);
1173      if (count == 0)
1174	rl_backward (1, c);
1175
1176      rl_end_undo_group ();
1177    }
1178  return (0);
1179}
1180
1181int
1182rl_vi_subst (count, key)
1183     int count, key;
1184{
1185  rl_begin_undo_group ();
1186
1187  if (_rl_uppercase_p (key))
1188    {
1189      rl_beg_of_line (1, key);
1190      rl_kill_line (1, key);
1191    }
1192  else
1193    rl_delete_text (rl_point, rl_point+count);
1194
1195  rl_end_undo_group ();
1196
1197  _rl_vi_set_last (key, count, rl_arg_sign);
1198
1199  if (vi_redoing)
1200    {
1201      int o = _rl_doing_an_undo;
1202
1203      _rl_doing_an_undo = 1;
1204      if (vi_insert_buffer && *vi_insert_buffer)
1205	rl_insert_text (vi_insert_buffer);
1206      _rl_doing_an_undo = o;
1207    }
1208  else
1209    {
1210      rl_begin_undo_group ();
1211      _rl_vi_doing_insert = 1;
1212      rl_vi_insertion_mode (1, key);
1213    }
1214
1215  return (0);
1216}
1217
1218int
1219rl_vi_overstrike (count, key)
1220     int count, key;
1221{
1222  int i;
1223
1224  if (_rl_vi_doing_insert == 0)
1225    {
1226      _rl_vi_doing_insert = 1;
1227      rl_begin_undo_group ();
1228    }
1229
1230  for (i = 0; i < count; i++)
1231    {
1232      vi_replace_count++;
1233      rl_begin_undo_group ();
1234
1235      if (rl_point < rl_end)
1236	{
1237	  rl_delete (1, key);
1238	  rl_insert (1, key);
1239	}
1240      else
1241	rl_insert (1, key);
1242
1243      rl_end_undo_group ();
1244    }
1245  return (0);
1246}
1247
1248int
1249rl_vi_overstrike_delete (count, key)
1250     int count, key;
1251{
1252  int i, s;
1253
1254  for (i = 0; i < count; i++)
1255    {
1256      if (vi_replace_count == 0)
1257	{
1258	  ding ();
1259	  break;
1260	}
1261      s = rl_point;
1262
1263      if (rl_do_undo ())
1264	vi_replace_count--;
1265
1266      if (rl_point == s)
1267	rl_backward (1, key);
1268    }
1269
1270  if (vi_replace_count == 0 && _rl_vi_doing_insert)
1271    {
1272      rl_end_undo_group ();
1273      rl_do_undo ();
1274      _rl_vi_doing_insert = 0;
1275    }
1276  return (0);
1277}
1278
1279int
1280rl_vi_replace (count, key)
1281     int count, key;
1282{
1283  int i;
1284
1285  vi_replace_count = 0;
1286
1287  if (!vi_replace_map)
1288    {
1289      vi_replace_map = rl_make_bare_keymap ();
1290
1291      for (i = ' '; i < KEYMAP_SIZE; i++)
1292	vi_replace_map[i].function = rl_vi_overstrike;
1293
1294      vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1295      vi_replace_map[ESC].function = rl_vi_movement_mode;
1296      vi_replace_map[RETURN].function = rl_newline;
1297      vi_replace_map[NEWLINE].function = rl_newline;
1298
1299      /* If the normal vi insertion keymap has ^H bound to erase, do the
1300         same here.  Probably should remove the assignment to RUBOUT up
1301         there, but I don't think it will make a difference in real life. */
1302      if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1303	  vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1304	vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1305
1306    }
1307  _rl_keymap = vi_replace_map;
1308  return (0);
1309}
1310
1311#if 0
1312/* Try to complete the word we are standing on or the word that ends with
1313   the previous character.  A space matches everything.  Word delimiters are
1314   space and ;. */
1315int
1316rl_vi_possible_completions()
1317{
1318  int save_pos = rl_point;
1319
1320  if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1321    {
1322      while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1323	     rl_line_buffer[rl_point] != ';')
1324	rl_point++;
1325    }
1326  else if (rl_line_buffer[rl_point - 1] == ';')
1327    {
1328      ding ();
1329      return (0);
1330    }
1331
1332  rl_possible_completions ();
1333  rl_point = save_pos;
1334
1335  return (0);
1336}
1337#endif
1338
1339/* Functions to save and restore marks. */
1340int
1341rl_vi_set_mark (count, key)
1342     int count, key;
1343{
1344  int ch;
1345
1346  ch = rl_read_key ();
1347  if (_rl_lowercase_p (ch) == 0)
1348    {
1349      ding ();
1350      return -1;
1351    }
1352  ch -= 'a';
1353  vi_mark_chars[ch] = rl_point;
1354  return 0;
1355}
1356
1357int
1358rl_vi_goto_mark (count, key)
1359     int count, key;
1360{
1361  int ch;
1362
1363  ch = rl_read_key ();
1364  if (ch == '`')
1365    {
1366      rl_point = rl_mark;
1367      return 0;
1368    }
1369  else if (_rl_lowercase_p (ch) == 0)
1370    {
1371      ding ();
1372      return -1;
1373    }
1374
1375  ch -= 'a';
1376  if (vi_mark_chars[ch] == -1)
1377    {
1378      ding ();
1379      return -1;
1380    }
1381  rl_point = vi_mark_chars[ch];
1382  return 0;
1383}
1384
1385#endif /* VI_MODE */
1386