* This code is derived from software copyrighted by the Free Software
* Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
* Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
* @(#)vi_mode.c 6.4 (Berkeley) 5/8/91
/* vi_mode.c -- A vi emulation mode for Bash.
Mostly written by Jeff Sparkes (jeff1@????).
/* **************************************************************** */
/* **************************************************************** */
/* Last string searched for from `/' or `?'. */
static char *vi_last_search
= (char *)NULL
;
/* Command keys which do movement for xxx_to commands. */
static char *vi_motion
= " hl^$0ftFt;,%wbeWBE|";
/* Keymap used for vi replace characters. Created dynamically since
static Keymap vi_replace_map
= (Keymap
)NULL
;
/* The number of characters inserted in the last replace operation. */
static vi_replace_count
= 0;
/* Yank the nth arg from the previous line into this line at point. */
/* Search again for the last thing searched for. */
rl_vi_search_again (ignore
, key
)
rl_vi_dosearch (vi_last_search
, -1);
rl_vi_dosearch (vi_last_search
, 1);
/* Do a vi style search. */
rl_vi_search (count
, key
)
vi_histpos
= where_history ();
/* Reuse the line input buffer to read the search string. */
p
= (char *)alloca (2 + (rl_prompt
? strlen (rl_prompt
) : 0));
sprintf (p
, "%s%c", rl_prompt
? rl_prompt
: "", key
);
while (c
= rl_read_key (in_stream
))
vi_last_search
= savestring (the_line
);
rl_vi_dosearch (the_line
, dir
);
rl_vi_dosearch (string
, dir
)
int old
, save
= vi_histpos
;
if (string
== 0 || *string
== 0 || vi_histpos
< 0)
if ((save
= history_search_pos (string
, dir
, vi_histpos
+ dir
)) == -1)
history_set_pos (vi_histpos
);
strcpy (the_line
, h
->line
);
rl_undo_list
= (UNDO_LIST
*)h
->data
;
rl_end
= strlen (the_line
);
/* Completion, from vi's point of view. */
rl_vi_complete (ignore
, key
)
if (!whitespace (the_line
[rl_point
]))
rl_complete_internal ('*');
/* Previous word in vi mode. */
rl_vi_prev_word (count
, key
)
rl_vi_next_word (-count
, key
);
/* Next word in vi mode. */
rl_vi_next_word (count
, key
)
rl_vi_prev_word (-count
, key
);
/* Move to the end of the ?next? word. */
rl_vi_end_word (count
, key
)
/* Move forward a word the way that 'W' does. */
while (count
-- && rl_point
< (rl_end
- 1))
/* Skip until whitespace. */
while (!whitespace (the_line
[rl_point
]) && rl_point
< rl_end
)
/* Now skip whitespace. */
while (whitespace (the_line
[rl_point
]) && rl_point
< rl_end
)
while (count
-- && rl_point
> 0)
while (rl_point
-- >= 0 && whitespace (the_line
[rl_point
]));
while (rl_point
>= 0 && !whitespace (the_line
[rl_point
]))
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
]));
while (count
-- && rl_point
< (rl_end
- 1))
if (isident (the_line
[rl_point
]))
while (isident (the_line
[rl_point
]) && rl_point
< rl_end
)
else if (!whitespace (the_line
[rl_point
]))
while (!isident (the_line
[rl_point
]) &&
!whitespace (the_line
[rl_point
]) && rl_point
< rl_end
)
while (whitespace (the_line
[rl_point
]) && rl_point
< rl_end
)
while (count
-- && rl_point
> 0)
while (--rl_point
> 0 && whitespace (the_line
[rl_point
]));
if (isident (the_line
[rl_point
]))
while (--rl_point
>= 0 && isident (the_line
[rl_point
]));
while (--rl_point
>= 0 && !isident (the_line
[rl_point
]) &&
!whitespace (the_line
[rl_point
]));
while (count
-- && rl_point
< rl_end
- 1)
while (++rl_point
< rl_end
&& whitespace (the_line
[rl_point
]));
if (isident (the_line
[rl_point
]))
while (++rl_point
< rl_end
&& isident (the_line
[rl_point
]));
while (++rl_point
< rl_end
&& !isident (the_line
[rl_point
])
&& !whitespace (the_line
[rl_point
]));
/* What to do in the case of C-d. */
rl_vi_eof_maybe (count
, c
)
/* Insertion mode stuff. */
/* Switching from one mode to the other really just involves
keymap
= vi_insertion_keymap
;
keymap
= vi_movement_keymap
;
rl_vi_arg_digit (count
, c
)
if (c
== '0' && rl_numeric_arg
== 1 && !rl_explicit_arg
)
rl_digit_argument (count
, c
);
/* Doesn't take an arg count in vi */
rl_vi_change_case (ignore1
, ignore2
)
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
]);
/* Vi is kind of strange here. */
if (rl_point
&& rl_point
== rl_end
)
c
= rl_read_key (in_stream
);
if (!member (c
, vi_motion
))
/* No change in position means the command failed. */
if ((c
== 'w' || c
== 'W') && rl_point
< rl_end
)
while((rl_point
> 0) && whitespace (the_line
[rl_point
]))
exchange (rl_point
, rl_mark
);
/* A simplified loop for vi. Don't dispatch key at end.
Don't recognize minus sign? */
rl_message ("(arg: %d) ", arg_sign
* rl_numeric_arg
);
key
= c
= rl_read_key ();
if (keymap
[c
].type
== ISFUNC
&&
keymap
[c
].function
== rl_universal_argument
)
rl_numeric_arg
= (rl_numeric_arg
* 10) + (c
- '0');
rl_numeric_arg
= (c
- '0');
rl_vi_delete_to (count
, key
)
rl_kill_text (rl_point
, rl_mark
);
rl_vi_change_to (count
, key
)
rl_kill_text (rl_point
, rl_mark
);
rl_vi_yank_to (count
, key
)
rl_kill_text (rl_point
, rl_mark
);
if (rl_point
>= rl_end
- 1)
/* Turn the current line into a comment in shell history. A ksh function */
rl_insert_text (": "); /* # doesn't work in interactive mode */
rl_back_to_indent (ignore1
, ignore2
)
while (rl_point
< rl_end
&& whitespace (the_line
[rl_point
]))
/* NOTE: it is necessary that opposite directions are inverses */
#define FTO 1 /* forward to */
#define BTO -1 /* backward to */
#define FFIND 2 /* forward find */
#define BFIND -2 /* backward find */
rl_vi_char_search (count
, key
)
static int orig_dir
, dir
;
if (key
== ';' || key
== ',')
dir
= (key
== ';' ? orig_dir
: -orig_dir
);
if (the_line
[pos
] == target
)
if (the_line
[pos
] == target
)
int count
= 1, brack
, pos
;
if ((brack
= rl_vi_bracktype (the_line
[rl_point
])) == 0)
while ((brack
= rl_vi_bracktype (the_line
[rl_point
])) == 0 &&
int b
= rl_vi_bracktype (the_line
[pos
]);
int b
= rl_vi_bracktype (the_line
[pos
]);
rl_vi_overstrike (count
, key
)
if (vi_doing_insert
== 0)
for (i
= 0; i
< count
; i
++)
rl_vi_overstrike_delete (count
)
for (i
= 0; i
< count
; i
++)
if (vi_replace_count
== 0)
if (vi_replace_count
== 0 && vi_doing_insert
)
vi_replace_map
= rl_make_bare_keymap ();
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
[CTRL('H')].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
;