mirror of
https://github.com/neovim/neovim.git
synced 2024-09-17 20:58:20 -04:00
vim-patch:8.2.3389: cannot stop insert mode completion without side effects #15538
Problem: Cannot stop insert mode completion without side effects.
Solution: Add CTRL-X CTRL-Z. (closes vim/vim#8821)
dca29d9cf4
This commit is contained in:
parent
5e22fdd9cc
commit
9697023a0b
@ -155,6 +155,7 @@ commands in CTRL-X submode *i_CTRL-X_index*
|
||||
|i_CTRL-X_CTRL-Y| CTRL-X CTRL-Y scroll down
|
||||
|i_CTRL-X_CTRL-U| CTRL-X CTRL-U complete with 'completefunc'
|
||||
|i_CTRL-X_CTRL-V| CTRL-X CTRL-V complete like in : command line
|
||||
|i_CTRL-X_CTRL-Z| CTRL-X CTRL-Z stop completion, keeping the text as-is
|
||||
|i_CTRL-X_CTRL-]| CTRL-X CTRL-] complete tags
|
||||
|i_CTRL-X_s| CTRL-X s spelling suggestions
|
||||
|
||||
|
@ -622,6 +622,8 @@ Completion can be done for:
|
||||
12. Spelling suggestions |i_CTRL-X_s|
|
||||
13. keywords in 'complete' |i_CTRL-N| |i_CTRL-P|
|
||||
|
||||
Additionally, |i_CTRL-X_CTRL-Z| stops completion without changing the text.
|
||||
|
||||
All these, except CTRL-N and CTRL-P, are done in CTRL-X mode. This is a
|
||||
sub-mode of Insert and Replace modes. You enter CTRL-X mode by typing CTRL-X
|
||||
and one of the CTRL-X commands. You exit CTRL-X mode by typing a key that is
|
||||
@ -1022,6 +1024,12 @@ CTRL-P Find previous match for words that start with the
|
||||
other contexts unless a double CTRL-X is used.
|
||||
|
||||
|
||||
Stop completion *compl-stop*
|
||||
|
||||
*i_CTRL-X_CTRL-Z*
|
||||
CTRL-X CTRL-Z Stop completion without changing the text.
|
||||
|
||||
|
||||
FUNCTIONS FOR FINDING COMPLETIONS *complete-functions*
|
||||
|
||||
This applies to 'completefunc' and 'omnifunc'.
|
||||
|
@ -84,6 +84,7 @@
|
||||
#define CTRL_X_SPELL 14
|
||||
#define CTRL_X_LOCAL_MSG 15 ///< only used in "ctrl_x_msgs"
|
||||
#define CTRL_X_EVAL 16 ///< for builtin function complete()
|
||||
#define CTRL_X_CMDLINE_CTRL_X 17 ///< CTRL-X typed in CTRL_X_CMDLINE
|
||||
|
||||
#define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
|
||||
#define CTRL_X_MODE_LINE_OR_EVAL(m) \
|
||||
@ -109,6 +110,7 @@ static char *ctrl_x_msgs[] =
|
||||
N_(" Spelling suggestion (s^N^P)"),
|
||||
N_(" Keyword Local completion (^N^P)"),
|
||||
NULL, // CTRL_X_EVAL doesn't use msg.
|
||||
N_(" Command-line completion (^V^N^P)"),
|
||||
};
|
||||
|
||||
static char *ctrl_x_mode_names[] = {
|
||||
@ -128,7 +130,8 @@ static char *ctrl_x_mode_names[] = {
|
||||
"omni",
|
||||
"spell",
|
||||
NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs"
|
||||
"eval"
|
||||
"eval",
|
||||
"cmdline",
|
||||
};
|
||||
|
||||
static char e_hitend[] = N_("Hit end of paragraph");
|
||||
@ -762,7 +765,8 @@ static int insert_execute(VimState *state, int key)
|
||||
|
||||
s->c = do_digraph(s->c);
|
||||
|
||||
if ((s->c == Ctrl_V || s->c == Ctrl_Q) && ctrl_x_mode == CTRL_X_CMDLINE) {
|
||||
if ((s->c == Ctrl_V || s->c == Ctrl_Q)
|
||||
&& (ctrl_x_mode == CTRL_X_CMDLINE || ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X)) {
|
||||
insert_do_complete(s);
|
||||
return 1;
|
||||
}
|
||||
@ -2028,11 +2032,8 @@ static bool del_char_after_col(int limit_col)
|
||||
*/
|
||||
static void ins_ctrl_x(void)
|
||||
{
|
||||
/* CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X
|
||||
* CTRL-V works like CTRL-N */
|
||||
if (ctrl_x_mode != CTRL_X_CMDLINE) {
|
||||
/* if the next ^X<> won't ADD nothing, then reset
|
||||
* compl_cont_status */
|
||||
if (ctrl_x_mode != CTRL_X_CMDLINE && ctrl_x_mode != CTRL_X_CMDLINE_CTRL_X) {
|
||||
// if the next ^X<> won't ADD nothing, then reset compl_cont_status
|
||||
if (compl_cont_status & CONT_N_ADDS) {
|
||||
compl_cont_status |= CONT_INTRPT;
|
||||
} else {
|
||||
@ -2043,6 +2044,10 @@ static void ins_ctrl_x(void)
|
||||
edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
|
||||
edit_submode_pre = NULL;
|
||||
showmode();
|
||||
} else {
|
||||
// CTRL-X in CTRL-X CTRL-V mode behaves differently to make CTRL-X
|
||||
// CTRL-V look like CTRL-N
|
||||
ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2052,7 +2057,8 @@ bool ctrl_x_mode_not_default(void)
|
||||
return ctrl_x_mode != CTRL_X_NORMAL;
|
||||
}
|
||||
|
||||
// Whether CTRL-X was typed without a following character.
|
||||
// Whether CTRL-X was typed without a following character,
|
||||
// not including when in CTRL-X CTRL-V mode.
|
||||
bool ctrl_x_mode_not_defined_yet(void)
|
||||
{
|
||||
return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET;
|
||||
@ -2104,12 +2110,14 @@ bool vim_is_ctrl_x_key(int c)
|
||||
case 0: // Not in any CTRL-X mode
|
||||
return c == Ctrl_N || c == Ctrl_P || c == Ctrl_X;
|
||||
case CTRL_X_NOT_DEFINED_YET:
|
||||
case CTRL_X_CMDLINE_CTRL_X:
|
||||
return c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
|
||||
|| c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
|
||||
|| c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
|
||||
|| c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
|
||||
|| c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
|
||||
|| c == Ctrl_S || c == Ctrl_K || c == 's';
|
||||
|| c == Ctrl_S || c == Ctrl_K || c == 's'
|
||||
|| c == Ctrl_Z;
|
||||
case CTRL_X_SCROLL:
|
||||
return c == Ctrl_Y || c == Ctrl_E;
|
||||
case CTRL_X_WHOLE_LINE:
|
||||
@ -2163,6 +2171,7 @@ static bool ins_compl_accept_char(int c)
|
||||
return vim_isfilec(c) && !vim_ispathsep(c);
|
||||
|
||||
case CTRL_X_CMDLINE:
|
||||
case CTRL_X_CMDLINE_CTRL_X:
|
||||
case CTRL_X_OMNI:
|
||||
// Command line and Omni completion can work with just about any
|
||||
// printable character, but do stop at white space.
|
||||
@ -3567,6 +3576,26 @@ static bool ins_compl_prep(int c)
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X && c != Ctrl_X) {
|
||||
if (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_Z || ins_compl_pum_key(c)
|
||||
|| !vim_is_ctrl_x_key(c)) {
|
||||
// Not starting another completion mode.
|
||||
ctrl_x_mode = CTRL_X_CMDLINE;
|
||||
|
||||
// CTRL-X CTRL-Z should stop completion without inserting anything
|
||||
if (c == Ctrl_Z) {
|
||||
retval = true;
|
||||
}
|
||||
} else {
|
||||
ctrl_x_mode = CTRL_X_CMDLINE;
|
||||
|
||||
// Other CTRL-X keys first stop completion, then start another
|
||||
// completion mode.
|
||||
ins_compl_prep(' ');
|
||||
ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
|
||||
}
|
||||
}
|
||||
|
||||
// Set "compl_get_longest" when finding the first matches.
|
||||
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
|
||||
|| (ctrl_x_mode == CTRL_X_NORMAL && !compl_started)) {
|
||||
@ -3633,6 +3662,12 @@ static bool ins_compl_prep(int c)
|
||||
case Ctrl_Q:
|
||||
ctrl_x_mode = CTRL_X_CMDLINE;
|
||||
break;
|
||||
case Ctrl_Z:
|
||||
ctrl_x_mode = CTRL_X_NORMAL;
|
||||
edit_submode = NULL;
|
||||
showmode();
|
||||
retval = true;
|
||||
break;
|
||||
case Ctrl_P:
|
||||
case Ctrl_N:
|
||||
/* ^X^P means LOCAL expansion if nothing interrupted (eg we
|
||||
@ -4292,10 +4327,11 @@ static int ins_compl_get_exp(pos_T *ini)
|
||||
break;
|
||||
|
||||
case CTRL_X_CMDLINE:
|
||||
case CTRL_X_CMDLINE_CTRL_X:
|
||||
if (expand_cmdline(&compl_xp, compl_pattern,
|
||||
(int)STRLEN(compl_pattern),
|
||||
&num_matches, &matches) == EXPAND_OK) {
|
||||
ins_compl_add_matches(num_matches, matches, FALSE);
|
||||
ins_compl_add_matches(num_matches, matches, false);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -5135,7 +5171,7 @@ static int ins_complete(int c, bool enable_pum)
|
||||
compl_col += startcol;
|
||||
compl_length = (int)curs_col - startcol;
|
||||
compl_pattern = addstar(line + compl_col, compl_length, EXPAND_FILES);
|
||||
} else if (ctrl_x_mode == CTRL_X_CMDLINE) {
|
||||
} else if (ctrl_x_mode == CTRL_X_CMDLINE || ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X) {
|
||||
compl_pattern = vim_strnsave(line, curs_col);
|
||||
set_cmd_context(&compl_xp, compl_pattern,
|
||||
(int)STRLEN(compl_pattern), curs_col, false);
|
||||
|
@ -497,6 +497,133 @@ func Test_ins_compl_tag_sft()
|
||||
%bwipe!
|
||||
endfunc
|
||||
|
||||
" Test for completing special characters
|
||||
func Test_complete_special_chars()
|
||||
new
|
||||
call setline(1, 'int .*[-\^$ func float')
|
||||
call feedkeys("oin\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>", 'xt')
|
||||
call assert_equal('int .*[-\^$ func float', getline(2))
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test for completion when text is wrapped across lines.
|
||||
func Test_complete_across_line()
|
||||
new
|
||||
call setline(1, ['red green blue', 'one two three'])
|
||||
setlocal textwidth=20
|
||||
exe "normal 2G$a re\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>"
|
||||
call assert_equal(['one two three red', 'green blue one'], getline(2, '$'))
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test for using CTRL-L to add one character when completing matching
|
||||
func Test_complete_add_onechar()
|
||||
new
|
||||
call setline(1, ['wool', 'woodwork'])
|
||||
call feedkeys("Gowoo\<C-P>\<C-P>\<C-P>\<C-L>f", 'xt')
|
||||
call assert_equal('woof', getline(3))
|
||||
|
||||
" use 'ignorecase' and backspace to erase characters from the prefix string
|
||||
" and then add letters using CTRL-L
|
||||
%d
|
||||
set ignorecase backspace=2
|
||||
setlocal complete=.
|
||||
call setline(1, ['workhorse', 'workload'])
|
||||
normal Go
|
||||
exe "normal aWOR\<C-P>\<bs>\<bs>\<bs>\<bs>\<bs>\<bs>\<C-L>r\<C-L>\<C-L>"
|
||||
call assert_equal('workh', getline(3))
|
||||
set ignorecase& backspace&
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test insert completion with 'cindent' (adjust the indent)
|
||||
func Test_complete_with_cindent()
|
||||
new
|
||||
setlocal cindent
|
||||
call setline(1, ['if (i == 1)', " j = 2;"])
|
||||
exe "normal Go{\<CR>i\<C-X>\<C-L>\<C-X>\<C-L>\<CR>}"
|
||||
call assert_equal(['{', "\tif (i == 1)", "\t\tj = 2;", '}'], getline(3, '$'))
|
||||
|
||||
%d
|
||||
call setline(1, ['when while', '{', ''])
|
||||
setlocal cinkeys+==while
|
||||
exe "normal Giwh\<C-P> "
|
||||
call assert_equal("\twhile ", getline('$'))
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test for <CTRL-X> <CTRL-V> completion. Complete commands and functions
|
||||
func Test_complete_cmdline()
|
||||
new
|
||||
exe "normal icaddb\<C-X>\<C-V>"
|
||||
call assert_equal('caddbuffer', getline(1))
|
||||
exe "normal ocall getqf\<C-X>\<C-V>"
|
||||
call assert_equal('call getqflist(', getline(2))
|
||||
exe "normal oabcxyz(\<C-X>\<C-V>"
|
||||
call assert_equal('abcxyz(', getline(3))
|
||||
com! -buffer TestCommand1 echo 'TestCommand1'
|
||||
com! -buffer TestCommand2 echo 'TestCommand2'
|
||||
write TestCommand1Test
|
||||
write TestCommand2Test
|
||||
" Test repeating <CTRL-X> <CTRL-V> and switching to another CTRL-X mode
|
||||
exe "normal oT\<C-X>\<C-V>\<C-X>\<C-V>\<C-X>\<C-F>\<Esc>"
|
||||
call assert_equal('TestCommand2Test', getline(4))
|
||||
call delete('TestCommand1Test')
|
||||
call delete('TestCommand2Test')
|
||||
delcom TestCommand1
|
||||
delcom TestCommand2
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test for <CTRL-X> <CTRL-Z> stopping completion without changing the match
|
||||
func Test_complete_stop()
|
||||
new
|
||||
func Save_mode1()
|
||||
let g:mode1 = mode(1)
|
||||
return ''
|
||||
endfunc
|
||||
func Save_mode2()
|
||||
let g:mode2 = mode(1)
|
||||
return ''
|
||||
endfunc
|
||||
inoremap <F1> <C-R>=Save_mode1()<CR>
|
||||
inoremap <F2> <C-R>=Save_mode2()<CR>
|
||||
call setline(1, ['aaa bbb ccc '])
|
||||
exe "normal A\<C-N>\<C-P>\<F1>\<C-X>\<C-Z>\<F2>\<Esc>"
|
||||
call assert_equal('ic', g:mode1)
|
||||
call assert_equal('i', g:mode2)
|
||||
call assert_equal('aaa bbb ccc ', getline(1))
|
||||
exe "normal A\<C-N>\<Down>\<F1>\<C-X>\<C-Z>\<F2>\<Esc>"
|
||||
call assert_equal('ic', g:mode1)
|
||||
call assert_equal('i', g:mode2)
|
||||
call assert_equal('aaa bbb ccc aaa', getline(1))
|
||||
set completeopt+=noselect
|
||||
exe "normal A \<C-N>\<Down>\<Down>\<C-L>\<C-L>\<F1>\<C-X>\<C-Z>\<F2>\<Esc>"
|
||||
call assert_equal('ic', g:mode1)
|
||||
call assert_equal('i', g:mode2)
|
||||
call assert_equal('aaa bbb ccc aaa bb', getline(1))
|
||||
set completeopt&
|
||||
exe "normal A d\<C-N>\<F1>\<C-X>\<C-Z>\<F2>\<Esc>"
|
||||
call assert_equal('ic', g:mode1)
|
||||
call assert_equal('i', g:mode2)
|
||||
call assert_equal('aaa bbb ccc aaa bb d', getline(1))
|
||||
com! -buffer TestCommand1 echo 'TestCommand1'
|
||||
com! -buffer TestCommand2 echo 'TestCommand2'
|
||||
exe "normal oT\<C-X>\<C-V>\<C-X>\<C-V>\<F1>\<C-X>\<C-Z>\<F2>\<Esc>"
|
||||
call assert_equal('ic', g:mode1)
|
||||
call assert_equal('i', g:mode2)
|
||||
call assert_equal('TestCommand2', getline(2))
|
||||
delcom TestCommand1
|
||||
delcom TestCommand2
|
||||
unlet g:mode1
|
||||
unlet g:mode2
|
||||
iunmap <F1>
|
||||
iunmap <F2>
|
||||
delfunc Save_mode1
|
||||
delfunc Save_mode2
|
||||
close!
|
||||
endfunc
|
||||
|
||||
" Test to ensure 'Scanning...' messages are not recorded in messages history
|
||||
func Test_z1_complete_no_history()
|
||||
new
|
||||
|
Loading…
Reference in New Issue
Block a user