vi_mode.c revision 21308
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  start = up->start;
619  end = up->end;
620  len = end - start + 1;
621  if (len >= vi_insert_buffer_size)
622    {
623      vi_insert_buffer_size += (len + 32) - (len % 32);
624      vi_insert_buffer = xrealloc (vi_insert_buffer, vi_insert_buffer_size);
625    }
626  strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
627  vi_insert_buffer[len-1] = '\0';
628}
629
630void
631_rl_vi_done_inserting ()
632{
633  if (_rl_vi_doing_insert)
634    {
635      rl_end_undo_group ();
636      /* Now, the text between rl_undo_list->next->start and
637	 rl_undo_list->next->end is what was inserted while in insert
638	 mode.  It gets copied to VI_INSERT_BUFFER because it depends
639	 on absolute indices into the line which may change (though they
640	 probably will not). */
641      _rl_vi_doing_insert = 0;
642      _rl_vi_save_insert (rl_undo_list->next);
643      vi_continued_command = 1;
644    }
645  else
646    {
647      if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list)
648        _rl_vi_save_insert (rl_undo_list);
649      /* XXX - Other keys probably need to be checked. */
650      else if (_rl_vi_last_key_before_insert == 'C')
651	rl_end_undo_group ();
652      while (_rl_undo_group_level > 0)
653	rl_end_undo_group ();
654      vi_continued_command = 0;
655    }
656}
657
658int
659rl_vi_movement_mode (count, key)
660     int count, key;
661{
662  if (rl_point > 0)
663    rl_backward (1, key);
664
665  _rl_keymap = vi_movement_keymap;
666  _rl_vi_done_inserting ();
667  return (0);
668}
669
670int
671rl_vi_arg_digit (count, c)
672     int count, c;
673{
674  if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
675    return (rl_beg_of_line (1, c));
676  else
677    return (rl_digit_argument (count, c));
678}
679
680int
681rl_vi_change_case (count, ignore)
682     int count, ignore;
683{
684  char c = 0;
685
686  /* Don't try this on an empty line. */
687  if (rl_point >= rl_end)
688    return (0);
689
690  while (count-- && rl_point < rl_end)
691    {
692      if (_rl_uppercase_p (rl_line_buffer[rl_point]))
693	c = _rl_to_lower (rl_line_buffer[rl_point]);
694      else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
695	c = _rl_to_upper (rl_line_buffer[rl_point]);
696      else
697	{
698	  /* Just skip over characters neither upper nor lower case. */
699	  rl_forward (1, c);
700	  continue;
701	}
702
703      /* Vi is kind of strange here. */
704      if (c)
705	{
706	  rl_begin_undo_group ();
707	  rl_delete (1, c);
708	  rl_insert (1, c);
709	  rl_end_undo_group ();
710	  rl_vi_check ();
711        }
712      else
713	rl_forward (1, c);
714    }
715  return (0);
716}
717
718int
719rl_vi_put (count, key)
720     int count, key;
721{
722  if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
723    rl_point++;
724
725  rl_yank ();
726  rl_backward (1, key);
727  return (0);
728}
729
730int
731rl_vi_check ()
732{
733  if (rl_point && rl_point == rl_end)
734    rl_point--;
735  return (0);
736}
737
738int
739rl_vi_column (count, key)
740     int count, key;
741{
742  if (count > rl_end)
743    rl_end_of_line (1, key);
744  else
745    rl_point = count - 1;
746  return (0);
747}
748
749int
750rl_vi_domove (key, nextkey)
751     int key, *nextkey;
752{
753  int c, save;
754  int old_end;
755
756  rl_mark = rl_point;
757  c = rl_read_key ();
758  *nextkey = c;
759
760  if (!member (c, vi_motion))
761    {
762      if (_rl_digit_p (c))
763	{
764	  save = rl_numeric_arg;
765	  rl_numeric_arg = _rl_digit_value (c);
766	  rl_digit_loop1 ();
767	  rl_numeric_arg *= save;
768	  c = rl_read_key ();	/* real command */
769	  *nextkey = c;
770	}
771      else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
772	{
773	  rl_mark = rl_end;
774	  rl_beg_of_line (1, c);
775	  _rl_vi_last_motion = c;
776	  return (0);
777	}
778      else
779	return (-1);
780    }
781
782  _rl_vi_last_motion = c;
783
784  /* Append a blank character temporarily so that the motion routines
785     work right at the end of the line. */
786  old_end = rl_end;
787  rl_line_buffer[rl_end++] = ' ';
788  rl_line_buffer[rl_end] = '\0';
789
790  _rl_dispatch (c, _rl_keymap);
791
792  /* Remove the blank that we added. */
793  rl_end = old_end;
794  rl_line_buffer[rl_end] = '\0';
795  if (rl_point > rl_end)
796    rl_point = rl_end;
797
798  /* No change in position means the command failed. */
799  if (rl_mark == rl_point)
800    return (-1);
801
802  /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
803     word.  If we are not at the end of the line, and we are on a
804     non-whitespace character, move back one (presumably to whitespace). */
805  if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
806      !whitespace (rl_line_buffer[rl_point]))
807    rl_point--;
808
809  /* If cw or cW, back up to the end of a word, so the behaviour of ce
810     or cE is the actual result.  Brute-force, no subtlety. */
811  if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
812    {
813      /* Don't move farther back than where we started. */
814      while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
815	rl_point--;
816
817      /* Posix.2 says that if cw or cW moves the cursor towards the end of
818	 the line, the character under the cursor should be deleted. */
819      if (rl_point == rl_mark)
820        rl_point++;
821      else
822	{
823	  /* Move past the end of the word so that the kill doesn't
824	     remove the last letter of the previous word.  Only do this
825	     if we are not at the end of the line. */
826	  if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
827	    rl_point++;
828	}
829    }
830
831  if (rl_mark < rl_point)
832    exchange (rl_point, rl_mark);
833
834  return (0);
835}
836
837/* A simplified loop for vi. Don't dispatch key at end.
838   Don't recognize minus sign? */
839static int
840rl_digit_loop1 ()
841{
842  int key, c;
843
844  while (1)
845    {
846      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
847      key = c = rl_read_key ();
848
849      if (_rl_keymap[c].type == ISFUNC &&
850	  _rl_keymap[c].function == rl_universal_argument)
851	{
852	  rl_numeric_arg *= 4;
853	  continue;
854	}
855
856      c = UNMETA (c);
857      if (_rl_digit_p (c))
858	{
859	  if (rl_explicit_arg)
860	    rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
861	  else
862	    rl_numeric_arg = _rl_digit_value (c);
863	  rl_explicit_arg = 1;
864	}
865      else
866	{
867	  rl_clear_message ();
868	  rl_stuff_char (key);
869	  break;
870	}
871    }
872  return (0);
873}
874
875int
876rl_vi_delete_to (count, key)
877     int count, key;
878{
879  int c;
880
881  if (_rl_uppercase_p (key))
882    rl_stuff_char ('$');
883  else if (vi_redoing)
884    rl_stuff_char (_rl_vi_last_motion);
885
886  if (rl_vi_domove (key, &c))
887    {
888      ding ();
889      return -1;
890    }
891
892  /* These are the motion commands that do not require adjusting the
893     mark. */
894  if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
895    rl_mark++;
896
897  rl_kill_text (rl_point, rl_mark);
898  return (0);
899}
900
901int
902rl_vi_change_to (count, key)
903     int count, key;
904{
905  int c, start_pos;
906
907  if (_rl_uppercase_p (key))
908    rl_stuff_char ('$');
909  else if (vi_redoing)
910    rl_stuff_char (_rl_vi_last_motion);
911
912  start_pos = rl_point;
913
914  if (rl_vi_domove (key, &c))
915    {
916      ding ();
917      return -1;
918    }
919
920  /* These are the motion commands that do not require adjusting the
921     mark.  c[wW] are handled by special-case code in rl_vi_domove(),
922     and already leave the mark at the correct location. */
923  if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
924    rl_mark++;
925
926  /* The cursor never moves with c[wW]. */
927  if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
928    rl_point = start_pos;
929
930  if (vi_redoing)
931    {
932      if (vi_insert_buffer && *vi_insert_buffer)
933	rl_begin_undo_group ();
934      rl_delete_text (rl_point, rl_mark);
935      if (vi_insert_buffer && *vi_insert_buffer)
936	{
937	  rl_insert_text (vi_insert_buffer);
938	  rl_end_undo_group ();
939	}
940    }
941  else
942    {
943      rl_begin_undo_group ();		/* to make the `u' command work */
944      rl_kill_text (rl_point, rl_mark);
945      /* `C' does not save the text inserted for undoing or redoing. */
946      if (_rl_uppercase_p (key) == 0)
947        _rl_vi_doing_insert = 1;
948      _rl_vi_set_last (key, count, rl_arg_sign);
949      rl_vi_insertion_mode (1, key);
950    }
951
952  return (0);
953}
954
955int
956rl_vi_yank_to (count, key)
957     int count, key;
958{
959  int c, save = rl_point;
960
961  if (_rl_uppercase_p (key))
962    rl_stuff_char ('$');
963
964  if (rl_vi_domove (key, &c))
965    {
966      ding ();
967      return -1;
968    }
969
970  /* These are the motion commands that do not require adjusting the
971     mark. */
972  if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
973    rl_mark++;
974
975  rl_begin_undo_group ();
976  rl_kill_text (rl_point, rl_mark);
977  rl_end_undo_group ();
978  rl_do_undo ();
979  rl_point = save;
980
981  return (0);
982}
983
984int
985rl_vi_delete (count, key)
986     int count, key;
987{
988  int end;
989
990  if (rl_end == 0)
991    {
992      ding ();
993      return -1;
994    }
995
996  end = rl_point + count;
997
998  if (end >= rl_end)
999    end = rl_end;
1000
1001  rl_kill_text (rl_point, end);
1002
1003  if (rl_point > 0 && rl_point == rl_end)
1004    rl_backward (1, key);
1005  return (0);
1006}
1007
1008int
1009rl_vi_back_to_indent (count, key)
1010     int count, key;
1011{
1012  rl_beg_of_line (1, key);
1013  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
1014    rl_point++;
1015  return (0);
1016}
1017
1018int
1019rl_vi_first_print (count, key)
1020     int count, key;
1021{
1022  return (rl_vi_back_to_indent (1, key));
1023}
1024
1025int
1026rl_vi_char_search (count, key)
1027     int count, key;
1028{
1029  static char target;
1030  static int orig_dir, dir;
1031
1032  if (key == ';' || key == ',')
1033    dir = key == ';' ? orig_dir : -orig_dir;
1034  else
1035    {
1036      if (vi_redoing)
1037	target = _rl_vi_last_search_char;
1038      else
1039	_rl_vi_last_search_char = target = rl_getc (rl_instream);
1040
1041      switch (key)
1042        {
1043        case 't':
1044          orig_dir = dir = FTO;
1045          break;
1046
1047        case 'T':
1048          orig_dir = dir = BTO;
1049          break;
1050
1051        case 'f':
1052          orig_dir = dir = FFIND;
1053          break;
1054
1055        case 'F':
1056          orig_dir = dir = BFIND;
1057          break;
1058        }
1059    }
1060
1061  return (_rl_char_search_internal (count, dir, target));
1062}
1063
1064/* Match brackets */
1065int
1066rl_vi_match (ignore, key)
1067     int ignore, key;
1068{
1069  int count = 1, brack, pos;
1070
1071  pos = rl_point;
1072  if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
1073    {
1074      while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
1075	     rl_point < rl_end - 1)
1076	rl_forward (1, key);
1077
1078      if (brack <= 0)
1079	{
1080	  rl_point = pos;
1081	  ding ();
1082	  return -1;
1083	}
1084    }
1085
1086  pos = rl_point;
1087
1088  if (brack < 0)
1089    {
1090      while (count)
1091	{
1092	  if (--pos >= 0)
1093	    {
1094	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
1095	      if (b == -brack)
1096		count--;
1097	      else if (b == brack)
1098		count++;
1099	    }
1100	  else
1101	    {
1102	      ding ();
1103	      return -1;
1104	    }
1105	}
1106    }
1107  else
1108    {			/* brack > 0 */
1109      while (count)
1110	{
1111	  if (++pos < rl_end)
1112	    {
1113	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
1114	      if (b == -brack)
1115		count--;
1116	      else if (b == brack)
1117		count++;
1118	    }
1119	  else
1120	    {
1121	      ding ();
1122	      return -1;
1123	    }
1124	}
1125    }
1126  rl_point = pos;
1127  return (0);
1128}
1129
1130int
1131rl_vi_bracktype (c)
1132     int c;
1133{
1134  switch (c)
1135    {
1136    case '(': return  1;
1137    case ')': return -1;
1138    case '[': return  2;
1139    case ']': return -2;
1140    case '{': return  3;
1141    case '}': return -3;
1142    default:  return  0;
1143    }
1144}
1145
1146int
1147rl_vi_change_char (count, key)
1148     int count, key;
1149{
1150  int c;
1151
1152  if (vi_redoing)
1153    c = _rl_vi_last_replacement;
1154  else
1155    _rl_vi_last_replacement = c = rl_getc (rl_instream);
1156
1157  if (c == '\033' || c == CTRL ('C'))
1158    return -1;
1159
1160  while (count-- && rl_point < rl_end)
1161    {
1162      rl_begin_undo_group ();
1163
1164      rl_delete (1, c);
1165      rl_insert (1, c);
1166      if (count == 0)
1167	rl_backward (1, c);
1168
1169      rl_end_undo_group ();
1170    }
1171  return (0);
1172}
1173
1174int
1175rl_vi_subst (count, key)
1176     int count, key;
1177{
1178  rl_begin_undo_group ();
1179
1180  if (_rl_uppercase_p (key))
1181    {
1182      rl_beg_of_line (1, key);
1183      rl_kill_line (1, key);
1184    }
1185  else
1186    rl_delete_text (rl_point, rl_point+count);
1187
1188  rl_end_undo_group ();
1189
1190  _rl_vi_set_last (key, count, rl_arg_sign);
1191
1192  if (vi_redoing)
1193    {
1194      int o = _rl_doing_an_undo;
1195
1196      _rl_doing_an_undo = 1;
1197      if (vi_insert_buffer && *vi_insert_buffer)
1198	rl_insert_text (vi_insert_buffer);
1199      _rl_doing_an_undo = o;
1200    }
1201  else
1202    {
1203      rl_begin_undo_group ();
1204      _rl_vi_doing_insert = 1;
1205      rl_vi_insertion_mode (1, key);
1206    }
1207
1208  return (0);
1209}
1210
1211int
1212rl_vi_overstrike (count, key)
1213     int count, key;
1214{
1215  int i;
1216
1217  if (_rl_vi_doing_insert == 0)
1218    {
1219      _rl_vi_doing_insert = 1;
1220      rl_begin_undo_group ();
1221    }
1222
1223  for (i = 0; i < count; i++)
1224    {
1225      vi_replace_count++;
1226      rl_begin_undo_group ();
1227
1228      if (rl_point < rl_end)
1229	{
1230	  rl_delete (1, key);
1231	  rl_insert (1, key);
1232	}
1233      else
1234	rl_insert (1, key);
1235
1236      rl_end_undo_group ();
1237    }
1238  return (0);
1239}
1240
1241int
1242rl_vi_overstrike_delete (count, key)
1243     int count, key;
1244{
1245  int i, s;
1246
1247  for (i = 0; i < count; i++)
1248    {
1249      if (vi_replace_count == 0)
1250	{
1251	  ding ();
1252	  break;
1253	}
1254      s = rl_point;
1255
1256      if (rl_do_undo ())
1257	vi_replace_count--;
1258
1259      if (rl_point == s)
1260	rl_backward (1, key);
1261    }
1262
1263  if (vi_replace_count == 0 && _rl_vi_doing_insert)
1264    {
1265      rl_end_undo_group ();
1266      rl_do_undo ();
1267      _rl_vi_doing_insert = 0;
1268    }
1269  return (0);
1270}
1271
1272int
1273rl_vi_replace (count, key)
1274     int count, key;
1275{
1276  int i;
1277
1278  vi_replace_count = 0;
1279
1280  if (!vi_replace_map)
1281    {
1282      vi_replace_map = rl_make_bare_keymap ();
1283
1284      for (i = ' '; i < KEYMAP_SIZE; i++)
1285	vi_replace_map[i].function = rl_vi_overstrike;
1286
1287      vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
1288      vi_replace_map[ESC].function = rl_vi_movement_mode;
1289      vi_replace_map[RETURN].function = rl_newline;
1290      vi_replace_map[NEWLINE].function = rl_newline;
1291
1292      /* If the normal vi insertion keymap has ^H bound to erase, do the
1293         same here.  Probably should remove the assignment to RUBOUT up
1294         there, but I don't think it will make a difference in real life. */
1295      if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
1296	  vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
1297	vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
1298
1299    }
1300  _rl_keymap = vi_replace_map;
1301  return (0);
1302}
1303
1304#if 0
1305/* Try to complete the word we are standing on or the word that ends with
1306   the previous character.  A space matches everything.  Word delimiters are
1307   space and ;. */
1308int
1309rl_vi_possible_completions()
1310{
1311  int save_pos = rl_point;
1312
1313  if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
1314    {
1315      while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
1316	     rl_line_buffer[rl_point] != ';')
1317	rl_point++;
1318    }
1319  else if (rl_line_buffer[rl_point - 1] == ';')
1320    {
1321      ding ();
1322      return (0);
1323    }
1324
1325  rl_possible_completions ();
1326  rl_point = save_pos;
1327
1328  return (0);
1329}
1330#endif
1331
1332/* Functions to save and restore marks. */
1333int
1334rl_vi_set_mark (count, key)
1335     int count, key;
1336{
1337  int ch;
1338
1339  ch = rl_read_key ();
1340  if (_rl_lowercase_p (ch) == 0)
1341    {
1342      ding ();
1343      return -1;
1344    }
1345  ch -= 'a';
1346  vi_mark_chars[ch] = rl_point;
1347  return 0;
1348}
1349
1350int
1351rl_vi_goto_mark (count, key)
1352     int count, key;
1353{
1354  int ch;
1355
1356  ch = rl_read_key ();
1357  if (ch == '`')
1358    {
1359      rl_point = rl_mark;
1360      return 0;
1361    }
1362  else if (_rl_lowercase_p (ch) == 0)
1363    {
1364      ding ();
1365      return -1;
1366    }
1367
1368  ch -= 'a';
1369  if (vi_mark_chars[ch] == -1)
1370    {
1371      ding ();
1372      return -1;
1373    }
1374  rl_point = vi_mark_chars[ch];
1375  return 0;
1376}
1377
1378#endif /* VI_MODE */
1379