X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Freadline%2Fvi_mode.c;h=5f35cf080653ea5f3881a2b61343b439913d32aa;hb=3185942a5234e26ab13fa02f9c51d340cec514f8;hp=c730296d0a57282e0bf995dea4fce88a951d18ac;hpb=ccc6cda312fea9f0468ee65b8f368e9653e1380b;p=platform%2Fupstream%2Fbash.git diff --git a/lib/readline/vi_mode.c b/lib/readline/vi_mode.c index c730296..5f35cf0 100644 --- a/lib/readline/vi_mode.c +++ b/lib/readline/vi_mode.c @@ -1,25 +1,25 @@ /* vi_mode.c -- A vi emulation mode for Bash. Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ -/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1987-2009 Free Software Foundation, Inc. - This file is part of the GNU Readline Library, a library for - reading lines of text with interactive input and history editing. + This file is part of the GNU Readline Library (Readline), a library + for reading lines of text with interactive input and history editing. - The GNU Readline 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 + Readline 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 3 of the License, or (at your option) any later version. - The GNU Readline 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 + Readline 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. */ + You should have received a copy of the GNU General Public License + along with Readline. If not, see . +*/ + #define READLINE_LIBRARY /* **************************************************************** */ @@ -51,54 +51,25 @@ /* Some standard library routines. */ #include "rldefs.h" +#include "rlmbutil.h" + #include "readline.h" #include "history.h" -#ifndef _rl_digit_p -#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9') -#endif - -#ifndef _rl_digit_value -#define _rl_digit_value(c) ((c) - '0') -#endif +#include "rlprivate.h" +#include "xmalloc.h" #ifndef member #define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) #endif -#ifndef isident -#define isident(c) ((_rl_pure_alphabetic (c) || _rl_digit_p (c) || c == '_')) -#endif - -#ifndef exchange -#define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0) -#endif - -extern char *xmalloc (), *xrealloc (); - -/* 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 _rl_keymap; -extern char *rl_prompt; -extern char *rl_line_buffer; -extern int rl_arg_sign; - -extern int _rl_doing_an_undo; -extern int _rl_undo_group_level; - -extern void _rl_dispatch (); -extern int _rl_char_search_internal (); - -extern void rl_extend_line_buffer (); -extern int rl_vi_check (); +int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ /* Non-zero means enter insertion mode. */ static int _rl_vi_doing_insert; /* Command keys which do movement for xxx_to commands. */ -static char *vi_motion = " hl^$0ftFt;,%wbeWBE|"; +static const char * const vi_motion = " hl^$0ftFT;,%wbeWBE|`"; /* Keymap used for vi replace characters. Created dynamically since rarely used. */ @@ -114,11 +85,15 @@ static int vi_continued_command; static char *vi_insert_buffer; static int vi_insert_buffer_size; -static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ static int _rl_vi_last_repeat = 1; static int _rl_vi_last_arg_sign = 1; static int _rl_vi_last_motion; +#if defined (HANDLE_MULTIBYTE) +static char _rl_vi_last_search_mbchar[MB_LEN_MAX]; +static int _rl_vi_last_search_mblen; +#else static int _rl_vi_last_search_char; +#endif static int _rl_vi_last_replacement; static int _rl_vi_last_key_before_insert; @@ -126,12 +101,32 @@ static int _rl_vi_last_key_before_insert; static int vi_redoing; /* Text modification commands. These are the `redoable' commands. */ -static char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; +static const char * const vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; /* Arrays for the saved marks. */ -static int vi_mark_chars[27]; +static int vi_mark_chars['z' - 'a' + 1]; + +static void _rl_vi_stuff_insert PARAMS((int)); +static void _rl_vi_save_insert PARAMS((UNDO_LIST *)); + +static void _rl_vi_backup PARAMS((void)); + +static int _rl_vi_arg_dispatch PARAMS((int)); +static int rl_digit_loop1 PARAMS((void)); -static int rl_digit_loop1 (); +static int _rl_vi_set_mark PARAMS((void)); +static int _rl_vi_goto_mark PARAMS((void)); + +static void _rl_vi_append_forward PARAMS((int)); + +static int _rl_vi_callback_getchar PARAMS((char *, int)); + +#if defined (READLINE_CALLBACKS) +static int _rl_vi_callback_set_mark PARAMS((_rl_callback_generic_arg *)); +static int _rl_vi_callback_goto_mark PARAMS((_rl_callback_generic_arg *)); +static int _rl_vi_callback_change_char PARAMS((_rl_callback_generic_arg *)); +static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *)); +#endif void _rl_vi_initialize_line () @@ -140,6 +135,8 @@ _rl_vi_initialize_line () for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) vi_mark_chars[i] = -1; + + RL_UNSETSTATE(RL_STATE_VICMDONCE); } void @@ -160,6 +157,16 @@ _rl_vi_set_last (key, repeat, sign) _rl_vi_last_arg_sign = sign; } +/* 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) @@ -185,12 +192,15 @@ int rl_vi_redo (count, c) int count, c; { + 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. */ @@ -199,13 +209,40 @@ rl_vi_redo (count, c) _rl_vi_stuff_insert (count); /* And back up point over the last character inserted. */ if (rl_point > 0) - rl_point--; + _rl_vi_backup (); + } + /* Ditto for redoing an insert with `I', but move to the beginning of the + line like the `I' command does. */ + else if (_rl_vi_last_command == 'I' && vi_insert_buffer && *vi_insert_buffer) + { + rl_beg_of_line (1, 'I'); + _rl_vi_stuff_insert (count); + 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. */ + else if (_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 (); + } + /* Ditto for redoing an insert with `A', but move to the end of the line + like the `A' command does. */ + else if (_rl_vi_last_command == 'A' && vi_insert_buffer && *vi_insert_buffer) + { + rl_end_of_line (1, 'A'); + _rl_vi_stuff_insert (count); + if (rl_point > 0) + _rl_vi_backup (); } else - _rl_dispatch (_rl_vi_last_command, _rl_keymap); + r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); vi_redoing = 0; - return (0); + return (r); } /* A placeholder for further expansion. */ @@ -283,15 +320,17 @@ rl_vi_search (count, key) switch (key) { case '?': + _rl_free_saved_history_line (); rl_noninc_forward_search (count, key); break; case '/': + _rl_free_saved_history_line (); rl_noninc_reverse_search (count, key); break; default: - ding (); + rl_ding (); break; } return (0); @@ -319,10 +358,8 @@ rl_vi_complete (ignore, key) rl_complete (0, key); if (key == '*' || key == '\\') - { - _rl_vi_set_last (key, 1, rl_arg_sign); - rl_vi_insertion_mode (1, key); - } + rl_vi_start_inserting (key, 1, rl_arg_sign); + return (0); } @@ -332,8 +369,7 @@ rl_vi_tilde_expand (ignore, key) int ignore, key; { rl_tilde_expand (0, key); - _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */ - rl_vi_insertion_mode (1, key); + rl_vi_start_inserting (key, 1, rl_arg_sign); return (0); } @@ -347,14 +383,14 @@ rl_vi_prev_word (count, key) if (rl_point == 0) { - ding (); + rl_ding (); return (0); } if (_rl_uppercase_p (key)) - rl_vi_bWord (count); + rl_vi_bWord (count, key); else - rl_vi_bword (count); + rl_vi_bword (count, key); return (0); } @@ -369,14 +405,14 @@ rl_vi_next_word (count, key) if (rl_point >= (rl_end - 1)) { - ding (); + rl_ding (); return (0); } if (_rl_uppercase_p (key)) - rl_vi_fWord (count); + rl_vi_fWord (count, key); else - rl_vi_fword (count); + rl_vi_fword (count, key); return (0); } @@ -387,21 +423,21 @@ rl_vi_end_word (count, key) { if (count < 0) { - ding (); + rl_ding (); return -1; } if (_rl_uppercase_p (key)) - rl_vi_eWord (count); + rl_vi_eWord (count, key); else - rl_vi_eword (count); + rl_vi_eword (count, key); return (0); } /* Move forward a word the way that 'W' does. */ int -rl_vi_fWord (count) - int count; +rl_vi_fWord (count, ignore) + int count, ignore; { while (count-- && rl_point < (rl_end - 1)) { @@ -417,8 +453,8 @@ rl_vi_fWord (count) } int -rl_vi_bWord (count) - int count; +rl_vi_bWord (count, ignore) + int count, ignore; { while (count-- && rl_point > 0) { @@ -441,8 +477,8 @@ rl_vi_bWord (count) } int -rl_vi_eWord (count) - int count; +rl_vi_eWord (count, ignore) + int count, ignore; { while (count-- && rl_point < (rl_end - 1)) { @@ -451,7 +487,8 @@ rl_vi_eWord (count) /* 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])); + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; if (rl_point && rl_point < rl_end) { @@ -471,20 +508,20 @@ rl_vi_eWord (count) } int -rl_vi_fword (count) - int count; +rl_vi_fword (count, ignore) + int count, ignore; { while (count-- && rl_point < (rl_end - 1)) { /* Move to white space (really non-identifer). */ - if (isident (rl_line_buffer[rl_point])) + if (_rl_isident (rl_line_buffer[rl_point])) { - while (isident (rl_line_buffer[rl_point]) && rl_point < rl_end) + while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end) rl_point++; } else /* if (!whitespace (rl_line_buffer[rl_point])) */ { - while (!isident (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++; } @@ -497,8 +534,8 @@ rl_vi_fword (count) } int -rl_vi_bword (count) - int count; +rl_vi_bword (count, ignore) + int count, ignore; { while (count-- && rl_point > 0) { @@ -514,9 +551,9 @@ rl_vi_bword (count) 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)) + 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])) @@ -524,10 +561,10 @@ rl_vi_bword (count) if (rl_point > 0) { - if (isident (rl_line_buffer[rl_point])) - while (--rl_point >= 0 && isident (rl_line_buffer[rl_point])); + if (_rl_isident (rl_line_buffer[rl_point])) + while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); else - while (--rl_point >= 0 && !isident (rl_line_buffer[rl_point]) && + while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) && !whitespace (rl_line_buffer[rl_point])); rl_point++; } @@ -536,8 +573,8 @@ rl_vi_bword (count) } int -rl_vi_eword (count) - int count; +rl_vi_eword (count, ignore) + int count, ignore; { while (count-- && rl_point < rl_end - 1) { @@ -549,10 +586,10 @@ rl_vi_eword (count) if (rl_point < rl_end) { - if (isident (rl_line_buffer[rl_point])) - while (++rl_point < rl_end && isident (rl_line_buffer[rl_point])); + 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 && !isident (rl_line_buffer[rl_point]) + while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point]) && !whitespace (rl_line_buffer[rl_point])); } rl_point--; @@ -565,17 +602,36 @@ rl_vi_insert_beg (count, key) int count, key; { rl_beg_of_line (1, key); - rl_vi_insertion_mode (1, key); + rl_vi_insert_mode (1, key); return (0); } +static void +_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, key; { - if (rl_point < rl_end) - rl_point++; - rl_vi_insertion_mode (1, key); + _rl_vi_append_forward (key); + rl_vi_start_inserting (key, 1, rl_arg_sign); return (0); } @@ -609,19 +665,34 @@ rl_vi_insertion_mode (count, key) return (0); } +int +rl_vi_insert_mode (count, key) + int count, key; +{ + rl_vi_start_inserting (key, 1, rl_arg_sign); + return (0); +} + static void _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 = xrealloc (vi_insert_buffer, vi_insert_buffer_size); + 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'; @@ -632,6 +703,7 @@ _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->end is what was inserted while in insert @@ -644,7 +716,10 @@ _rl_vi_done_inserting () } else { - if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list) + if (rl_undo_list && (_rl_vi_last_key_before_insert == 'i' || + _rl_vi_last_key_before_insert == 'a' || + _rl_vi_last_key_before_insert == 'I' || + _rl_vi_last_key_before_insert == 'A')) _rl_vi_save_insert (rl_undo_list); /* XXX - Other keys probably need to be checked. */ else if (_rl_vi_last_key_before_insert == 'C') @@ -660,10 +735,17 @@ rl_vi_movement_mode (count, key) int count, key; { if (rl_point > 0) - rl_backward (1, key); + rl_backward_char (1, key); _rl_keymap = vi_movement_keymap; _rl_vi_done_inserting (); + + /* 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); } @@ -677,16 +759,73 @@ rl_vi_arg_digit (count, c) return (rl_digit_argument (count, c)); } +/* Change the case of the next COUNT characters. */ +#if defined (HANDLE_MULTIBYTE) +static int +_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); + else if (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); + } + + return 0; +} +#endif + int rl_vi_change_case (count, ignore) int count, ignore; { - char c = 0; + int c, p; /* Don't try this on an empty line. */ if (rl_point >= rl_end) return (0); + c = 0; +#if defined (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])) @@ -696,21 +835,24 @@ rl_vi_change_case (count, ignore) else { /* Just skip over characters neither upper nor lower case. */ - rl_forward (1, c); + rl_forward_char (1, c); continue; } /* Vi is kind of strange here. */ if (c) { + p = rl_point; rl_begin_undo_group (); - rl_delete (1, c); - rl_insert (1, c); + 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 (1, c); + rl_forward_char (1, c); } return (0); } @@ -720,18 +862,34 @@ rl_vi_put (count, key) int count, key; { if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) - rl_point++; + rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); + + while (count--) + rl_yank (1, key); - rl_yank (); - rl_backward (1, key); + rl_backward_char (1, key); return (0); } +static void +_rl_vi_backup () +{ + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else + rl_point--; +} + int rl_vi_check () { if (rl_point && rl_point == rl_end) - rl_point--; + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else + rl_point--; + } return (0); } @@ -754,7 +912,16 @@ rl_vi_domove (key, nextkey) int old_end; rl_mark = rl_point; + RL_SETSTATE(RL_STATE_MOREINPUT); c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (c < 0) + { + *nextkey = 0; + return -1; + } + *nextkey = c; if (!member (c, vi_motion)) @@ -763,9 +930,19 @@ rl_vi_domove (key, nextkey) { save = rl_numeric_arg; rl_numeric_arg = _rl_digit_value (c); + rl_explicit_arg = 1; + RL_SETSTATE (RL_STATE_NUMERICARG|RL_STATE_VIMOTION); rl_digit_loop1 (); + RL_UNSETSTATE (RL_STATE_VIMOTION); rl_numeric_arg *= save; + RL_SETSTATE(RL_STATE_MOREINPUT); c = rl_read_key (); /* real command */ + RL_UNSETSTATE(RL_STATE_MOREINPUT); + if (c < 0) + { + *nextkey = 0; + return -1; + } *nextkey = c; } else if (key == c && (key == 'd' || key == 'y' || key == 'c')) @@ -829,46 +1006,67 @@ rl_vi_domove (key, nextkey) } if (rl_mark < rl_point) - exchange (rl_point, rl_mark); + SWAP (rl_point, rl_mark); return (0); } +/* Process C as part of the current numeric argument. Return -1 if the + argument should be aborted, 0 if we should not read any more chars, and + 1 if we should continue to read chars. */ +static int +_rl_vi_arg_dispatch (c) + int c; +{ + int key; + + key = c; + if (c >= 0 && _rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument) + { + rl_numeric_arg *= 4; + return 1; + } + + c = UNMETA (c); + + if (_rl_digit_p (c)) + { + if (rl_explicit_arg) + rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); + else + rl_numeric_arg = _rl_digit_value (c); + rl_explicit_arg = 1; + return 1; + } + else + { + rl_clear_message (); + rl_stuff_char (key); + return 0; + } +} + /* A simplified loop for vi. Don't dispatch key at end. - Don't recognize minus sign? */ + Don't recognize minus sign? + Should this do rl_save_prompt/rl_restore_prompt? */ static int rl_digit_loop1 () { - int key, c; + int c, r; while (1) { - rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg, 0); - key = c = rl_read_key (); + if (_rl_arg_overflow ()) + return 1; - if (_rl_keymap[c].type == ISFUNC && - _rl_keymap[c].function == rl_universal_argument) - { - rl_numeric_arg *= 4; - continue; - } + c = _rl_arg_getchar (); - c = UNMETA (c); - if (_rl_digit_p (c)) - { - if (rl_explicit_arg) - rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); - else - rl_numeric_arg = _rl_digit_value (c); - rl_explicit_arg = 1; - } - else - { - rl_clear_message (); - rl_stuff_char (key); - break; - } + r = _rl_vi_arg_dispatch (c); + if (r <= 0) + break; } + + RL_UNSETSTATE(RL_STATE_NUMERICARG); return (0); } @@ -876,22 +1074,25 @@ int rl_vi_delete_to (count, key) int count, key; { - int c; + int c, start_pos; if (_rl_uppercase_p (key)) rl_stuff_char ('$'); else if (vi_redoing) rl_stuff_char (_rl_vi_last_motion); + start_pos = rl_point; + if (rl_vi_domove (key, &c)) { - ding (); + 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)) + if (((strchr (" l|h^0bBFT`", c) == 0) && (rl_point >= start_pos)) && + (rl_mark < rl_end)) rl_mark++; rl_kill_text (rl_point, rl_mark); @@ -913,14 +1114,15 @@ rl_vi_change_to (count, key) if (rl_vi_domove (key, &c)) { - ding (); + rl_ding (); return -1; } /* These are the motion commands that do not require adjusting the mark. c[wW] are handled by special-case code in rl_vi_domove(), and already leave the mark at the correct location. */ - if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) + if (((strchr (" l|hwW^0bBFT`", c) == 0) && (rl_point >= start_pos)) && + (rl_mark < rl_end)) rl_mark++; /* The cursor never moves with c[wW]. */ @@ -945,8 +1147,7 @@ rl_vi_change_to (count, key) /* `C' does not save the text inserted for undoing or redoing. */ if (_rl_uppercase_p (key) == 0) _rl_vi_doing_insert = 1; - _rl_vi_set_last (key, count, rl_arg_sign); - rl_vi_insertion_mode (1, key); + rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign); } return (0); @@ -956,44 +1157,84 @@ int rl_vi_yank_to (count, key) int count, key; { - int c, save = rl_point; + int c, start_pos; if (_rl_uppercase_p (key)) rl_stuff_char ('$'); + start_pos = rl_point; + if (rl_vi_domove (key, &c)) { - ding (); + 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)) + if (((strchr (" l|h^0%bBFT`", c) == 0) && (rl_point >= start_pos)) && + (rl_mark < rl_end)) rl_mark++; rl_begin_undo_group (); rl_kill_text (rl_point, rl_mark); rl_end_undo_group (); rl_do_undo (); - rl_point = save; + rl_point = start_pos; return (0); } int +rl_vi_rubout (count, key) + int count, key; +{ + int opoint; + + if (count < 0) + return (rl_vi_delete (-count, key)); + + if (rl_point == 0) + { + rl_ding (); + return -1; + } + + opoint = rl_point; + if (count > 1 && MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_backward_char (count, key); + else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else + rl_point -= count; + + if (rl_point < 0) + rl_point = 0; + + rl_kill_text (rl_point, opoint); + + return (0); +} + +int rl_vi_delete (count, key) int count, key; { int end; + if (count < 0) + return (rl_vi_rubout (-count, key)); + if (rl_end == 0) { - ding (); + rl_ding (); return -1; } - end = rl_point + count; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); + else + end = rl_point + count; if (end >= rl_end) end = rl_end; @@ -1001,7 +1242,8 @@ rl_vi_delete (count, key) rl_kill_text (rl_point, end); if (rl_point > 0 && rl_point == rl_end) - rl_backward (1, key); + rl_backward_char (1, key); + return (0); } @@ -1022,43 +1264,118 @@ rl_vi_first_print (count, key) return (rl_vi_back_to_indent (1, key)); } +static int _rl_cs_dir, _rl_cs_orig_dir; + +#if defined (READLINE_CALLBACKS) +static int +_rl_vi_callback_char_search (data) + _rl_callback_generic_arg *data; +{ + int c; +#if defined (HANDLE_MULTIBYTE) + c = _rl_vi_last_search_mblen = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); +#else + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); +#endif + + if (c <= 0) + return -1; + +#if !defined (HANDLE_MULTIBYTE) + _rl_vi_last_search_char = c; +#endif + + _rl_callback_func = 0; + _rl_want_redisplay = 1; + +#if defined (HANDLE_MULTIBYTE) + return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_mbchar, _rl_vi_last_search_mblen)); +#else + return (_rl_char_search_internal (data->count, _rl_cs_dir, _rl_vi_last_search_char)); +#endif +} +#endif + int rl_vi_char_search (count, key) int count, key; { + int c; +#if defined (HANDLE_MULTIBYTE) + static char *target; + static int tlen; +#else static char target; - static int orig_dir, dir; +#endif if (key == ';' || key == ',') - dir = key == ';' ? orig_dir : -orig_dir; + _rl_cs_dir = (key == ';') ? _rl_cs_orig_dir : -_rl_cs_orig_dir; else { - if (vi_redoing) - target = _rl_vi_last_search_char; - else - _rl_vi_last_search_char = target = rl_getc (rl_instream); - switch (key) { case 't': - orig_dir = dir = FTO; + _rl_cs_orig_dir = _rl_cs_dir = FTO; break; case 'T': - orig_dir = dir = BTO; + _rl_cs_orig_dir = _rl_cs_dir = BTO; break; case 'f': - orig_dir = dir = FFIND; + _rl_cs_orig_dir = _rl_cs_dir = FFIND; break; case 'F': - orig_dir = dir = BFIND; + _rl_cs_orig_dir = _rl_cs_dir = BFIND; break; } + + if (vi_redoing) + { + /* set target and tlen below */ + } +#if defined (READLINE_CALLBACKS) + else if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + _rl_callback_data = _rl_callback_data_alloc (count); + _rl_callback_data->i1 = _rl_cs_dir; + _rl_callback_func = _rl_vi_callback_char_search; + return (0); + } +#endif + else + { +#if defined (HANDLE_MULTIBYTE) + c = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); + if (c <= 0) + return -1; + _rl_vi_last_search_mblen = c; +#else + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + if (c < 0) + return -1; + _rl_vi_last_search_char = c; +#endif + } } - return (_rl_char_search_internal (count, dir, target)); +#if defined (HANDLE_MULTIBYTE) + target = _rl_vi_last_search_mbchar; + tlen = _rl_vi_last_search_mblen; +#else + target = _rl_vi_last_search_char; +#endif + +#if defined (HANDLE_MULTIBYTE) + return (_rl_char_search_internal (count, _rl_cs_dir, target, tlen)); +#else + return (_rl_char_search_internal (count, _rl_cs_dir, target)); +#endif } /* Match brackets */ @@ -1066,19 +1383,30 @@ int rl_vi_match (ignore, key) int ignore, key; { - int count = 1, brack, pos; + int count = 1, brack, pos, tmp, pre; pos = rl_point; if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) { - while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && - rl_point < rl_end - 1) - rl_forward (1, key); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) + { + pre = rl_point; + rl_forward_char (1, key); + if (pre == rl_point) + break; + } + } + else + while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && + rl_point < rl_end - 1) + rl_forward_char (1, key); if (brack <= 0) { rl_point = pos; - ding (); + rl_ding (); return -1; } } @@ -1089,7 +1417,16 @@ rl_vi_match (ignore, key) { while (count) { - if (--pos >= 0) + tmp = pos; + if (MB_CUR_MAX == 1 || rl_byte_oriented) + pos--; + else + { + pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); + if (tmp == pos) + pos--; + } + if (pos >= 0) { int b = rl_vi_bracktype (rl_line_buffer[pos]); if (b == -brack) @@ -1099,7 +1436,7 @@ rl_vi_match (ignore, key) } else { - ding (); + rl_ding (); return -1; } } @@ -1108,7 +1445,12 @@ rl_vi_match (ignore, key) { /* brack > 0 */ while (count) { - if (++pos < rl_end) + if (MB_CUR_MAX == 1 || rl_byte_oriented) + pos++; + else + pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); + + if (pos < rl_end) { int b = rl_vi_bracktype (rl_line_buffer[pos]); if (b == -brack) @@ -1118,7 +1460,7 @@ rl_vi_match (ignore, key) } else { - ding (); + rl_ding (); return -1; } } @@ -1143,98 +1485,138 @@ rl_vi_bracktype (c) } } -int -rl_vi_change_char (count, key) - int count, key; +static int +_rl_vi_change_char (count, c, mb) + int count, c; + char *mb; { - int c; - - if (vi_redoing) - c = _rl_vi_last_replacement; - else - _rl_vi_last_replacement = c = rl_getc (rl_instream); + int p; if (c == '\033' || c == CTRL ('C')) return -1; + rl_begin_undo_group (); while (count-- && rl_point < rl_end) { - rl_begin_undo_group (); + p = rl_point; + rl_vi_delete (1, c); + if (rl_point < p) /* Did we retreat at EOL? */ + rl_point++; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_insert_text (mb); + else +#endif + _rl_insert_char (1, c); + } - rl_delete (1, c); - rl_insert (1, c); - if (count == 0) - rl_backward (1, c); + /* The cursor shall be left on the last character changed. */ + rl_backward_char (1, c); + + rl_end_undo_group (); - rl_end_undo_group (); - } return (0); } -int -rl_vi_subst (count, key) - int count, key; +static int +_rl_vi_callback_getchar (mb, mlen) + char *mb; + int mlen; { - rl_begin_undo_group (); + int c; - if (_rl_uppercase_p (key)) - { - rl_beg_of_line (1, key); - rl_kill_line (1, key); - } - else - rl_delete_text (rl_point, rl_point+count); + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); - rl_end_undo_group (); + if (c < 0) + return -1; + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + c = _rl_read_mbstring (c, mb, mlen); +#endif + + return c; +} - _rl_vi_set_last (key, count, rl_arg_sign); +#if defined (READLINE_CALLBACKS) +static int +_rl_vi_callback_change_char (data) + _rl_callback_generic_arg *data; +{ + int c; + char mb[MB_LEN_MAX]; + + _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); + + if (c < 0) + return -1; + + _rl_callback_func = 0; + _rl_want_redisplay = 1; + + return (_rl_vi_change_char (data->count, c, mb)); +} +#endif + +int +rl_vi_change_char (count, key) + int count, key; +{ + int c; + char mb[MB_LEN_MAX]; if (vi_redoing) { - int o = _rl_doing_an_undo; - - _rl_doing_an_undo = 1; - if (vi_insert_buffer && *vi_insert_buffer) - rl_insert_text (vi_insert_buffer); - _rl_doing_an_undo = o; + c = _rl_vi_last_replacement; + mb[0] = c; + mb[1] = '\0'; } - else +#if defined (READLINE_CALLBACKS) + else if (RL_ISSTATE (RL_STATE_CALLBACK)) { - rl_begin_undo_group (); - _rl_vi_doing_insert = 1; - rl_vi_insertion_mode (1, key); + _rl_callback_data = _rl_callback_data_alloc (count); + _rl_callback_func = _rl_vi_callback_change_char; + return (0); } +#endif + else + _rl_vi_last_replacement = c = _rl_vi_callback_getchar (mb, MB_LEN_MAX); - return (0); + if (c < 0) + return -1; + + return (_rl_vi_change_char (count, c, mb)); } int -rl_vi_overstrike (count, key) +rl_vi_subst (count, key) int count, key; { - int i; + /* 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 (); } - for (i = 0; i < count; i++) + if (count > 0) { - vi_replace_count++; - rl_begin_undo_group (); - - if (rl_point < rl_end) - { - rl_delete (1, key); - rl_insert (1, key); - } - else - rl_insert (1, key); - - rl_end_undo_group (); + _rl_overwrite_char (count, key); + vi_replace_count += count; } + return (0); } @@ -1248,7 +1630,7 @@ rl_vi_overstrike_delete (count, key) { if (vi_replace_count == 0) { - ding (); + rl_ding (); break; } s = rl_point; @@ -1257,7 +1639,7 @@ rl_vi_overstrike_delete (count, key) vi_replace_count--; if (rl_point == s) - rl_backward (1, key); + rl_backward_char (1, key); } if (vi_replace_count == 0 && _rl_vi_doing_insert) @@ -1318,7 +1700,7 @@ rl_vi_possible_completions() } else if (rl_line_buffer[rl_point - 1] == ';') { - ding (); + rl_ding (); return (0); } @@ -1330,16 +1712,18 @@ rl_vi_possible_completions() #endif /* Functions to save and restore marks. */ -int -rl_vi_set_mark (count, key) - int count, key; +static int +_rl_vi_set_mark () { int ch; + RL_SETSTATE(RL_STATE_MOREINPUT); ch = rl_read_key (); - if (_rl_lowercase_p (ch) == 0) + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */ { - ding (); + rl_ding (); return -1; } ch -= 'a'; @@ -1347,32 +1731,89 @@ rl_vi_set_mark (count, key) return 0; } +#if defined (READLINE_CALLBACKS) +static int +_rl_vi_callback_set_mark (data) + _rl_callback_generic_arg *data; +{ + _rl_callback_func = 0; + _rl_want_redisplay = 1; + + return (_rl_vi_set_mark ()); +} +#endif + int -rl_vi_goto_mark (count, key) +rl_vi_set_mark (count, key) int count, key; { +#if defined (READLINE_CALLBACKS) + if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + _rl_callback_data = 0; + _rl_callback_func = _rl_vi_callback_set_mark; + return (0); + } +#endif + + return (_rl_vi_set_mark ()); +} + +static int +_rl_vi_goto_mark () +{ int ch; + RL_SETSTATE(RL_STATE_MOREINPUT); ch = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + if (ch == '`') { rl_point = rl_mark; return 0; } - else if (_rl_lowercase_p (ch) == 0) + else if (ch < 0 || ch < 'a' || ch > 'z') /* make test against 0 explicit */ { - ding (); + rl_ding (); return -1; } ch -= 'a'; if (vi_mark_chars[ch] == -1) { - ding (); + rl_ding (); return -1; } rl_point = vi_mark_chars[ch]; return 0; } +#if defined (READLINE_CALLBACKS) +static int +_rl_vi_callback_goto_mark (data) + _rl_callback_generic_arg *data; +{ + _rl_callback_func = 0; + _rl_want_redisplay = 1; + + return (_rl_vi_goto_mark ()); +} +#endif + +int +rl_vi_goto_mark (count, key) + int count, key; +{ +#if defined (READLINE_CALLBACKS) + if (RL_ISSTATE (RL_STATE_CALLBACK)) + { + _rl_callback_data = 0; + _rl_callback_func = _rl_vi_callback_goto_mark; + return (0); + } +#endif + + return (_rl_vi_goto_mark ()); +} #endif /* VI_MODE */