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