|
|
|
@ -1,14 +1,83 @@ |
|
|
|
/* vi_mode.c -- A vi emulation mode for Bash.
|
|
|
|
Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ |
|
|
|
|
|
|
|
Derived from code written by Jeff Sparkes (jeff1@????). |
|
|
|
*/ |
|
|
|
/* Copyright (C) 1988, 1991 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
This file is part of the GNU Readline Library (the Library), a set of |
|
|
|
routines for providing Emacs style line input to programs that ask |
|
|
|
for it. |
|
|
|
|
|
|
|
The Library is free software; you can redistribute it and/or modify |
|
|
|
it under the terms of the GNU General Public License as published by |
|
|
|
the Free Software Foundation; either version 1, or (at your option) |
|
|
|
any later version. |
|
|
|
|
|
|
|
The Library is distributed in the hope that it will be useful, but |
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
|
|
General Public License for more details. |
|
|
|
|
|
|
|
The GNU General Public License is often shipped with GNU software, and |
|
|
|
is generally kept in a file called COPYING or LICENSE. If you do not |
|
|
|
have a copy of the license, write to the Free Software Foundation, |
|
|
|
675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
|
|
|
|
|
/* **************************************************************** */ |
|
|
|
/* */ |
|
|
|
/* VI Emulation Mode */ |
|
|
|
/* */ |
|
|
|
/* **************************************************************** */ |
|
|
|
#if defined (VI_MODE) |
|
|
|
|
|
|
|
#include <stdio.h> |
|
|
|
|
|
|
|
#if defined (__GNUC__) |
|
|
|
# define alloca __builtin_alloca |
|
|
|
#else |
|
|
|
# if defined (sparc) || defined (HAVE_ALLOCA_H) |
|
|
|
# include <alloca.h> |
|
|
|
# endif |
|
|
|
#endif |
|
|
|
|
|
|
|
/* Some standard library routines. */ |
|
|
|
#include "readline.h" |
|
|
|
#include "history.h" |
|
|
|
|
|
|
|
#ifndef digit |
|
|
|
#define digit(c) ((c) >= '0' && (c) <= '9') |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifndef isletter |
|
|
|
#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z')) |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifndef digit_value |
|
|
|
#define digit_value(c) ((c) - '0') |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifndef member |
|
|
|
#define member(c, s) ((c) ? index ((s), (c)) : 0) |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifndef isident |
|
|
|
#define isident(c) ((isletter(c) || digit(c) || c == '_')) |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifndef exchange |
|
|
|
#define exchange(x, y) {int temp = x; x = y; y = temp;} |
|
|
|
#endif |
|
|
|
|
|
|
|
/* Variables imported from readline.c */ |
|
|
|
extern int rl_point, rl_end, rl_mark, rl_done; |
|
|
|
extern FILE *rl_instream; |
|
|
|
extern int rl_line_buffer_len, rl_explicit_arg, rl_numeric_arg; |
|
|
|
extern Keymap keymap; |
|
|
|
extern char *rl_prompt; |
|
|
|
extern char *rl_line_buffer; |
|
|
|
extern int rl_arg_sign; |
|
|
|
|
|
|
|
extern char *xmalloc (), *xrealloc (); |
|
|
|
extern void rl_extend_line_buffer (); |
|
|
|
|
|
|
|
/* Last string searched for from `/' or `?'. */ |
|
|
|
static char *vi_last_search = (char *)NULL; |
|
|
|
@ -17,6 +86,9 @@ static int vi_histpos; |
|
|
|
/* Non-zero means enter insertion mode. */ |
|
|
|
int vi_doing_insert = 0; |
|
|
|
|
|
|
|
/* String inserted into the line by rl_vi_comment (). */ |
|
|
|
char *rl_vi_comment_begin = (char *)NULL; |
|
|
|
|
|
|
|
/* *** UNCLEAN *** */ |
|
|
|
/* Command keys which do movement for xxx_to commands. */ |
|
|
|
static char *vi_motion = " hl^$0ftFt;,%wbeWBE|"; |
|
|
|
@ -26,13 +98,43 @@ static char *vi_motion = " hl^$0ftFt;,%wbeWBE|"; |
|
|
|
static Keymap vi_replace_map = (Keymap)NULL; |
|
|
|
|
|
|
|
/* The number of characters inserted in the last replace operation. */ |
|
|
|
static vi_replace_count = 0; |
|
|
|
static int vi_replace_count = 0; |
|
|
|
|
|
|
|
/* Yank the nth arg from the previous line into this line at point. */ |
|
|
|
rl_vi_yank_arg (count) |
|
|
|
int count; |
|
|
|
{ |
|
|
|
rl_yank_nth_arg (count, 0); |
|
|
|
/* Readline thinks that the first word on a line is the 0th, while vi
|
|
|
|
thinks the first word on a line is the 1st. Compensate. */ |
|
|
|
if (rl_explicit_arg) |
|
|
|
rl_yank_nth_arg (count - 1, 0); |
|
|
|
else |
|
|
|
rl_yank_nth_arg ('$', 0); |
|
|
|
} |
|
|
|
|
|
|
|
/* With an argument, move back that many history lines, else move to the
|
|
|
|
beginning of history. */ |
|
|
|
rl_vi_fetch_history (count, c) |
|
|
|
int count, c; |
|
|
|
{ |
|
|
|
extern int rl_explicit_arg; |
|
|
|
int current = where_history (); |
|
|
|
|
|
|
|
/* Giving an argument of n means we want the nth command in the history
|
|
|
|
file. The command number is interpreted the same way that the bash |
|
|
|
`history' command does it -- that is, giving an argument count of 450 |
|
|
|
to this command would get the command listed as number 450 in the |
|
|
|
output of `history'. */ |
|
|
|
if (rl_explicit_arg) |
|
|
|
{ |
|
|
|
int wanted = history_base + current - count; |
|
|
|
if (wanted <= 0) |
|
|
|
rl_beginning_of_history (0, 0); |
|
|
|
else |
|
|
|
rl_get_previous_history (wanted); |
|
|
|
} |
|
|
|
else |
|
|
|
rl_beginning_of_history (count, 0); |
|
|
|
} |
|
|
|
|
|
|
|
/* Search again for the last thing searched for. */ |
|
|
|
@ -78,7 +180,7 @@ rl_vi_search (count, key) |
|
|
|
save_pos = rl_point; |
|
|
|
|
|
|
|
/* Reuse the line input buffer to read the search string. */ |
|
|
|
the_line[0] = 0; |
|
|
|
rl_line_buffer[0] = 0; |
|
|
|
rl_end = rl_point = 0; |
|
|
|
p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0)); |
|
|
|
|
|
|
|
@ -128,8 +230,38 @@ rl_vi_search (count, key) |
|
|
|
if (vi_last_search) |
|
|
|
free (vi_last_search); |
|
|
|
|
|
|
|
vi_last_search = savestring (the_line); |
|
|
|
rl_vi_dosearch (the_line, dir); |
|
|
|
vi_last_search = savestring (rl_line_buffer); |
|
|
|
rl_vi_dosearch (rl_line_buffer, dir); |
|
|
|
} |
|
|
|
|
|
|
|
/* Search for STRING in the history list. DIR is < 0 for searching
|
|
|
|
backwards. POS is an absolute index into the history list at |
|
|
|
which point to begin searching. If the first character of STRING |
|
|
|
is `^', the string must match a prefix of a history line, otherwise |
|
|
|
a full substring match is performed. */ |
|
|
|
static int |
|
|
|
vi_history_search_pos (string, dir, pos) |
|
|
|
char *string; |
|
|
|
int dir, pos; |
|
|
|
{ |
|
|
|
int ret, old = where_history (); |
|
|
|
|
|
|
|
history_set_pos (pos); |
|
|
|
|
|
|
|
if (*string == '^') |
|
|
|
ret = history_search_prefix (string + 1, dir); |
|
|
|
else |
|
|
|
ret = history_search (string, dir); |
|
|
|
|
|
|
|
if (ret == -1) |
|
|
|
{ |
|
|
|
history_set_pos (old); |
|
|
|
return (-1); |
|
|
|
} |
|
|
|
|
|
|
|
ret = where_history (); |
|
|
|
history_set_pos (old); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
rl_vi_dosearch (string, dir) |
|
|
|
@ -145,7 +277,7 @@ rl_vi_dosearch (string, dir) |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if ((save = history_search_pos (string, dir, vi_histpos + dir)) == -1) |
|
|
|
if ((save = vi_history_search_pos (string, dir, vi_histpos + dir)) == -1) |
|
|
|
{ |
|
|
|
maybe_unsave_line (); |
|
|
|
rl_clear_message (); |
|
|
|
@ -161,9 +293,16 @@ rl_vi_dosearch (string, dir) |
|
|
|
h = current_history (); |
|
|
|
history_set_pos (old); |
|
|
|
|
|
|
|
strcpy (the_line, h->line); |
|
|
|
{ |
|
|
|
int line_len = strlen (h->line); |
|
|
|
|
|
|
|
if (line_len >= rl_line_buffer_len) |
|
|
|
rl_extend_line_buffer (line_len); |
|
|
|
strcpy (rl_line_buffer, h->line); |
|
|
|
} |
|
|
|
|
|
|
|
rl_undo_list = (UNDO_LIST *)h->data; |
|
|
|
rl_end = strlen (the_line); |
|
|
|
rl_end = strlen (rl_line_buffer); |
|
|
|
rl_point = 0; |
|
|
|
rl_clear_message (); |
|
|
|
} |
|
|
|
@ -172,19 +311,21 @@ rl_vi_dosearch (string, dir) |
|
|
|
rl_vi_complete (ignore, key) |
|
|
|
int ignore, key; |
|
|
|
{ |
|
|
|
if (!whitespace (the_line[rl_point])) |
|
|
|
if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) |
|
|
|
{ |
|
|
|
if (!whitespace (the_line[rl_point + 1])) |
|
|
|
if (!whitespace (rl_line_buffer[rl_point + 1])) |
|
|
|
rl_vi_end_word (1, 'E'); |
|
|
|
rl_point++; |
|
|
|
} |
|
|
|
|
|
|
|
if (key == '*') |
|
|
|
rl_complete_internal ('*'); |
|
|
|
rl_complete_internal ('*'); /* Expansion and replacement. */ |
|
|
|
else if (key == '=') |
|
|
|
rl_complete_internal ('?'); /* List possible completions. */ |
|
|
|
else if (key == '\\') |
|
|
|
rl_complete_internal (TAB); /* Standard Readline completion. */ |
|
|
|
else |
|
|
|
rl_complete (0, key); |
|
|
|
|
|
|
|
rl_vi_insertion_mode (); |
|
|
|
} |
|
|
|
|
|
|
|
/* Previous word in vi mode. */ |
|
|
|
@ -197,6 +338,12 @@ rl_vi_prev_word (count, key) |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (rl_point == 0) |
|
|
|
{ |
|
|
|
ding (); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (uppercase_p (key)) |
|
|
|
rl_vi_bWord (count); |
|
|
|
else |
|
|
|
@ -213,6 +360,12 @@ rl_vi_next_word (count, key) |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (rl_point >= (rl_end - 1)) |
|
|
|
{ |
|
|
|
ding (); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (uppercase_p (key)) |
|
|
|
rl_vi_fWord (count); |
|
|
|
else |
|
|
|
@ -242,11 +395,11 @@ rl_vi_fWord (count) |
|
|
|
while (count-- && rl_point < (rl_end - 1)) |
|
|
|
{ |
|
|
|
/* Skip until whitespace. */ |
|
|
|
while (!whitespace (the_line[rl_point]) && rl_point < rl_end) |
|
|
|
while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) |
|
|
|
rl_point++; |
|
|
|
|
|
|
|
/* Now skip whitespace. */ |
|
|
|
while (whitespace (the_line[rl_point]) && rl_point < rl_end) |
|
|
|
while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) |
|
|
|
rl_point++; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -256,42 +409,71 @@ rl_vi_bWord (count) |
|
|
|
{ |
|
|
|
while (count-- && rl_point > 0) |
|
|
|
{ |
|
|
|
while (rl_point-- >= 0 && whitespace (the_line[rl_point])); |
|
|
|
while (rl_point >= 0 && !whitespace (the_line[rl_point])) |
|
|
|
/* If we are at the start of a word, move back to whitespace so
|
|
|
|
we will go back to the start of the previous word. */ |
|
|
|
if (!whitespace (rl_line_buffer[rl_point]) && |
|
|
|
whitespace (rl_line_buffer[rl_point - 1])) |
|
|
|
rl_point--; |
|
|
|
rl_point++; |
|
|
|
|
|
|
|
while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) |
|
|
|
rl_point--; |
|
|
|
|
|
|
|
if (rl_point > 0) |
|
|
|
{ |
|
|
|
while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); |
|
|
|
rl_point++; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
rl_vi_eWord (count) |
|
|
|
int count; |
|
|
|
{ |
|
|
|
while (count -- && rl_point < (rl_end - 1)) |
|
|
|
while (count-- && rl_point < (rl_end - 1)) |
|
|
|
{ |
|
|
|
while (rl_point++ < rl_end && whitespace (the_line[rl_point])); |
|
|
|
while (rl_point++ < rl_end && !whitespace (the_line[rl_point])); |
|
|
|
rl_point--; |
|
|
|
if (!whitespace (rl_line_buffer[rl_point])) |
|
|
|
rl_point++; |
|
|
|
|
|
|
|
/* Move to the next non-whitespace character (to the start of the
|
|
|
|
next word). */ |
|
|
|
while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point])); |
|
|
|
|
|
|
|
if (rl_point && rl_point < rl_end) |
|
|
|
{ |
|
|
|
/* Skip whitespace. */ |
|
|
|
while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) |
|
|
|
rl_point++; |
|
|
|
|
|
|
|
/* Skip until whitespace. */ |
|
|
|
while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) |
|
|
|
rl_point++; |
|
|
|
|
|
|
|
/* Move back to the last character of the word. */ |
|
|
|
rl_point--; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
rl_vi_fword (count) |
|
|
|
int count; |
|
|
|
{ |
|
|
|
while (count -- && rl_point < (rl_end - 1)) |
|
|
|
while (count-- && rl_point < (rl_end - 1)) |
|
|
|
{ |
|
|
|
if (isident (the_line[rl_point])) |
|
|
|
/* Move to white space (really non-identifer). */ |
|
|
|
if (isident (rl_line_buffer[rl_point])) |
|
|
|
{ |
|
|
|
while (isident (the_line[rl_point]) && rl_point < rl_end) |
|
|
|
rl_point += 1; |
|
|
|
while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end) |
|
|
|
rl_point++; |
|
|
|
} |
|
|
|
else if (!whitespace (the_line[rl_point])) |
|
|
|
else /* if (!whitespace (rl_line_buffer[rl_point])) */ |
|
|
|
{ |
|
|
|
while (!isident (the_line[rl_point]) && |
|
|
|
!whitespace (the_line[rl_point]) && rl_point < rl_end) |
|
|
|
rl_point += 1; |
|
|
|
while (!isident (rl_line_buffer[rl_point]) && |
|
|
|
!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) |
|
|
|
rl_point++; |
|
|
|
} |
|
|
|
|
|
|
|
while (whitespace (the_line[rl_point]) && rl_point < rl_end) |
|
|
|
/* Move past whitespace. */ |
|
|
|
while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) |
|
|
|
rl_point++; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -299,16 +481,35 @@ rl_vi_fword (count) |
|
|
|
rl_vi_bword (count) |
|
|
|
int count; |
|
|
|
{ |
|
|
|
while (count -- && rl_point > 0) |
|
|
|
while (count-- && rl_point > 0) |
|
|
|
{ |
|
|
|
while (--rl_point > 0 && whitespace (the_line[rl_point])); |
|
|
|
int last_is_ident; |
|
|
|
|
|
|
|
/* If we are at the start of a word, move back to whitespace
|
|
|
|
so we will go back to the start of the previous word. */ |
|
|
|
if (!whitespace (rl_line_buffer[rl_point]) && |
|
|
|
whitespace (rl_line_buffer[rl_point - 1])) |
|
|
|
rl_point--; |
|
|
|
|
|
|
|
/* If this character and the previous character are `opposite', move
|
|
|
|
back so we don't get messed up by the rl_point++ down there in |
|
|
|
the while loop. Without this code, words like `l;' screw up the |
|
|
|
function. */ |
|
|
|
last_is_ident = isident (rl_line_buffer[rl_point - 1]); |
|
|
|
if ((isident (rl_line_buffer[rl_point]) && !last_is_ident) || |
|
|
|
(!isident (rl_line_buffer[rl_point]) && last_is_ident)) |
|
|
|
rl_point--; |
|
|
|
|
|
|
|
while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) |
|
|
|
rl_point--; |
|
|
|
|
|
|
|
if (rl_point > 0) |
|
|
|
{ |
|
|
|
if (isident (the_line[rl_point])) |
|
|
|
while (--rl_point >= 0 && isident (the_line[rl_point])); |
|
|
|
if (isident (rl_line_buffer[rl_point])) |
|
|
|
while (--rl_point >= 0 && isident (rl_line_buffer[rl_point])); |
|
|
|
else |
|
|
|
while (--rl_point >= 0 && !isident (the_line[rl_point]) && |
|
|
|
!whitespace (the_line[rl_point])); |
|
|
|
while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) && |
|
|
|
!whitespace (rl_line_buffer[rl_point])); |
|
|
|
rl_point++; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -317,19 +518,23 @@ rl_vi_bword (count) |
|
|
|
rl_vi_eword (count) |
|
|
|
int count; |
|
|
|
{ |
|
|
|
while (count -- && rl_point < rl_end - 1) |
|
|
|
while (count-- && rl_point < rl_end - 1) |
|
|
|
{ |
|
|
|
while (++rl_point < rl_end && whitespace (the_line[rl_point])); |
|
|
|
if (!whitespace (rl_line_buffer[rl_point])) |
|
|
|
rl_point++; |
|
|
|
|
|
|
|
while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) |
|
|
|
rl_point++; |
|
|
|
|
|
|
|
if (rl_point < rl_end) |
|
|
|
{ |
|
|
|
if (isident (the_line[rl_point])) |
|
|
|
while (++rl_point < rl_end && isident (the_line[rl_point])); |
|
|
|
if (isident (rl_line_buffer[rl_point])) |
|
|
|
while (++rl_point < rl_end && isident (rl_line_buffer[rl_point])); |
|
|
|
else |
|
|
|
while (++rl_point < rl_end && !isident (the_line[rl_point]) |
|
|
|
&& !whitespace (the_line[rl_point])); |
|
|
|
rl_point--; |
|
|
|
while (++rl_point < rl_end && !isident (rl_line_buffer[rl_point]) |
|
|
|
&& !whitespace (rl_line_buffer[rl_point])); |
|
|
|
} |
|
|
|
rl_point--; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -398,35 +603,41 @@ rl_vi_arg_digit (count, c) |
|
|
|
rl_digit_argument (count, c); |
|
|
|
} |
|
|
|
|
|
|
|
/* Doesn't take an arg count in vi */ |
|
|
|
rl_vi_change_case (ignore1, ignore2) |
|
|
|
int ignore1, ignore2; |
|
|
|
rl_vi_change_case (count, ignore) |
|
|
|
int count, ignore; |
|
|
|
{ |
|
|
|
char c = 0; |
|
|
|
|
|
|
|
if (uppercase_p (the_line[rl_point])) |
|
|
|
c = to_lower (the_line[rl_point]); |
|
|
|
else if (lowercase_p (the_line[rl_point])) |
|
|
|
c = to_upper (the_line[rl_point]); |
|
|
|
/* Don't try this on an empty line. */ |
|
|
|
if (rl_point >= rl_end) |
|
|
|
return; |
|
|
|
|
|
|
|
/* Vi is kind of strange here. */ |
|
|
|
if (c) |
|
|
|
while (count-- && rl_point < rl_end) |
|
|
|
{ |
|
|
|
rl_begin_undo_group (); |
|
|
|
rl_delete (1, c); |
|
|
|
rl_insert (1, c); |
|
|
|
rl_end_undo_group (); |
|
|
|
rl_vi_check (); |
|
|
|
if (uppercase_p (rl_line_buffer[rl_point])) |
|
|
|
c = to_lower (rl_line_buffer[rl_point]); |
|
|
|
else if (lowercase_p (rl_line_buffer[rl_point])) |
|
|
|
c = to_upper (rl_line_buffer[rl_point]); |
|
|
|
|
|
|
|
/* Vi is kind of strange here. */ |
|
|
|
if (c) |
|
|
|
{ |
|
|
|
rl_begin_undo_group (); |
|
|
|
rl_delete (1, c); |
|
|
|
rl_insert (1, c); |
|
|
|
rl_end_undo_group (); |
|
|
|
rl_vi_check (); |
|
|
|
} |
|
|
|
else |
|
|
|
rl_forward (1); |
|
|
|
} |
|
|
|
else |
|
|
|
rl_forward (1); |
|
|
|
} |
|
|
|
|
|
|
|
rl_vi_put (count, key) |
|
|
|
int count, key; |
|
|
|
{ |
|
|
|
if (!uppercase_p (key)) |
|
|
|
rl_forward (1); |
|
|
|
if (!uppercase_p (key) && (rl_point + 1 <= rl_end)) |
|
|
|
rl_point++; |
|
|
|
|
|
|
|
rl_yank (); |
|
|
|
rl_backward (1); |
|
|
|
@ -451,6 +662,9 @@ rl_vi_domove (key, nextkey) |
|
|
|
int key, *nextkey; |
|
|
|
{ |
|
|
|
int c, save; |
|
|
|
int old_end, added_blank; |
|
|
|
|
|
|
|
added_blank = 0; |
|
|
|
|
|
|
|
rl_mark = rl_point; |
|
|
|
c = rl_read_key (); |
|
|
|
@ -461,10 +675,14 @@ rl_vi_domove (key, nextkey) |
|
|
|
if (digit (c)) |
|
|
|
{ |
|
|
|
save = rl_numeric_arg; |
|
|
|
rl_numeric_arg = digit_value (c); |
|
|
|
rl_digit_loop1 (); |
|
|
|
rl_numeric_arg *= save; |
|
|
|
c = rl_read_key (); /* real command */ |
|
|
|
*nextkey = c; |
|
|
|
} |
|
|
|
else if ((key == 'd' && c == 'd') || |
|
|
|
(key == 'y' && c == 'y') || |
|
|
|
(key == 'c' && c == 'c')) |
|
|
|
{ |
|
|
|
rl_mark = rl_end; |
|
|
|
@ -475,15 +693,41 @@ rl_vi_domove (key, nextkey) |
|
|
|
return (-1); |
|
|
|
} |
|
|
|
|
|
|
|
/* Append a blank character temporarily so that the motion routines
|
|
|
|
work right at the end of the line. */ |
|
|
|
old_end = rl_end; |
|
|
|
rl_line_buffer[rl_end++] = ' '; /* This looks pretty bogus to me??? */ |
|
|
|
rl_line_buffer[rl_end] = '\0'; |
|
|
|
added_blank++; |
|
|
|
|
|
|
|
rl_dispatch (c, keymap); |
|
|
|
|
|
|
|
/* Remove the blank that we added. */ |
|
|
|
rl_end = old_end; |
|
|
|
rl_line_buffer[rl_end] = '\0'; |
|
|
|
if (rl_point > rl_end) |
|
|
|
rl_point = rl_end - 1; |
|
|
|
|
|
|
|
/* No change in position means the command failed. */ |
|
|
|
if (rl_mark == rl_point) |
|
|
|
return (-1); |
|
|
|
|
|
|
|
if ((c == 'w' || c == 'W') && rl_point < rl_end) |
|
|
|
/* rl_vi_f[wW]ord () leaves the cursor on the first character of the next
|
|
|
|
word. If we are not at the end of the line, and we are on a |
|
|
|
non-whitespace character, move back one (presumably to whitespace). */ |
|
|
|
if ((c == 'w' || c == 'W') && (rl_point < rl_end) && |
|
|
|
!whitespace (rl_line_buffer[rl_point])) |
|
|
|
rl_point--; |
|
|
|
|
|
|
|
/* If cw or cW, back up to the end of a word, so the behaviour of ce
|
|
|
|
or cE is the actual result. Brute-force, no subtlety. Do the same |
|
|
|
thing for dw or dW. */ |
|
|
|
if (key == 'c' && (to_upper (c) == 'W')) |
|
|
|
{ |
|
|
|
while (rl_point && whitespace (rl_line_buffer[rl_point])) |
|
|
|
rl_point--; |
|
|
|
} |
|
|
|
|
|
|
|
if (rl_mark < rl_point) |
|
|
|
exchange (rl_point, rl_mark); |
|
|
|
|
|
|
|
@ -498,7 +742,7 @@ rl_digit_loop1 () |
|
|
|
|
|
|
|
while (1) |
|
|
|
{ |
|
|
|
rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg, 0); |
|
|
|
rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0); |
|
|
|
key = c = rl_read_key (); |
|
|
|
|
|
|
|
if (keymap[c].type == ISFUNC && |
|
|
|
@ -507,19 +751,21 @@ rl_digit_loop1 () |
|
|
|
rl_numeric_arg *= 4; |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
c = UNMETA (c); |
|
|
|
if (numeric (c)) |
|
|
|
{ |
|
|
|
if (rl_explicit_arg) |
|
|
|
rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0'); |
|
|
|
rl_numeric_arg = (rl_numeric_arg * 10) + digit_value (c); |
|
|
|
else |
|
|
|
rl_numeric_arg = (c - '0'); |
|
|
|
rl_numeric_arg = digit_value (c); |
|
|
|
rl_explicit_arg = 1; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
rl_clear_message (); |
|
|
|
rl_stuff_char (key); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -538,7 +784,7 @@ rl_vi_delete_to (count, key) |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if ((c != '|') && (c != 'h') && rl_mark < rl_end) |
|
|
|
if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end) |
|
|
|
rl_mark++; |
|
|
|
|
|
|
|
rl_kill_text (rl_point, rl_mark); |
|
|
|
@ -558,7 +804,7 @@ rl_vi_change_to (count, key) |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if ((c != '|') && (c != 'h') && rl_mark < rl_end) |
|
|
|
if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end) |
|
|
|
rl_mark++; |
|
|
|
|
|
|
|
rl_begin_undo_group (); |
|
|
|
@ -581,6 +827,9 @@ rl_vi_yank_to (count, key) |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if ((c != 'l') && (c != '|') && (c != 'h') && rl_mark < rl_end) |
|
|
|
rl_mark++; |
|
|
|
|
|
|
|
rl_begin_undo_group (); |
|
|
|
rl_kill_text (rl_point, rl_mark); |
|
|
|
rl_end_undo_group (); |
|
|
|
@ -590,21 +839,36 @@ rl_vi_yank_to (count, key) |
|
|
|
|
|
|
|
rl_vi_delete (count) |
|
|
|
{ |
|
|
|
if (rl_point >= rl_end - 1) |
|
|
|
int end; |
|
|
|
|
|
|
|
if (rl_end == 0) |
|
|
|
{ |
|
|
|
rl_delete (count, 0); |
|
|
|
if (rl_point > 0) |
|
|
|
rl_backward (1); |
|
|
|
ding (); |
|
|
|
return; |
|
|
|
} |
|
|
|
else |
|
|
|
rl_delete (count, 0); |
|
|
|
|
|
|
|
end = rl_point + count; |
|
|
|
|
|
|
|
if (end >= rl_end) |
|
|
|
end = rl_end; |
|
|
|
|
|
|
|
rl_kill_text (rl_point, end); |
|
|
|
|
|
|
|
if (rl_point > 0 && rl_point == rl_end) |
|
|
|
rl_backward (1); |
|
|
|
} |
|
|
|
|
|
|
|
/* Turn the current line into a comment in shell history. A ksh function */ |
|
|
|
/* Turn the current line into a comment in shell history.
|
|
|
|
A K*rn shell style function. */ |
|
|
|
rl_vi_comment () |
|
|
|
{ |
|
|
|
rl_beg_of_line (); |
|
|
|
rl_insert_text (": "); /* # doesn't work in interactive mode */ |
|
|
|
|
|
|
|
if (rl_vi_comment_begin != (char *)NULL) |
|
|
|
rl_insert_text (rl_vi_comment_begin); |
|
|
|
else |
|
|
|
rl_insert_text (": "); /* Default. */ |
|
|
|
|
|
|
|
rl_redisplay (); |
|
|
|
rl_newline (1, '\010'); |
|
|
|
} |
|
|
|
@ -618,7 +882,7 @@ rl_back_to_indent (ignore1, ignore2) |
|
|
|
int ignore1, ignore2; |
|
|
|
{ |
|
|
|
rl_beg_of_line (); |
|
|
|
while (rl_point < rl_end && whitespace (the_line[rl_point])) |
|
|
|
while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) |
|
|
|
rl_point++; |
|
|
|
} |
|
|
|
|
|
|
|
@ -639,70 +903,88 @@ rl_vi_char_search (count, key) |
|
|
|
dir = (key == ';' ? orig_dir : -orig_dir); |
|
|
|
else |
|
|
|
{ |
|
|
|
target = rl_getc (in_stream); |
|
|
|
target = rl_getc (rl_instream); |
|
|
|
|
|
|
|
switch (key) |
|
|
|
{ |
|
|
|
case 't': |
|
|
|
orig_dir = dir = FTO; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'T': |
|
|
|
orig_dir = dir = BTO; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'f': |
|
|
|
orig_dir = dir = FFIND; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'F': |
|
|
|
orig_dir = dir = BFIND; |
|
|
|
break; |
|
|
|
} |
|
|
|
{ |
|
|
|
case 't': |
|
|
|
orig_dir = dir = FTO; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'T': |
|
|
|
orig_dir = dir = BTO; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'f': |
|
|
|
orig_dir = dir = FFIND; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'F': |
|
|
|
orig_dir = dir = BFIND; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
pos = rl_point; |
|
|
|
|
|
|
|
if (dir < 0) |
|
|
|
while (count--) |
|
|
|
{ |
|
|
|
pos--; |
|
|
|
do |
|
|
|
if (dir < 0) |
|
|
|
{ |
|
|
|
if (the_line[pos] == target) |
|
|
|
if (pos == 0) |
|
|
|
{ |
|
|
|
if (dir == BTO) |
|
|
|
rl_point = pos + 1; |
|
|
|
else |
|
|
|
rl_point = pos; |
|
|
|
ding (); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
while (pos--); |
|
|
|
|
|
|
|
if (pos < 0) |
|
|
|
{ |
|
|
|
ding (); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ /* dir > 0 */ |
|
|
|
pos++; |
|
|
|
do |
|
|
|
{ |
|
|
|
if (the_line[pos] == target) |
|
|
|
pos--; |
|
|
|
do |
|
|
|
{ |
|
|
|
if (dir == FTO) |
|
|
|
rl_point = pos - 1; |
|
|
|
else |
|
|
|
rl_point = pos; |
|
|
|
if (rl_line_buffer[pos] == target) |
|
|
|
{ |
|
|
|
if (dir == BTO) |
|
|
|
rl_point = pos + 1; |
|
|
|
else |
|
|
|
rl_point = pos; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
while (pos--); |
|
|
|
|
|
|
|
if (pos < 0) |
|
|
|
{ |
|
|
|
ding (); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
while (++pos < rl_end); |
|
|
|
else |
|
|
|
{ /* dir > 0 */ |
|
|
|
if (pos >= rl_end) |
|
|
|
{ |
|
|
|
ding (); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (pos >= (rl_end - 1)) |
|
|
|
ding (); |
|
|
|
pos++; |
|
|
|
do |
|
|
|
{ |
|
|
|
if (rl_line_buffer[pos] == target) |
|
|
|
{ |
|
|
|
if (dir == FTO) |
|
|
|
rl_point = pos - 1; |
|
|
|
else |
|
|
|
rl_point = pos; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
while (++pos < rl_end); |
|
|
|
|
|
|
|
if (pos >= (rl_end - 1)) |
|
|
|
{ |
|
|
|
ding (); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -712,9 +994,9 @@ rl_vi_match () |
|
|
|
int count = 1, brack, pos; |
|
|
|
|
|
|
|
pos = rl_point; |
|
|
|
if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0) |
|
|
|
if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) |
|
|
|
{ |
|
|
|
while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 && |
|
|
|
while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && |
|
|
|
rl_point < rl_end - 1) |
|
|
|
rl_forward (1); |
|
|
|
|
|
|
|
@ -734,7 +1016,7 @@ rl_vi_match () |
|
|
|
{ |
|
|
|
if (--pos >= 0) |
|
|
|
{ |
|
|
|
int b = rl_vi_bracktype (the_line[pos]); |
|
|
|
int b = rl_vi_bracktype (rl_line_buffer[pos]); |
|
|
|
if (b == -brack) |
|
|
|
count--; |
|
|
|
else if (b == brack) |
|
|
|
@ -753,7 +1035,7 @@ rl_vi_match () |
|
|
|
{ |
|
|
|
if (++pos < rl_end) |
|
|
|
{ |
|
|
|
int b = rl_vi_bracktype (the_line[pos]); |
|
|
|
int b = rl_vi_bracktype (rl_line_buffer[pos]); |
|
|
|
if (b == -brack) |
|
|
|
count--; |
|
|
|
else if (b == brack) |
|
|
|
@ -785,24 +1067,26 @@ rl_vi_bracktype (c) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
rl_vi_change_char () |
|
|
|
rl_vi_change_char (count, key) |
|
|
|
int count, key; |
|
|
|
{ |
|
|
|
int c; |
|
|
|
|
|
|
|
c = rl_getc (in_stream); |
|
|
|
c = rl_getc (rl_instream); |
|
|
|
|
|
|
|
switch (c) |
|
|
|
{ |
|
|
|
case '\033': |
|
|
|
case CTRL('C'): |
|
|
|
return; |
|
|
|
if (c == '\033' || c == CTRL ('C')) |
|
|
|
return; |
|
|
|
|
|
|
|
default: |
|
|
|
while (count-- && rl_point < rl_end) |
|
|
|
{ |
|
|
|
rl_begin_undo_group (); |
|
|
|
|
|
|
|
rl_delete (1, c); |
|
|
|
rl_insert (1, c); |
|
|
|
if (count == 0) |
|
|
|
rl_backward (1); |
|
|
|
|
|
|
|
rl_end_undo_group (); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -818,7 +1102,7 @@ rl_vi_subst (count, key) |
|
|
|
rl_kill_line (1); |
|
|
|
} |
|
|
|
else |
|
|
|
rl_delete (1, key); |
|
|
|
rl_delete (count, key); |
|
|
|
|
|
|
|
rl_vi_insertion_mode (); |
|
|
|
} |
|
|
|
@ -880,21 +1164,33 @@ rl_vi_overstrike_delete (count) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
rl_vi_replace () |
|
|
|
rl_vi_replace (count, key) |
|
|
|
int count, key; |
|
|
|
{ |
|
|
|
int i; |
|
|
|
|
|
|
|
vi_replace_count = 0; |
|
|
|
|
|
|
|
vi_replace_map = rl_make_bare_keymap (); |
|
|
|
if (!vi_replace_map) |
|
|
|
{ |
|
|
|
vi_replace_map = rl_make_bare_keymap (); |
|
|
|
|
|
|
|
for (i = ' '; i < 127; i++) |
|
|
|
vi_replace_map[i].function = rl_vi_overstrike; |
|
|
|
for (i = ' '; i < 127; i++) |
|
|
|
vi_replace_map[i].function = rl_vi_overstrike; |
|
|
|
|
|
|
|
vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; |
|
|
|
vi_replace_map[ESC].function = rl_vi_movement_mode; |
|
|
|
vi_replace_map[RETURN].function = rl_newline; |
|
|
|
vi_replace_map[NEWLINE].function = rl_newline; |
|
|
|
vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; |
|
|
|
vi_replace_map[ESC].function = rl_vi_movement_mode; |
|
|
|
vi_replace_map[RETURN].function = rl_newline; |
|
|
|
vi_replace_map[NEWLINE].function = rl_newline; |
|
|
|
|
|
|
|
/* If the normal vi insertion keymap has ^H bound to erase, do the
|
|
|
|
same here. Probably should remove the assignment to RUBOUT up |
|
|
|
there, but I don't think it will make a difference in real life. */ |
|
|
|
if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && |
|
|
|
vi_insertion_keymap[CTRL ('H')].function == rl_rubout) |
|
|
|
vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; |
|
|
|
|
|
|
|
} |
|
|
|
keymap = vi_replace_map; |
|
|
|
} |
|
|
|
|
|
|
|
@ -907,12 +1203,12 @@ rl_vi_possible_completions() |
|
|
|
{ |
|
|
|
int save_pos = rl_point; |
|
|
|
|
|
|
|
if (!index (" ;", the_line[rl_point])) |
|
|
|
if (!index (" ;", rl_line_buffer[rl_point])) |
|
|
|
{ |
|
|
|
while (!index(" ;", the_line[++rl_point])) |
|
|
|
while (!index(" ;", rl_line_buffer[++rl_point])) |
|
|
|
; |
|
|
|
} |
|
|
|
else if (the_line[rl_point-1] == ';') |
|
|
|
else if (rl_line_buffer[rl_point-1] == ';') |
|
|
|
{ |
|
|
|
ding (); |
|
|
|
return (0); |
|
|
|
@ -923,3 +1219,5 @@ rl_vi_possible_completions() |
|
|
|
|
|
|
|
return (0); |
|
|
|
} |
|
|
|
|
|
|
|
#endif /* VI_MODE */ |
|
|
|
|