vi_mode.c revision 21308
121308Sache/* vi_mode.c -- A vi emulation mode for Bash.
221308Sache   Derived from code written by Jeff Sparkes (jsparkes@bnr.ca).  */
321308Sache
421308Sache/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
521308Sache
621308Sache   This file is part of the GNU Readline Library, a library for
721308Sache   reading lines of text with interactive input and history editing.
821308Sache
921308Sache   The GNU Readline Library is free software; you can redistribute it
1021308Sache   and/or modify it under the terms of the GNU General Public License
1121308Sache   as published by the Free Software Foundation; either version 1, or
1221308Sache   (at your option) any later version.
1321308Sache
1421308Sache   The GNU Readline Library is distributed in the hope that it will be
1521308Sache   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1621308Sache   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1721308Sache   GNU General Public License for more details.
1821308Sache
1921308Sache   The GNU General Public License is often shipped with GNU software, and
2021308Sache   is generally kept in a file called COPYING or LICENSE.  If you do not
2121308Sache   have a copy of the license, write to the Free Software Foundation,
2221308Sache   675 Mass Ave, Cambridge, MA 02139, USA. */
2321308Sache#define READLINE_LIBRARY
2421308Sache
2521308Sache/* **************************************************************** */
2621308Sache/*								    */
2721308Sache/*			VI Emulation Mode			    */
2821308Sache/*								    */
2921308Sache/* **************************************************************** */
3021308Sache#include "rlconf.h"
3121308Sache
3221308Sache#if defined (VI_MODE)
3321308Sache
3421308Sache#if defined (HAVE_CONFIG_H)
3521308Sache#  include <config.h>
3621308Sache#endif
3721308Sache
3821308Sache#include <sys/types.h>
3921308Sache
4021308Sache#if defined (HAVE_STDLIB_H)
4121308Sache#  include <stdlib.h>
4221308Sache#else
4321308Sache#  include "ansi_stdlib.h"
4421308Sache#endif /* HAVE_STDLIB_H */
4521308Sache
4621308Sache#if defined (HAVE_UNISTD_H)
4721308Sache#  include <unistd.h>
4821308Sache#endif
4921308Sache
5021308Sache#include <stdio.h>
5121308Sache
5221308Sache/* Some standard library routines. */
5321308Sache#include "rldefs.h"
5421308Sache#include "readline.h"
5521308Sache#include "history.h"
5621308Sache
5721308Sache#ifndef _rl_digit_p
5821308Sache#define _rl_digit_p(c)  ((c) >= '0' && (c) <= '9')
5921308Sache#endif
6021308Sache
6121308Sache#ifndef _rl_digit_value
6221308Sache#define _rl_digit_value(c) ((c) - '0')
6321308Sache#endif
6421308Sache
6521308Sache#ifndef member
6621308Sache#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
6721308Sache#endif
6821308Sache
6921308Sache#ifndef isident
7021308Sache#define isident(c) ((_rl_pure_alphabetic (c) || _rl_digit_p (c) || c == '_'))
7121308Sache#endif
7221308Sache
7321308Sache#ifndef exchange
7421308Sache#define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0)
7521308Sache#endif
7621308Sache
7721308Sacheextern char *xmalloc (), *xrealloc ();
7821308Sache
7921308Sache/* Variables imported from readline.c */
8021308Sacheextern int rl_point, rl_end, rl_mark, rl_done;
8121308Sacheextern FILE *rl_instream;
8221308Sacheextern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg;
8321308Sacheextern Keymap _rl_keymap;
8421308Sacheextern char *rl_prompt;
8521308Sacheextern char *rl_line_buffer;
8621308Sacheextern int rl_arg_sign;
8721308Sache
8821308Sacheextern int _rl_doing_an_undo;
8921308Sacheextern int _rl_undo_group_level;
9021308Sache
9121308Sacheextern void _rl_dispatch ();
9221308Sacheextern int _rl_char_search_internal ();
9321308Sache
9421308Sacheextern void rl_extend_line_buffer ();
9521308Sacheextern int rl_vi_check ();
9621308Sache
9721308Sache/* Non-zero means enter insertion mode. */
9821308Sachestatic int _rl_vi_doing_insert;
9921308Sache
10021308Sache/* Command keys which do movement for xxx_to commands. */
10121308Sachestatic char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
10221308Sache
10321308Sache/* Keymap used for vi replace characters.  Created dynamically since
10421308Sache   rarely used. */
10521308Sachestatic Keymap vi_replace_map;
10621308Sache
10721308Sache/* The number of characters inserted in the last replace operation. */
10821308Sachestatic int vi_replace_count;
10921308Sache
11021308Sache/* If non-zero, we have text inserted after a c[motion] command that put
11121308Sache   us implicitly into insert mode.  Some people want this text to be
11221308Sache   attached to the command so that it is `redoable' with `.'. */
11321308Sachestatic int vi_continued_command;
11421308Sachestatic char *vi_insert_buffer;
11521308Sachestatic int vi_insert_buffer_size;
11621308Sache
11721308Sachestatic int _rl_vi_last_command = 'i';	/* default `.' puts you in insert mode */
11821308Sachestatic int _rl_vi_last_repeat = 1;
11921308Sachestatic int _rl_vi_last_arg_sign = 1;
12021308Sachestatic int _rl_vi_last_motion;
12121308Sachestatic int _rl_vi_last_search_char;
12221308Sachestatic int _rl_vi_last_replacement;
12321308Sache
12421308Sachestatic int _rl_vi_last_key_before_insert;
12521308Sache
12621308Sachestatic int vi_redoing;
12721308Sache
12821308Sache/* Text modification commands.  These are the `redoable' commands. */
12921308Sachestatic char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~";
13021308Sache
13121308Sache/* Arrays for the saved marks. */
13221308Sachestatic int vi_mark_chars[27];
13321308Sache
13421308Sachestatic int rl_digit_loop1 ();
13521308Sache
13621308Sachevoid
13721308Sache_rl_vi_initialize_line ()
13821308Sache{
13921308Sache  register int i;
14021308Sache
14121308Sache  for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
14221308Sache    vi_mark_chars[i] = -1;
14321308Sache}
14421308Sache
14521308Sachevoid
14621308Sache_rl_vi_reset_last ()
14721308Sache{
14821308Sache  _rl_vi_last_command = 'i';
14921308Sache  _rl_vi_last_repeat = 1;
15021308Sache  _rl_vi_last_arg_sign = 1;
15121308Sache  _rl_vi_last_motion = 0;
15221308Sache}
15321308Sache
15421308Sachevoid
15521308Sache_rl_vi_set_last (key, repeat, sign)
15621308Sache     int key, repeat, sign;
15721308Sache{
15821308Sache  _rl_vi_last_command = key;
15921308Sache  _rl_vi_last_repeat = repeat;
16021308Sache  _rl_vi_last_arg_sign = sign;
16121308Sache}
16221308Sache
16321308Sache/* Is the command C a VI mode text modification command? */
16421308Sacheint
16521308Sache_rl_vi_textmod_command (c)
16621308Sache     int c;
16721308Sache{
16821308Sache  return (member (c, vi_textmod));
16921308Sache}
17021308Sache
17121308Sachestatic void
17221308Sache_rl_vi_stuff_insert (count)
17321308Sache     int count;
17421308Sache{
17521308Sache  rl_begin_undo_group ();
17621308Sache  while (count--)
17721308Sache    rl_insert_text (vi_insert_buffer);
17821308Sache  rl_end_undo_group ();
17921308Sache}
18021308Sache
18121308Sache/* Bound to `.'.  Called from command mode, so we know that we have to
18221308Sache   redo a text modification command.  The default for _rl_vi_last_command
18321308Sache   puts you back into insert mode. */
18421308Sacheint
18521308Sacherl_vi_redo (count, c)
18621308Sache     int count, c;
18721308Sache{
18821308Sache  if (!rl_explicit_arg)
18921308Sache    {
19021308Sache      rl_numeric_arg = _rl_vi_last_repeat;
19121308Sache      rl_arg_sign = _rl_vi_last_arg_sign;
19221308Sache    }
19321308Sache
19421308Sache  vi_redoing = 1;
19521308Sache  /* If we're redoing an insert with `i', stuff in the inserted text
19621308Sache     and do not go into insertion mode. */
19721308Sache  if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
19821308Sache    {
19921308Sache      _rl_vi_stuff_insert (count);
20021308Sache      /* And back up point over the last character inserted. */
20121308Sache      if (rl_point > 0)
20221308Sache	rl_point--;
20321308Sache    }
20421308Sache  else
20521308Sache    _rl_dispatch (_rl_vi_last_command, _rl_keymap);
20621308Sache  vi_redoing = 0;
20721308Sache
20821308Sache  return (0);
20921308Sache}
21021308Sache
21121308Sache/* A placeholder for further expansion. */
21221308Sacheint
21321308Sacherl_vi_undo (count, key)
21421308Sache     int count, key;
21521308Sache{
21621308Sache  return (rl_undo_command (count, key));
21721308Sache}
21821308Sache
21921308Sache/* Yank the nth arg from the previous line into this line at point. */
22021308Sacheint
22121308Sacherl_vi_yank_arg (count, key)
22221308Sache     int count, key;
22321308Sache{
22421308Sache  /* Readline thinks that the first word on a line is the 0th, while vi
22521308Sache     thinks the first word on a line is the 1st.  Compensate. */
22621308Sache  if (rl_explicit_arg)
22721308Sache    rl_yank_nth_arg (count - 1, 0);
22821308Sache  else
22921308Sache    rl_yank_nth_arg ('$', 0);
23021308Sache
23121308Sache  return (0);
23221308Sache}
23321308Sache
23421308Sache/* With an argument, move back that many history lines, else move to the
23521308Sache   beginning of history. */
23621308Sacheint
23721308Sacherl_vi_fetch_history (count, c)
23821308Sache     int count, c;
23921308Sache{
24021308Sache  int wanted;
24121308Sache
24221308Sache  /* Giving an argument of n means we want the nth command in the history
24321308Sache     file.  The command number is interpreted the same way that the bash
24421308Sache     `history' command does it -- that is, giving an argument count of 450
24521308Sache     to this command would get the command listed as number 450 in the
24621308Sache     output of `history'. */
24721308Sache  if (rl_explicit_arg)
24821308Sache    {
24921308Sache      wanted = history_base + where_history () - count;
25021308Sache      if (wanted <= 0)
25121308Sache        rl_beginning_of_history (0, 0);
25221308Sache      else
25321308Sache        rl_get_previous_history (wanted, c);
25421308Sache    }
25521308Sache  else
25621308Sache    rl_beginning_of_history (count, 0);
25721308Sache  return (0);
25821308Sache}
25921308Sache
26021308Sache/* Search again for the last thing searched for. */
26121308Sacheint
26221308Sacherl_vi_search_again (count, key)
26321308Sache     int count, key;
26421308Sache{
26521308Sache  switch (key)
26621308Sache    {
26721308Sache    case 'n':
26821308Sache      rl_noninc_reverse_search_again (count, key);
26921308Sache      break;
27021308Sache
27121308Sache    case 'N':
27221308Sache      rl_noninc_forward_search_again (count, key);
27321308Sache      break;
27421308Sache    }
27521308Sache  return (0);
27621308Sache}
27721308Sache
27821308Sache/* Do a vi style search. */
27921308Sacheint
28021308Sacherl_vi_search (count, key)
28121308Sache     int count, key;
28221308Sache{
28321308Sache  switch (key)
28421308Sache    {
28521308Sache    case '?':
28621308Sache      rl_noninc_forward_search (count, key);
28721308Sache      break;
28821308Sache
28921308Sache    case '/':
29021308Sache      rl_noninc_reverse_search (count, key);
29121308Sache      break;
29221308Sache
29321308Sache    default:
29421308Sache      ding ();
29521308Sache      break;
29621308Sache    }
29721308Sache  return (0);
29821308Sache}
29921308Sache
30021308Sache/* Completion, from vi's point of view. */
30121308Sacheint
30221308Sacherl_vi_complete (ignore, key)
30321308Sache     int ignore, key;
30421308Sache{
30521308Sache  if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
30621308Sache    {
30721308Sache      if (!whitespace (rl_line_buffer[rl_point + 1]))
30821308Sache	rl_vi_end_word (1, 'E');
30921308Sache      rl_point++;
31021308Sache    }
31121308Sache
31221308Sache  if (key == '*')
31321308Sache    rl_complete_internal ('*');	/* Expansion and replacement. */
31421308Sache  else if (key == '=')
31521308Sache    rl_complete_internal ('?');	/* List possible completions. */
31621308Sache  else if (key == '\\')
31721308Sache    rl_complete_internal (TAB);	/* Standard Readline completion. */
31821308Sache  else
31921308Sache    rl_complete (0, key);
32021308Sache
32121308Sache  if (key == '*' || key == '\\')
32221308Sache    {
32321308Sache      _rl_vi_set_last (key, 1, rl_arg_sign);
32421308Sache      rl_vi_insertion_mode (1, key);
32521308Sache    }
32621308Sache  return (0);
32721308Sache}
32821308Sache
32921308Sache/* Tilde expansion for vi mode. */
33021308Sacheint
33121308Sacherl_vi_tilde_expand (ignore, key)
33221308Sache     int ignore, key;
33321308Sache{
33421308Sache  rl_tilde_expand (0, key);
33521308Sache  _rl_vi_set_last (key, 1, rl_arg_sign);	/* XXX */
33621308Sache  rl_vi_insertion_mode (1, key);
33721308Sache  return (0);
33821308Sache}
33921308Sache
34021308Sache/* Previous word in vi mode. */
34121308Sacheint
34221308Sacherl_vi_prev_word (count, key)
34321308Sache     int count, key;
34421308Sache{
34521308Sache  if (count < 0)
34621308Sache    return (rl_vi_next_word (-count, key));
34721308Sache
34821308Sache  if (rl_point == 0)
34921308Sache    {
35021308Sache      ding ();
35121308Sache      return (0);
35221308Sache    }
35321308Sache
35421308Sache  if (_rl_uppercase_p (key))
35521308Sache    rl_vi_bWord (count);
35621308Sache  else
35721308Sache    rl_vi_bword (count);
35821308Sache
35921308Sache  return (0);
36021308Sache}
36121308Sache
36221308Sache/* Next word in vi mode. */
36321308Sacheint
36421308Sacherl_vi_next_word (count, key)
36521308Sache     int count, key;
36621308Sache{
36721308Sache  if (count < 0)
36821308Sache    return (rl_vi_prev_word (-count, key));
36921308Sache
37021308Sache  if (rl_point >= (rl_end - 1))
37121308Sache    {
37221308Sache      ding ();
37321308Sache      return (0);
37421308Sache    }
37521308Sache
37621308Sache  if (_rl_uppercase_p (key))
37721308Sache    rl_vi_fWord (count);
37821308Sache  else
37921308Sache    rl_vi_fword (count);
38021308Sache  return (0);
38121308Sache}
38221308Sache
38321308Sache/* Move to the end of the ?next? word. */
38421308Sacheint
38521308Sacherl_vi_end_word (count, key)
38621308Sache     int count, key;
38721308Sache{
38821308Sache  if (count < 0)
38921308Sache    {
39021308Sache      ding ();
39121308Sache      return -1;
39221308Sache    }
39321308Sache
39421308Sache  if (_rl_uppercase_p (key))
39521308Sache    rl_vi_eWord (count);
39621308Sache  else
39721308Sache    rl_vi_eword (count);
39821308Sache  return (0);
39921308Sache}
40021308Sache
40121308Sache/* Move forward a word the way that 'W' does. */
40221308Sacheint
40321308Sacherl_vi_fWord (count)
40421308Sache     int count;
40521308Sache{
40621308Sache  while (count-- && rl_point < (rl_end - 1))
40721308Sache    {
40821308Sache      /* Skip until whitespace. */
40921308Sache      while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
41021308Sache	rl_point++;
41121308Sache
41221308Sache      /* Now skip whitespace. */
41321308Sache      while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
41421308Sache	rl_point++;
41521308Sache    }
41621308Sache  return (0);
41721308Sache}
41821308Sache
41921308Sacheint
42021308Sacherl_vi_bWord (count)
42121308Sache     int count;
42221308Sache{
42321308Sache  while (count-- && rl_point > 0)
42421308Sache    {
42521308Sache      /* If we are at the start of a word, move back to whitespace so
42621308Sache	 we will go back to the start of the previous word. */
42721308Sache      if (!whitespace (rl_line_buffer[rl_point]) &&
42821308Sache	  whitespace (rl_line_buffer[rl_point - 1]))
42921308Sache	rl_point--;
43021308Sache
43121308Sache      while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
43221308Sache	rl_point--;
43321308Sache
43421308Sache      if (rl_point > 0)
43521308Sache	{
43621308Sache	  while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point]));
43721308Sache	  rl_point++;
43821308Sache	}
43921308Sache    }
44021308Sache  return (0);
44121308Sache}
44221308Sache
44321308Sacheint
44421308Sacherl_vi_eWord (count)
44521308Sache     int count;
44621308Sache{
44721308Sache  while (count-- && rl_point < (rl_end - 1))
44821308Sache    {
44921308Sache      if (!whitespace (rl_line_buffer[rl_point]))
45021308Sache	rl_point++;
45121308Sache
45221308Sache      /* Move to the next non-whitespace character (to the start of the
45321308Sache	 next word). */
45421308Sache      while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point]));
45521308Sache
45621308Sache      if (rl_point && rl_point < rl_end)
45721308Sache	{
45821308Sache	  /* Skip whitespace. */
45921308Sache	  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
46021308Sache	    rl_point++;
46121308Sache
46221308Sache	  /* Skip until whitespace. */
46321308Sache	  while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point]))
46421308Sache	    rl_point++;
46521308Sache
46621308Sache	  /* Move back to the last character of the word. */
46721308Sache	  rl_point--;
46821308Sache	}
46921308Sache    }
47021308Sache  return (0);
47121308Sache}
47221308Sache
47321308Sacheint
47421308Sacherl_vi_fword (count)
47521308Sache     int count;
47621308Sache{
47721308Sache  while (count-- && rl_point < (rl_end - 1))
47821308Sache    {
47921308Sache      /* Move to white space (really non-identifer). */
48021308Sache      if (isident (rl_line_buffer[rl_point]))
48121308Sache	{
48221308Sache	  while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
48321308Sache	    rl_point++;
48421308Sache	}
48521308Sache      else /* if (!whitespace (rl_line_buffer[rl_point])) */
48621308Sache	{
48721308Sache	  while (!isident (rl_line_buffer[rl_point]) &&
48821308Sache		 !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
48921308Sache	    rl_point++;
49021308Sache	}
49121308Sache
49221308Sache      /* Move past whitespace. */
49321308Sache      while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
49421308Sache	rl_point++;
49521308Sache    }
49621308Sache  return (0);
49721308Sache}
49821308Sache
49921308Sacheint
50021308Sacherl_vi_bword (count)
50121308Sache     int count;
50221308Sache{
50321308Sache  while (count-- && rl_point > 0)
50421308Sache    {
50521308Sache      int last_is_ident;
50621308Sache
50721308Sache      /* If we are at the start of a word, move back to whitespace
50821308Sache	 so we will go back to the start of the previous word. */
50921308Sache      if (!whitespace (rl_line_buffer[rl_point]) &&
51021308Sache	  whitespace (rl_line_buffer[rl_point - 1]))
51121308Sache	rl_point--;
51221308Sache
51321308Sache      /* If this character and the previous character are `opposite', move
51421308Sache	 back so we don't get messed up by the rl_point++ down there in
51521308Sache	 the while loop.  Without this code, words like `l;' screw up the
51621308Sache	 function. */
51721308Sache      last_is_ident = isident (rl_line_buffer[rl_point - 1]);
51821308Sache      if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
51921308Sache	  (!isident (rl_line_buffer[rl_point]) && last_is_ident))
52021308Sache	rl_point--;
52121308Sache
52221308Sache      while (rl_point > 0 && whitespace (rl_line_buffer[rl_point]))
52321308Sache	rl_point--;
52421308Sache
52521308Sache      if (rl_point > 0)
52621308Sache	{
52721308Sache	  if (isident (rl_line_buffer[rl_point]))
52821308Sache	    while (--rl_point >= 0 && isident (rl_line_buffer[rl_point]));
52921308Sache	  else
53021308Sache	    while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) &&
53121308Sache		   !whitespace (rl_line_buffer[rl_point]));
53221308Sache	  rl_point++;
53321308Sache	}
53421308Sache    }
53521308Sache  return (0);
53621308Sache}
53721308Sache
53821308Sacheint
53921308Sacherl_vi_eword (count)
54021308Sache     int count;
54121308Sache{
54221308Sache  while (count-- && rl_point < rl_end - 1)
54321308Sache    {
54421308Sache      if (!whitespace (rl_line_buffer[rl_point]))
54521308Sache	rl_point++;
54621308Sache
54721308Sache      while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
54821308Sache	rl_point++;
54921308Sache
55021308Sache      if (rl_point < rl_end)
55121308Sache	{
55221308Sache	  if (isident (rl_line_buffer[rl_point]))
55321308Sache	    while (++rl_point < rl_end && isident (rl_line_buffer[rl_point]));
55421308Sache	  else
55521308Sache	    while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point])
55621308Sache		   && !whitespace (rl_line_buffer[rl_point]));
55721308Sache	}
55821308Sache      rl_point--;
55921308Sache    }
56021308Sache  return (0);
56121308Sache}
56221308Sache
56321308Sacheint
56421308Sacherl_vi_insert_beg (count, key)
56521308Sache     int count, key;
56621308Sache{
56721308Sache  rl_beg_of_line (1, key);
56821308Sache  rl_vi_insertion_mode (1, key);
56921308Sache  return (0);
57021308Sache}
57121308Sache
57221308Sacheint
57321308Sacherl_vi_append_mode (count, key)
57421308Sache     int count, key;
57521308Sache{
57621308Sache  if (rl_point < rl_end)
57721308Sache    rl_point++;
57821308Sache  rl_vi_insertion_mode (1, key);
57921308Sache  return (0);
58021308Sache}
58121308Sache
58221308Sacheint
58321308Sacherl_vi_append_eol (count, key)
58421308Sache     int count, key;
58521308Sache{
58621308Sache  rl_end_of_line (1, key);
58721308Sache  rl_vi_append_mode (1, key);
58821308Sache  return (0);
58921308Sache}
59021308Sache
59121308Sache/* What to do in the case of C-d. */
59221308Sacheint
59321308Sacherl_vi_eof_maybe (count, c)
59421308Sache     int count, c;
59521308Sache{
59621308Sache  return (rl_newline (1, '\n'));
59721308Sache}
59821308Sache
59921308Sache/* Insertion mode stuff. */
60021308Sache
60121308Sache/* Switching from one mode to the other really just involves
60221308Sache   switching keymaps. */
60321308Sacheint
60421308Sacherl_vi_insertion_mode (count, key)
60521308Sache     int count, key;
60621308Sache{
60721308Sache  _rl_keymap = vi_insertion_keymap;
60821308Sache  _rl_vi_last_key_before_insert = key;
60921308Sache  return (0);
61021308Sache}
61121308Sache
61221308Sachestatic void
61321308Sache_rl_vi_save_insert (up)
61421308Sache      UNDO_LIST *up;
61521308Sache{
61621308Sache  int len, start, end;
61721308Sache
61821308Sache  start = up->start;
61921308Sache  end = up->end;
62021308Sache  len = end - start + 1;
62121308Sache  if (len >= vi_insert_buffer_size)
62221308Sache    {
62321308Sache      vi_insert_buffer_size += (len + 32) - (len % 32);
62421308Sache      vi_insert_buffer = xrealloc (vi_insert_buffer, vi_insert_buffer_size);
62521308Sache    }
62621308Sache  strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
62721308Sache  vi_insert_buffer[len-1] = '\0';
62821308Sache}
62921308Sache
63021308Sachevoid
63121308Sache_rl_vi_done_inserting ()
63221308Sache{
63321308Sache  if (_rl_vi_doing_insert)
63421308Sache    {
63521308Sache      rl_end_undo_group ();
63621308Sache      /* Now, the text between rl_undo_list->next->start and
63721308Sache	 rl_undo_list->next->end is what was inserted while in insert
63821308Sache	 mode.  It gets copied to VI_INSERT_BUFFER because it depends
63921308Sache	 on absolute indices into the line which may change (though they
64021308Sache	 probably will not). */
64121308Sache      _rl_vi_doing_insert = 0;
64221308Sache      _rl_vi_save_insert (rl_undo_list->next);
64321308Sache      vi_continued_command = 1;
64421308Sache    }
64521308Sache  else
64621308Sache    {
64721308Sache      if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list)
64821308Sache        _rl_vi_save_insert (rl_undo_list);
64921308Sache      /* XXX - Other keys probably need to be checked. */
65021308Sache      else if (_rl_vi_last_key_before_insert == 'C')
65121308Sache	rl_end_undo_group ();
65221308Sache      while (_rl_undo_group_level > 0)
65321308Sache	rl_end_undo_group ();
65421308Sache      vi_continued_command = 0;
65521308Sache    }
65621308Sache}
65721308Sache
65821308Sacheint
65921308Sacherl_vi_movement_mode (count, key)
66021308Sache     int count, key;
66121308Sache{
66221308Sache  if (rl_point > 0)
66321308Sache    rl_backward (1, key);
66421308Sache
66521308Sache  _rl_keymap = vi_movement_keymap;
66621308Sache  _rl_vi_done_inserting ();
66721308Sache  return (0);
66821308Sache}
66921308Sache
67021308Sacheint
67121308Sacherl_vi_arg_digit (count, c)
67221308Sache     int count, c;
67321308Sache{
67421308Sache  if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
67521308Sache    return (rl_beg_of_line (1, c));
67621308Sache  else
67721308Sache    return (rl_digit_argument (count, c));
67821308Sache}
67921308Sache
68021308Sacheint
68121308Sacherl_vi_change_case (count, ignore)
68221308Sache     int count, ignore;
68321308Sache{
68421308Sache  char c = 0;
68521308Sache
68621308Sache  /* Don't try this on an empty line. */
68721308Sache  if (rl_point >= rl_end)
68821308Sache    return (0);
68921308Sache
69021308Sache  while (count-- && rl_point < rl_end)
69121308Sache    {
69221308Sache      if (_rl_uppercase_p (rl_line_buffer[rl_point]))
69321308Sache	c = _rl_to_lower (rl_line_buffer[rl_point]);
69421308Sache      else if (_rl_lowercase_p (rl_line_buffer[rl_point]))
69521308Sache	c = _rl_to_upper (rl_line_buffer[rl_point]);
69621308Sache      else
69721308Sache	{
69821308Sache	  /* Just skip over characters neither upper nor lower case. */
69921308Sache	  rl_forward (1, c);
70021308Sache	  continue;
70121308Sache	}
70221308Sache
70321308Sache      /* Vi is kind of strange here. */
70421308Sache      if (c)
70521308Sache	{
70621308Sache	  rl_begin_undo_group ();
70721308Sache	  rl_delete (1, c);
70821308Sache	  rl_insert (1, c);
70921308Sache	  rl_end_undo_group ();
71021308Sache	  rl_vi_check ();
71121308Sache        }
71221308Sache      else
71321308Sache	rl_forward (1, c);
71421308Sache    }
71521308Sache  return (0);
71621308Sache}
71721308Sache
71821308Sacheint
71921308Sacherl_vi_put (count, key)
72021308Sache     int count, key;
72121308Sache{
72221308Sache  if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
72321308Sache    rl_point++;
72421308Sache
72521308Sache  rl_yank ();
72621308Sache  rl_backward (1, key);
72721308Sache  return (0);
72821308Sache}
72921308Sache
73021308Sacheint
73121308Sacherl_vi_check ()
73221308Sache{
73321308Sache  if (rl_point && rl_point == rl_end)
73421308Sache    rl_point--;
73521308Sache  return (0);
73621308Sache}
73721308Sache
73821308Sacheint
73921308Sacherl_vi_column (count, key)
74021308Sache     int count, key;
74121308Sache{
74221308Sache  if (count > rl_end)
74321308Sache    rl_end_of_line (1, key);
74421308Sache  else
74521308Sache    rl_point = count - 1;
74621308Sache  return (0);
74721308Sache}
74821308Sache
74921308Sacheint
75021308Sacherl_vi_domove (key, nextkey)
75121308Sache     int key, *nextkey;
75221308Sache{
75321308Sache  int c, save;
75421308Sache  int old_end;
75521308Sache
75621308Sache  rl_mark = rl_point;
75721308Sache  c = rl_read_key ();
75821308Sache  *nextkey = c;
75921308Sache
76021308Sache  if (!member (c, vi_motion))
76121308Sache    {
76221308Sache      if (_rl_digit_p (c))
76321308Sache	{
76421308Sache	  save = rl_numeric_arg;
76521308Sache	  rl_numeric_arg = _rl_digit_value (c);
76621308Sache	  rl_digit_loop1 ();
76721308Sache	  rl_numeric_arg *= save;
76821308Sache	  c = rl_read_key ();	/* real command */
76921308Sache	  *nextkey = c;
77021308Sache	}
77121308Sache      else if (key == c && (key == 'd' || key == 'y' || key == 'c'))
77221308Sache	{
77321308Sache	  rl_mark = rl_end;
77421308Sache	  rl_beg_of_line (1, c);
77521308Sache	  _rl_vi_last_motion = c;
77621308Sache	  return (0);
77721308Sache	}
77821308Sache      else
77921308Sache	return (-1);
78021308Sache    }
78121308Sache
78221308Sache  _rl_vi_last_motion = c;
78321308Sache
78421308Sache  /* Append a blank character temporarily so that the motion routines
78521308Sache     work right at the end of the line. */
78621308Sache  old_end = rl_end;
78721308Sache  rl_line_buffer[rl_end++] = ' ';
78821308Sache  rl_line_buffer[rl_end] = '\0';
78921308Sache
79021308Sache  _rl_dispatch (c, _rl_keymap);
79121308Sache
79221308Sache  /* Remove the blank that we added. */
79321308Sache  rl_end = old_end;
79421308Sache  rl_line_buffer[rl_end] = '\0';
79521308Sache  if (rl_point > rl_end)
79621308Sache    rl_point = rl_end;
79721308Sache
79821308Sache  /* No change in position means the command failed. */
79921308Sache  if (rl_mark == rl_point)
80021308Sache    return (-1);
80121308Sache
80221308Sache  /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
80321308Sache     word.  If we are not at the end of the line, and we are on a
80421308Sache     non-whitespace character, move back one (presumably to whitespace). */
80521308Sache  if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
80621308Sache      !whitespace (rl_line_buffer[rl_point]))
80721308Sache    rl_point--;
80821308Sache
80921308Sache  /* If cw or cW, back up to the end of a word, so the behaviour of ce
81021308Sache     or cE is the actual result.  Brute-force, no subtlety. */
81121308Sache  if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
81221308Sache    {
81321308Sache      /* Don't move farther back than where we started. */
81421308Sache      while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
81521308Sache	rl_point--;
81621308Sache
81721308Sache      /* Posix.2 says that if cw or cW moves the cursor towards the end of
81821308Sache	 the line, the character under the cursor should be deleted. */
81921308Sache      if (rl_point == rl_mark)
82021308Sache        rl_point++;
82121308Sache      else
82221308Sache	{
82321308Sache	  /* Move past the end of the word so that the kill doesn't
82421308Sache	     remove the last letter of the previous word.  Only do this
82521308Sache	     if we are not at the end of the line. */
82621308Sache	  if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
82721308Sache	    rl_point++;
82821308Sache	}
82921308Sache    }
83021308Sache
83121308Sache  if (rl_mark < rl_point)
83221308Sache    exchange (rl_point, rl_mark);
83321308Sache
83421308Sache  return (0);
83521308Sache}
83621308Sache
83721308Sache/* A simplified loop for vi. Don't dispatch key at end.
83821308Sache   Don't recognize minus sign? */
83921308Sachestatic int
84021308Sacherl_digit_loop1 ()
84121308Sache{
84221308Sache  int key, c;
84321308Sache
84421308Sache  while (1)
84521308Sache    {
84621308Sache      rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0);
84721308Sache      key = c = rl_read_key ();
84821308Sache
84921308Sache      if (_rl_keymap[c].type == ISFUNC &&
85021308Sache	  _rl_keymap[c].function == rl_universal_argument)
85121308Sache	{
85221308Sache	  rl_numeric_arg *= 4;
85321308Sache	  continue;
85421308Sache	}
85521308Sache
85621308Sache      c = UNMETA (c);
85721308Sache      if (_rl_digit_p (c))
85821308Sache	{
85921308Sache	  if (rl_explicit_arg)
86021308Sache	    rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c);
86121308Sache	  else
86221308Sache	    rl_numeric_arg = _rl_digit_value (c);
86321308Sache	  rl_explicit_arg = 1;
86421308Sache	}
86521308Sache      else
86621308Sache	{
86721308Sache	  rl_clear_message ();
86821308Sache	  rl_stuff_char (key);
86921308Sache	  break;
87021308Sache	}
87121308Sache    }
87221308Sache  return (0);
87321308Sache}
87421308Sache
87521308Sacheint
87621308Sacherl_vi_delete_to (count, key)
87721308Sache     int count, key;
87821308Sache{
87921308Sache  int c;
88021308Sache
88121308Sache  if (_rl_uppercase_p (key))
88221308Sache    rl_stuff_char ('$');
88321308Sache  else if (vi_redoing)
88421308Sache    rl_stuff_char (_rl_vi_last_motion);
88521308Sache
88621308Sache  if (rl_vi_domove (key, &c))
88721308Sache    {
88821308Sache      ding ();
88921308Sache      return -1;
89021308Sache    }
89121308Sache
89221308Sache  /* These are the motion commands that do not require adjusting the
89321308Sache     mark. */
89421308Sache  if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
89521308Sache    rl_mark++;
89621308Sache
89721308Sache  rl_kill_text (rl_point, rl_mark);
89821308Sache  return (0);
89921308Sache}
90021308Sache
90121308Sacheint
90221308Sacherl_vi_change_to (count, key)
90321308Sache     int count, key;
90421308Sache{
90521308Sache  int c, start_pos;
90621308Sache
90721308Sache  if (_rl_uppercase_p (key))
90821308Sache    rl_stuff_char ('$');
90921308Sache  else if (vi_redoing)
91021308Sache    rl_stuff_char (_rl_vi_last_motion);
91121308Sache
91221308Sache  start_pos = rl_point;
91321308Sache
91421308Sache  if (rl_vi_domove (key, &c))
91521308Sache    {
91621308Sache      ding ();
91721308Sache      return -1;
91821308Sache    }
91921308Sache
92021308Sache  /* These are the motion commands that do not require adjusting the
92121308Sache     mark.  c[wW] are handled by special-case code in rl_vi_domove(),
92221308Sache     and already leave the mark at the correct location. */
92321308Sache  if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
92421308Sache    rl_mark++;
92521308Sache
92621308Sache  /* The cursor never moves with c[wW]. */
92721308Sache  if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
92821308Sache    rl_point = start_pos;
92921308Sache
93021308Sache  if (vi_redoing)
93121308Sache    {
93221308Sache      if (vi_insert_buffer && *vi_insert_buffer)
93321308Sache	rl_begin_undo_group ();
93421308Sache      rl_delete_text (rl_point, rl_mark);
93521308Sache      if (vi_insert_buffer && *vi_insert_buffer)
93621308Sache	{
93721308Sache	  rl_insert_text (vi_insert_buffer);
93821308Sache	  rl_end_undo_group ();
93921308Sache	}
94021308Sache    }
94121308Sache  else
94221308Sache    {
94321308Sache      rl_begin_undo_group ();		/* to make the `u' command work */
94421308Sache      rl_kill_text (rl_point, rl_mark);
94521308Sache      /* `C' does not save the text inserted for undoing or redoing. */
94621308Sache      if (_rl_uppercase_p (key) == 0)
94721308Sache        _rl_vi_doing_insert = 1;
94821308Sache      _rl_vi_set_last (key, count, rl_arg_sign);
94921308Sache      rl_vi_insertion_mode (1, key);
95021308Sache    }
95121308Sache
95221308Sache  return (0);
95321308Sache}
95421308Sache
95521308Sacheint
95621308Sacherl_vi_yank_to (count, key)
95721308Sache     int count, key;
95821308Sache{
95921308Sache  int c, save = rl_point;
96021308Sache
96121308Sache  if (_rl_uppercase_p (key))
96221308Sache    rl_stuff_char ('$');
96321308Sache
96421308Sache  if (rl_vi_domove (key, &c))
96521308Sache    {
96621308Sache      ding ();
96721308Sache      return -1;
96821308Sache    }
96921308Sache
97021308Sache  /* These are the motion commands that do not require adjusting the
97121308Sache     mark. */
97221308Sache  if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
97321308Sache    rl_mark++;
97421308Sache
97521308Sache  rl_begin_undo_group ();
97621308Sache  rl_kill_text (rl_point, rl_mark);
97721308Sache  rl_end_undo_group ();
97821308Sache  rl_do_undo ();
97921308Sache  rl_point = save;
98021308Sache
98121308Sache  return (0);
98221308Sache}
98321308Sache
98421308Sacheint
98521308Sacherl_vi_delete (count, key)
98621308Sache     int count, key;
98721308Sache{
98821308Sache  int end;
98921308Sache
99021308Sache  if (rl_end == 0)
99121308Sache    {
99221308Sache      ding ();
99321308Sache      return -1;
99421308Sache    }
99521308Sache
99621308Sache  end = rl_point + count;
99721308Sache
99821308Sache  if (end >= rl_end)
99921308Sache    end = rl_end;
100021308Sache
100121308Sache  rl_kill_text (rl_point, end);
100221308Sache
100321308Sache  if (rl_point > 0 && rl_point == rl_end)
100421308Sache    rl_backward (1, key);
100521308Sache  return (0);
100621308Sache}
100721308Sache
100821308Sacheint
100921308Sacherl_vi_back_to_indent (count, key)
101021308Sache     int count, key;
101121308Sache{
101221308Sache  rl_beg_of_line (1, key);
101321308Sache  while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
101421308Sache    rl_point++;
101521308Sache  return (0);
101621308Sache}
101721308Sache
101821308Sacheint
101921308Sacherl_vi_first_print (count, key)
102021308Sache     int count, key;
102121308Sache{
102221308Sache  return (rl_vi_back_to_indent (1, key));
102321308Sache}
102421308Sache
102521308Sacheint
102621308Sacherl_vi_char_search (count, key)
102721308Sache     int count, key;
102821308Sache{
102921308Sache  static char target;
103021308Sache  static int orig_dir, dir;
103121308Sache
103221308Sache  if (key == ';' || key == ',')
103321308Sache    dir = key == ';' ? orig_dir : -orig_dir;
103421308Sache  else
103521308Sache    {
103621308Sache      if (vi_redoing)
103721308Sache	target = _rl_vi_last_search_char;
103821308Sache      else
103921308Sache	_rl_vi_last_search_char = target = rl_getc (rl_instream);
104021308Sache
104121308Sache      switch (key)
104221308Sache        {
104321308Sache        case 't':
104421308Sache          orig_dir = dir = FTO;
104521308Sache          break;
104621308Sache
104721308Sache        case 'T':
104821308Sache          orig_dir = dir = BTO;
104921308Sache          break;
105021308Sache
105121308Sache        case 'f':
105221308Sache          orig_dir = dir = FFIND;
105321308Sache          break;
105421308Sache
105521308Sache        case 'F':
105621308Sache          orig_dir = dir = BFIND;
105721308Sache          break;
105821308Sache        }
105921308Sache    }
106021308Sache
106121308Sache  return (_rl_char_search_internal (count, dir, target));
106221308Sache}
106321308Sache
106421308Sache/* Match brackets */
106521308Sacheint
106621308Sacherl_vi_match (ignore, key)
106721308Sache     int ignore, key;
106821308Sache{
106921308Sache  int count = 1, brack, pos;
107021308Sache
107121308Sache  pos = rl_point;
107221308Sache  if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
107321308Sache    {
107421308Sache      while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
107521308Sache	     rl_point < rl_end - 1)
107621308Sache	rl_forward (1, key);
107721308Sache
107821308Sache      if (brack <= 0)
107921308Sache	{
108021308Sache	  rl_point = pos;
108121308Sache	  ding ();
108221308Sache	  return -1;
108321308Sache	}
108421308Sache    }
108521308Sache
108621308Sache  pos = rl_point;
108721308Sache
108821308Sache  if (brack < 0)
108921308Sache    {
109021308Sache      while (count)
109121308Sache	{
109221308Sache	  if (--pos >= 0)
109321308Sache	    {
109421308Sache	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
109521308Sache	      if (b == -brack)
109621308Sache		count--;
109721308Sache	      else if (b == brack)
109821308Sache		count++;
109921308Sache	    }
110021308Sache	  else
110121308Sache	    {
110221308Sache	      ding ();
110321308Sache	      return -1;
110421308Sache	    }
110521308Sache	}
110621308Sache    }
110721308Sache  else
110821308Sache    {			/* brack > 0 */
110921308Sache      while (count)
111021308Sache	{
111121308Sache	  if (++pos < rl_end)
111221308Sache	    {
111321308Sache	      int b = rl_vi_bracktype (rl_line_buffer[pos]);
111421308Sache	      if (b == -brack)
111521308Sache		count--;
111621308Sache	      else if (b == brack)
111721308Sache		count++;
111821308Sache	    }
111921308Sache	  else
112021308Sache	    {
112121308Sache	      ding ();
112221308Sache	      return -1;
112321308Sache	    }
112421308Sache	}
112521308Sache    }
112621308Sache  rl_point = pos;
112721308Sache  return (0);
112821308Sache}
112921308Sache
113021308Sacheint
113121308Sacherl_vi_bracktype (c)
113221308Sache     int c;
113321308Sache{
113421308Sache  switch (c)
113521308Sache    {
113621308Sache    case '(': return  1;
113721308Sache    case ')': return -1;
113821308Sache    case '[': return  2;
113921308Sache    case ']': return -2;
114021308Sache    case '{': return  3;
114121308Sache    case '}': return -3;
114221308Sache    default:  return  0;
114321308Sache    }
114421308Sache}
114521308Sache
114621308Sacheint
114721308Sacherl_vi_change_char (count, key)
114821308Sache     int count, key;
114921308Sache{
115021308Sache  int c;
115121308Sache
115221308Sache  if (vi_redoing)
115321308Sache    c = _rl_vi_last_replacement;
115421308Sache  else
115521308Sache    _rl_vi_last_replacement = c = rl_getc (rl_instream);
115621308Sache
115721308Sache  if (c == '\033' || c == CTRL ('C'))
115821308Sache    return -1;
115921308Sache
116021308Sache  while (count-- && rl_point < rl_end)
116121308Sache    {
116221308Sache      rl_begin_undo_group ();
116321308Sache
116421308Sache      rl_delete (1, c);
116521308Sache      rl_insert (1, c);
116621308Sache      if (count == 0)
116721308Sache	rl_backward (1, c);
116821308Sache
116921308Sache      rl_end_undo_group ();
117021308Sache    }
117121308Sache  return (0);
117221308Sache}
117321308Sache
117421308Sacheint
117521308Sacherl_vi_subst (count, key)
117621308Sache     int count, key;
117721308Sache{
117821308Sache  rl_begin_undo_group ();
117921308Sache
118021308Sache  if (_rl_uppercase_p (key))
118121308Sache    {
118221308Sache      rl_beg_of_line (1, key);
118321308Sache      rl_kill_line (1, key);
118421308Sache    }
118521308Sache  else
118621308Sache    rl_delete_text (rl_point, rl_point+count);
118721308Sache
118821308Sache  rl_end_undo_group ();
118921308Sache
119021308Sache  _rl_vi_set_last (key, count, rl_arg_sign);
119121308Sache
119221308Sache  if (vi_redoing)
119321308Sache    {
119421308Sache      int o = _rl_doing_an_undo;
119521308Sache
119621308Sache      _rl_doing_an_undo = 1;
119721308Sache      if (vi_insert_buffer && *vi_insert_buffer)
119821308Sache	rl_insert_text (vi_insert_buffer);
119921308Sache      _rl_doing_an_undo = o;
120021308Sache    }
120121308Sache  else
120221308Sache    {
120321308Sache      rl_begin_undo_group ();
120421308Sache      _rl_vi_doing_insert = 1;
120521308Sache      rl_vi_insertion_mode (1, key);
120621308Sache    }
120721308Sache
120821308Sache  return (0);
120921308Sache}
121021308Sache
121121308Sacheint
121221308Sacherl_vi_overstrike (count, key)
121321308Sache     int count, key;
121421308Sache{
121521308Sache  int i;
121621308Sache
121721308Sache  if (_rl_vi_doing_insert == 0)
121821308Sache    {
121921308Sache      _rl_vi_doing_insert = 1;
122021308Sache      rl_begin_undo_group ();
122121308Sache    }
122221308Sache
122321308Sache  for (i = 0; i < count; i++)
122421308Sache    {
122521308Sache      vi_replace_count++;
122621308Sache      rl_begin_undo_group ();
122721308Sache
122821308Sache      if (rl_point < rl_end)
122921308Sache	{
123021308Sache	  rl_delete (1, key);
123121308Sache	  rl_insert (1, key);
123221308Sache	}
123321308Sache      else
123421308Sache	rl_insert (1, key);
123521308Sache
123621308Sache      rl_end_undo_group ();
123721308Sache    }
123821308Sache  return (0);
123921308Sache}
124021308Sache
124121308Sacheint
124221308Sacherl_vi_overstrike_delete (count, key)
124321308Sache     int count, key;
124421308Sache{
124521308Sache  int i, s;
124621308Sache
124721308Sache  for (i = 0; i < count; i++)
124821308Sache    {
124921308Sache      if (vi_replace_count == 0)
125021308Sache	{
125121308Sache	  ding ();
125221308Sache	  break;
125321308Sache	}
125421308Sache      s = rl_point;
125521308Sache
125621308Sache      if (rl_do_undo ())
125721308Sache	vi_replace_count--;
125821308Sache
125921308Sache      if (rl_point == s)
126021308Sache	rl_backward (1, key);
126121308Sache    }
126221308Sache
126321308Sache  if (vi_replace_count == 0 && _rl_vi_doing_insert)
126421308Sache    {
126521308Sache      rl_end_undo_group ();
126621308Sache      rl_do_undo ();
126721308Sache      _rl_vi_doing_insert = 0;
126821308Sache    }
126921308Sache  return (0);
127021308Sache}
127121308Sache
127221308Sacheint
127321308Sacherl_vi_replace (count, key)
127421308Sache     int count, key;
127521308Sache{
127621308Sache  int i;
127721308Sache
127821308Sache  vi_replace_count = 0;
127921308Sache
128021308Sache  if (!vi_replace_map)
128121308Sache    {
128221308Sache      vi_replace_map = rl_make_bare_keymap ();
128321308Sache
128421308Sache      for (i = ' '; i < KEYMAP_SIZE; i++)
128521308Sache	vi_replace_map[i].function = rl_vi_overstrike;
128621308Sache
128721308Sache      vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
128821308Sache      vi_replace_map[ESC].function = rl_vi_movement_mode;
128921308Sache      vi_replace_map[RETURN].function = rl_newline;
129021308Sache      vi_replace_map[NEWLINE].function = rl_newline;
129121308Sache
129221308Sache      /* If the normal vi insertion keymap has ^H bound to erase, do the
129321308Sache         same here.  Probably should remove the assignment to RUBOUT up
129421308Sache         there, but I don't think it will make a difference in real life. */
129521308Sache      if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC &&
129621308Sache	  vi_insertion_keymap[CTRL ('H')].function == rl_rubout)
129721308Sache	vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete;
129821308Sache
129921308Sache    }
130021308Sache  _rl_keymap = vi_replace_map;
130121308Sache  return (0);
130221308Sache}
130321308Sache
130421308Sache#if 0
130521308Sache/* Try to complete the word we are standing on or the word that ends with
130621308Sache   the previous character.  A space matches everything.  Word delimiters are
130721308Sache   space and ;. */
130821308Sacheint
130921308Sacherl_vi_possible_completions()
131021308Sache{
131121308Sache  int save_pos = rl_point;
131221308Sache
131321308Sache  if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';')
131421308Sache    {
131521308Sache      while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' &&
131621308Sache	     rl_line_buffer[rl_point] != ';')
131721308Sache	rl_point++;
131821308Sache    }
131921308Sache  else if (rl_line_buffer[rl_point - 1] == ';')
132021308Sache    {
132121308Sache      ding ();
132221308Sache      return (0);
132321308Sache    }
132421308Sache
132521308Sache  rl_possible_completions ();
132621308Sache  rl_point = save_pos;
132721308Sache
132821308Sache  return (0);
132921308Sache}
133021308Sache#endif
133121308Sache
133221308Sache/* Functions to save and restore marks. */
133321308Sacheint
133421308Sacherl_vi_set_mark (count, key)
133521308Sache     int count, key;
133621308Sache{
133721308Sache  int ch;
133821308Sache
133921308Sache  ch = rl_read_key ();
134021308Sache  if (_rl_lowercase_p (ch) == 0)
134121308Sache    {
134221308Sache      ding ();
134321308Sache      return -1;
134421308Sache    }
134521308Sache  ch -= 'a';
134621308Sache  vi_mark_chars[ch] = rl_point;
134721308Sache  return 0;
134821308Sache}
134921308Sache
135021308Sacheint
135121308Sacherl_vi_goto_mark (count, key)
135221308Sache     int count, key;
135321308Sache{
135421308Sache  int ch;
135521308Sache
135621308Sache  ch = rl_read_key ();
135721308Sache  if (ch == '`')
135821308Sache    {
135921308Sache      rl_point = rl_mark;
136021308Sache      return 0;
136121308Sache    }
136221308Sache  else if (_rl_lowercase_p (ch) == 0)
136321308Sache    {
136421308Sache      ding ();
136521308Sache      return -1;
136621308Sache    }
136721308Sache
136821308Sache  ch -= 'a';
136921308Sache  if (vi_mark_chars[ch] == -1)
137021308Sache    {
137121308Sache      ding ();
137221308Sache      return -1;
137321308Sache    }
137421308Sache  rl_point = vi_mark_chars[ch];
137521308Sache  return 0;
137621308Sache}
137721308Sache
137821308Sache#endif /* VI_MODE */
1379