TheGNUGeneralPublicLicenseisoftenshippedwithGNUsoftware,and isgenerallykeptinafilecalledCOPYINGorLICENSE.Ifyoudonot haveacopyofthelicense,writetotheFreeSoftwareFoundation,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA. */ #define READLINE_LIBRARY
int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
/* Non-zero means enter insertion mode. */ staticint _rl_vi_doing_insert;
/* Command keys which do movement for xxx_to commands. */ staticconstchar *vi_motion = " hl^$0ftFT;,%wbeWBE|";
/* Keymap used for vi replace characters. Created dynamically since
rarely used. */ static Keymap vi_replace_map;
/* The number of characters inserted in the last replace operation. */ staticint vi_replace_count;
/* If non-zero, we have text inserted after a c[motion] command that put usimplicitlyintoinsertmode.Somepeoplewantthistexttobe
attached to the command so that it is `redoable' with `.'. */ staticint vi_continued_command; staticchar *vi_insert_buffer; staticint vi_insert_buffer_size;
/* A convenience function that calls _rl_vi_set_last to save the last command
information and enters insertion mode. */ void
rl_vi_start_inserting (key, repeat, sign) int key, repeat, sign;
{
_rl_vi_set_last (key, repeat, sign);
rl_vi_insertion_mode (1, key);
}
/* Is the command C a VI mode text modification command? */ int
_rl_vi_textmod_command (c) int c;
{ return (member (c, vi_textmod));
}
staticvoid
_rl_vi_stuff_insert (count) int count;
{
rl_begin_undo_group (); while (count--)
rl_insert_text (vi_insert_buffer);
rl_end_undo_group ();
}
/* Bound to `.'. Called from command mode, so we know that we have to redoatextmodificationcommand.Thedefaultfor_rl_vi_last_command
puts you back into insert mode. */ int
rl_vi_redo (count, c) int count, c __attribute__((unused));
{ int r;
if (!rl_explicit_arg)
{
rl_numeric_arg = _rl_vi_last_repeat;
rl_arg_sign = _rl_vi_last_arg_sign;
}
r = 0;
vi_redoing = 1; /* If we're redoing an insert with `i', stuff in the inserted text
and do not go into insertion mode. */ if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer)
{
_rl_vi_stuff_insert (count); /* And back up point over the last character inserted. */ if (rl_point > 0)
_rl_vi_backup ();
} /* Ditto for redoing an insert with `a', but move forward a character first
like the `a' command does. */ elseif (_rl_vi_last_command == 'a' && vi_insert_buffer && *vi_insert_buffer)
{
_rl_vi_append_forward ('a');
_rl_vi_stuff_insert (count); if (rl_point > 0)
_rl_vi_backup ();
} else
r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
vi_redoing = 0;
return (r);
}
/* A placeholder for further expansion. */ int
rl_vi_undo (count, key) int count, key;
{ return (rl_undo_command (count, key));
}
/* Yank the nth arg from the previous line into this line at point. */ int
rl_vi_yank_arg (count, key) int count, key __attribute__((unused));
{ /* 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);
return (0);
}
/* With an argument, move back that many history lines, else move to the
beginning of history. */ int
rl_vi_fetch_history (count, c) int count, c;
{ int wanted;
/* Giving an argument of n means we want the nth command in the history file.Thecommandnumberisinterpretedthesamewaythatthebash `history'commanddoesit--thatis,givinganargumentcountof450 tothiscommandwouldgetthecommandlistedasnumber450inthe
output of `history'. */ if (rl_explicit_arg)
{
wanted = history_base + where_history () - count; if (wanted <= 0)
rl_beginning_of_history (0, 0); else
rl_get_previous_history (wanted, c);
} else
rl_beginning_of_history (count, 0); return (0);
}
/* Search again for the last thing searched for. */ int
rl_vi_search_again (count, key) int count, key;
{ switch (key)
{ case'n':
rl_noninc_reverse_search_again (count, key); break;
/* Do a vi style search. */ int
rl_vi_search (count, key) int count, key;
{ switch (key)
{ case'?':
_rl_free_saved_history_line ();
rl_noninc_forward_search (count, key); break;
/* Completion, from vi's point of view. */ int
rl_vi_complete (ignore, key) int ignore __attribute__((unused)), key;
{ if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
{ if (!whitespace (rl_line_buffer[rl_point + 1]))
rl_vi_end_word (1, 'E');
rl_point++;
}
if (key == '*')
rl_complete_internal ('*'); /* Expansion and replacement. */ elseif (key == '=')
rl_complete_internal ('?'); /* List possible completions. */ elseif (key == '\\')
rl_complete_internal (TAB); /* Standard Readline completion. */ else
rl_complete (0, key);
/* Move forward a word the way that 'W' does. */ int
rl_vi_fWord (count, ignore) int count, ignore __attribute__((unused));
{ while (count-- && rl_point < (rl_end - 1))
{ /* Skip until whitespace. */ while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
rl_point++;
/* Now skip whitespace. */ while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
rl_point++;
} return (0);
}
int
rl_vi_bWord (count, ignore) int count, ignore __attribute__((unused));
{ while (count-- && rl_point > 0)
{ /* 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--;
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++;
}
} return (0);
}
int
rl_vi_eWord (count, ignore) int count, ignore __attribute__((unused));
{ while (count-- && rl_point < (rl_end - 1))
{ 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]))
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--;
}
} return (0);
}
int
rl_vi_fword (count, ignore) int count, ignore __attribute__((unused));
{ while (count-- && rl_point < (rl_end - 1))
{ /* Move to white space (really non-identifer). */ if (_rl_isident (rl_line_buffer[rl_point]))
{ while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end)
rl_point++;
} else/* if (!whitespace (rl_line_buffer[rl_point])) */
{ while (!_rl_isident (rl_line_buffer[rl_point]) &&
!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
rl_point++;
}
/* Move past whitespace. */ while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end)
rl_point++;
} return (0);
}
int
rl_vi_bword (count, ignore) int count, ignore __attribute__((unused));
{ while (count-- && rl_point > 0)
{ 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 backsowedon'tgetmessedupbytherl_point++downtherein thewhileloop.Withoutthiscode,wordslike`l;'screwupthe
function. */
last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]); if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) ||
(!_rl_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 (_rl_isident (rl_line_buffer[rl_point])) while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); else while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) &&
!whitespace (rl_line_buffer[rl_point]));
rl_point++;
}
} return (0);
}
int
rl_vi_eword (count, ignore) int count, ignore __attribute__((unused));
{ while (count-- && rl_point < rl_end - 1)
{ 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 (_rl_isident (rl_line_buffer[rl_point])) while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point])); else while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point])
&& !whitespace (rl_line_buffer[rl_point]));
}
rl_point--;
} return (0);
}
int
rl_vi_insert_beg (count, key) int count __attribute__((unused)), key;
{
rl_beg_of_line (1, key);
rl_vi_insertion_mode (1, key); return (0);
}
staticvoid
_rl_vi_append_forward (key) int key;
{ int point;
if (rl_point < rl_end)
{ if (MB_CUR_MAX == 1 || rl_byte_oriented)
rl_point++; else
{
point = rl_point;
rl_forward_char (1, key); if (point == rl_point)
rl_point = rl_end;
}
}
}
int
rl_vi_append_mode (count, key) int count __attribute__((unused)), key;
{
_rl_vi_append_forward (key);
rl_vi_start_inserting (key, 1, rl_arg_sign); return (0);
}
int
rl_vi_append_eol (count, key) int count __attribute__((unused)), key;
{
rl_end_of_line (1, key);
rl_vi_append_mode (1, key); return (0);
}
/* What to do in the case of C-d. */ int
rl_vi_eof_maybe (count, c) int count __attribute__((unused)), c __attribute__((unused));
{ return (rl_newline (1, '\n'));
}
/* Insertion mode stuff. */
/* Switching from one mode to the other really just involves
switching keymaps. */ int
rl_vi_insertion_mode (count, key) int count __attribute__((unused)), key;
{
_rl_keymap = vi_insertion_keymap;
_rl_vi_last_key_before_insert = key; return (0);
}
staticvoid
_rl_vi_save_insert (up)
UNDO_LIST *up;
{ int len, start, end;
if (up == 0 || up->what != UNDO_INSERT)
{ if (vi_insert_buffer_size >= 1)
vi_insert_buffer[0] = '\0'; return;
}
start = up->start;
end = up->end;
len = end - start + 1; if (len >= vi_insert_buffer_size)
{
vi_insert_buffer_size += (len + 32) - (len % 32);
vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size);
}
strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1);
vi_insert_buffer[len-1] = '\0';
}
void
_rl_vi_done_inserting ()
{ if (_rl_vi_doing_insert)
{ /* The `C', `s', and `S' commands set this. */
rl_end_undo_group (); /* Now, the text between rl_undo_list->next->start and rl_undo_list->next->endiswhatwasinsertedwhileininsert mode.ItgetscopiedtoVI_INSERT_BUFFERbecauseitdepends onabsoluteindicesintothelinewhichmaychange(thoughthey
probably will not). */
_rl_vi_doing_insert = 0;
_rl_vi_save_insert (rl_undo_list->next);
vi_continued_command = 1;
} else
{ if ((_rl_vi_last_key_before_insert == 'i' || _rl_vi_last_key_before_insert == 'a') && rl_undo_list)
_rl_vi_save_insert (rl_undo_list); /* XXX - Other keys probably need to be checked. */ elseif (_rl_vi_last_key_before_insert == 'C')
rl_end_undo_group (); while (_rl_undo_group_level > 0)
rl_end_undo_group ();
vi_continued_command = 0;
}
}
int
rl_vi_movement_mode (count, key) int count __attribute__((unused)), key;
{ if (rl_point > 0)
rl_backward_char (1, key);
/* This is how POSIX.2 says `U' should behave -- everything up until the
first time you go into command mode should not be undone. */ if (RL_ISSTATE (RL_STATE_VICMDONCE) == 0)
rl_free_undo_list ();
RL_SETSTATE (RL_STATE_VICMDONCE); return (0);
}
int
rl_vi_arg_digit (count, c) int count, c;
{ if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) return (rl_beg_of_line (1, c)); else return (rl_digit_argument (count, c));
}
/* Change the case of the next COUNT characters. */ #ifdefined (HANDLE_MULTIBYTE) staticint
_rl_vi_change_mbchar_case (count) int count;
{ wchar_t wc; char mb[MB_LEN_MAX+1]; int mlen, p;
mbstate_t ps;
memset (&ps, 0, sizeof (mbstate_t)); if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0)
count--; while (count-- && rl_point < rl_end)
{
mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); if (iswupper (wc))
wc = towlower (wc); elseif (iswlower (wc))
wc = towupper (wc); else
{ /* Just skip over chars neither upper nor lower case */
rl_forward_char (1, 0); continue;
}
/* Vi is kind of strange here. */ if (wc)
{
p = rl_point;
mlen = wcrtomb (mb, wc, &ps); if (mlen >= 0)
mb[mlen] = '\0';
rl_begin_undo_group ();
rl_vi_delete (1, 0); if (rl_point < p) /* Did we retreat at EOL? */
rl_point++; /* XXX - should we advance more than 1 for mbchar? */
rl_insert_text (mb);
rl_end_undo_group ();
rl_vi_check ();
} else
rl_forward_char (1, 0);
}
return0;
} #endif
int
rl_vi_change_case (count, ignore) int count, ignore __attribute__((unused));
{ int c, p;
/* Don't try this on an empty line. */ if (rl_point >= rl_end) return (0);
c = 0; #ifdefined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) return (_rl_vi_change_mbchar_case (count)); #endif
while (count-- && rl_point < rl_end)
{ if (_rl_uppercase_p (rl_line_buffer[rl_point]))
c = _rl_to_lower (rl_line_buffer[rl_point]); elseif (_rl_lowercase_p (rl_line_buffer[rl_point]))
c = _rl_to_upper (rl_line_buffer[rl_point]); else
{ /* Just skip over characters neither upper nor lower case. */
rl_forward_char (1, c); continue;
}
/* Vi is kind of strange here. */ if (c)
{
p = rl_point;
rl_begin_undo_group ();
rl_vi_delete (1, c); if (rl_point < p) /* Did we retreat at EOL? */
rl_point++;
_rl_insert_char (1, c);
rl_end_undo_group ();
rl_vi_check ();
} else
rl_forward_char (1, c);
} return (0);
}
int
rl_vi_put (count, key) int count, key;
{ if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
/* 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++] = ' ';
rl_line_buffer[rl_end] = '\0';
_rl_dispatch (c, _rl_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;
/* No change in position means the command failed. */ if (rl_mark == rl_point) return (-1);
/* rl_vi_f[wW]ord () leaves the cursor on the first character of the next word.Ifwearenotattheendoftheline,andweareona
non-whitespace character, move back one (presumably to whitespace). */ if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark &&
!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. */ if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W'))
{ /* Don't move farther back than where we started. */ while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point]))
rl_point--;
/* Posix.2 says that if cw or cW moves the cursor towards the end of
the line, the character under the cursor should be deleted. */ if (rl_point == rl_mark)
rl_point++; else
{ /* Move past the end of the word so that the kill doesn't removethelastletterofthepreviousword.Onlydothis
if we are not at the end of the line. */ if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point]))
rl_point++;
}
}
if (rl_mark < rl_point)
SWAP (rl_point, rl_mark);
return (0);
}
/* Process C as part of the current numeric argument. Return -1 if the argumentshouldbeaborted,0ifweshouldnotreadanymorechars,and
1 if we should continue to read chars. */ staticint
_rl_vi_arg_dispatch (c) int c;
{ int key;
/* A simplified loop for vi. Don't dispatch key at end. Don'trecognizeminussign?
Should this do rl_save_prompt/rl_restore_prompt? */ staticint
rl_digit_loop1 ()
{ int c, r;
while (1)
{ if (_rl_arg_overflow ()) return1;
c = _rl_arg_getchar ();
r = _rl_vi_arg_dispatch (c); if (r <= 0) break;
}
RL_UNSETSTATE(RL_STATE_NUMERICARG); return (0);
}
int
rl_vi_delete_to (count, key) int count __attribute__((unused)), key;
{ int c;
if (_rl_uppercase_p (key))
rl_stuff_char ('$'); elseif (vi_redoing)
rl_stuff_char (_rl_vi_last_motion);
if (rl_vi_domove (key, &c))
{
rl_ding (); return -1;
}
/* These are the motion commands that do not require adjusting the
mark. */ if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end))
rl_mark++;
rl_kill_text (rl_point, rl_mark); return (0);
}
int
rl_vi_change_to (count, key) int count __attribute__((unused)), key;
{ int c, start_pos;
if (_rl_uppercase_p (key))
rl_stuff_char ('$'); elseif (vi_redoing)
rl_stuff_char (_rl_vi_last_motion);
start_pos = rl_point;
if (rl_vi_domove (key, &c))
{
rl_ding (); return -1;
}
/* These are the motion commands that do not require adjusting the mark.c[wW]arehandledbyspecial-casecodeinrl_vi_domove(),
and already leave the mark at the correct location. */ if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end))
rl_mark++;
/* The cursor never moves with c[wW]. */ if ((_rl_to_upper (c) == 'W') && rl_point < start_pos)
rl_point = start_pos;
if (vi_redoing)
{ if (vi_insert_buffer && *vi_insert_buffer)
rl_begin_undo_group ();
rl_delete_text (rl_point, rl_mark); if (vi_insert_buffer && *vi_insert_buffer)
{
rl_insert_text (vi_insert_buffer);
rl_end_undo_group ();
}
} else
{
rl_begin_undo_group (); /* to make the `u' command work */
rl_kill_text (rl_point, rl_mark); /* `C' does not save the text inserted for undoing or redoing. */ if (_rl_uppercase_p (key) == 0)
_rl_vi_doing_insert = 1;
rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign);
}
return (0);
}
int
rl_vi_yank_to (count, key) int count __attribute__((unused)), key;
{ int c, save;
save = rl_point; if (_rl_uppercase_p (key))
rl_stuff_char ('$');
if (rl_vi_domove (key, &c))
{
rl_ding (); return -1;
}
/* These are the motion commands that do not require adjusting the
mark. */ if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end))
rl_mark++;
int
rl_vi_subst (count, key) int count, key;
{ /* If we are redoing, rl_vi_change_to will stuff the last motion char */ if (vi_redoing == 0)
rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */
return (rl_vi_change_to (count, 'c'));
}
int
rl_vi_overstrike (count, key) int count, key;
{ if (_rl_vi_doing_insert == 0)
{
_rl_vi_doing_insert = 1;
rl_begin_undo_group ();
}
/* If the normal vi insertion keymap has ^H bound to erase, do the samehere.ProbablyshouldremovetheassignmenttoRUBOUTup
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;
}
_rl_keymap = vi_replace_map; return (0);
}
#if0 /* Try to complete the word we are standing on or the word that ends with thepreviouscharacter.Aspacematcheseverything.Worddelimitersare
space and ;. */ int
rl_vi_possible_completions()
{ int save_pos = rl_point;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.