vim-patch:9.1.1850: completion: not triggered after i_Ctrl-W/i_Ctrl-U (#36156)

Problem:  completion: not triggered after i_Ctrl-W/i_Ctrl-U
Solution: Trigger autocomplete when entering Insert mode
          (Girish Palya).

fixes: vim/vim#18535
closes: vim/vim#18543

da2dabc6f7

Co-authored-by: Girish Palya <girishji@gmail.com>
This commit is contained in:
zeertzjq
2025-10-13 08:08:53 +08:00
committed by GitHub
parent 72b0bfa1fb
commit 83c7193c11
3 changed files with 76 additions and 21 deletions

View File

@@ -69,10 +69,11 @@ CTRL-W Delete the word before the cursor (see |i_backspacing| about
By default, sets a new undo point before deleting. By default, sets a new undo point before deleting.
|default-mappings| |default-mappings|
*i_CTRL-U* *i_CTRL-U*
CTRL-U Delete all entered characters before the cursor in the current CTRL-U Delete all characters that were entered after starting Insert
line. If there are no newly entered characters and mode and before the cursor in the current line.
'backspace' is not empty, delete all characters before the If there are no newly entered characters and 'backspace' is
cursor in the current line. not empty, delete all characters before the cursor in the
current line.
If C-indenting is enabled the indent will be adjusted if the If C-indenting is enabled the indent will be adjusted if the
line becomes blank. line becomes blank.
See |i_backspacing| about joining lines. See |i_backspacing| about joining lines.

View File

@@ -88,6 +88,7 @@ typedef struct {
int mincol; int mincol;
int cmdchar; int cmdchar;
int cmdchar_todo; // cmdchar to handle once in init_prompt int cmdchar_todo; // cmdchar to handle once in init_prompt
bool ins_just_started;
int startln; int startln;
int count; int count;
int c; int c;
@@ -144,12 +145,33 @@ static linenr_T o_lnum = 0;
static kvec_t(char) replace_stack = KV_INITIAL_VALUE; static kvec_t(char) replace_stack = KV_INITIAL_VALUE;
#define TRIGGER_AUTOCOMPLETE() \
do { \
redraw_later(curwin, UPD_VALID); \
update_screen(); /* Show char deletion immediately */ \
ui_flush(); \
ins_compl_enable_autocomplete(); \
insert_do_complete(s); \
break; \
} while (0)
#define MAY_TRIGGER_AUTOCOMPLETE(c) \
do { \
if (ins_compl_has_autocomplete() && !char_avail() && curwin->w_cursor.col > 0) { \
(c) = char_before_cursor(); \
if (vim_isprintc(c)) { \
TRIGGER_AUTOCOMPLETE(); \
} \
} \
} while (0)
static void insert_enter(InsertState *s) static void insert_enter(InsertState *s)
{ {
s->did_backspace = true; s->did_backspace = true;
s->old_topfill = -1; s->old_topfill = -1;
s->replaceState = MODE_REPLACE; s->replaceState = MODE_REPLACE;
s->cmdchar_todo = s->cmdchar; s->cmdchar_todo = s->cmdchar;
s->ins_just_started = true;
// Remember whether editing was restarted after CTRL-O // Remember whether editing was restarted after CTRL-O
did_restart_edit = restart_edit; did_restart_edit = restart_edit;
// sleep before redrawing, needed for "CTRL-O :" that results in an // sleep before redrawing, needed for "CTRL-O :" that results in an
@@ -532,6 +554,22 @@ static int insert_check(VimState *state)
dont_sync_undo = kFalse; dont_sync_undo = kFalse;
} }
// Trigger autocomplete when entering Insert mode, either directly
// or via change commands like 'ciw', 'cw', etc., before the first
// character is typed.
if (s->ins_just_started) {
s->ins_just_started = false;
if (ins_compl_has_autocomplete() && !char_avail() && curwin->w_cursor.col > 0) {
s->c = char_before_cursor();
if (vim_isprintc(s->c)) {
ins_compl_enable_autocomplete();
ins_compl_init_get_longest();
insert_do_complete(s);
return 1;
}
}
}
return 1; return 1;
} }
@@ -855,17 +893,8 @@ static int insert_handle_key(InsertState *s)
case Ctrl_H: case Ctrl_H:
s->did_backspace = ins_bs(s->c, BACKSPACE_CHAR, &s->inserted_space); s->did_backspace = ins_bs(s->c, BACKSPACE_CHAR, &s->inserted_space);
auto_format(false, true); auto_format(false, true);
if (s->did_backspace && ins_compl_has_autocomplete() && !char_avail() if (s->did_backspace) {
&& curwin->w_cursor.col > 0) { MAY_TRIGGER_AUTOCOMPLETE(s->c);
s->c = char_before_cursor();
if (vim_isprintc(s->c)) {
redraw_later(curwin, UPD_VALID);
update_screen(); // Show char deletion immediately
ui_flush();
ins_compl_enable_autocomplete();
insert_do_complete(s); // Trigger autocompletion
return 1;
}
} }
break; break;
@@ -881,6 +910,9 @@ static int insert_handle_key(InsertState *s)
} }
s->did_backspace = ins_bs(s->c, BACKSPACE_WORD, &s->inserted_space); s->did_backspace = ins_bs(s->c, BACKSPACE_WORD, &s->inserted_space);
auto_format(false, true); auto_format(false, true);
if (s->did_backspace) {
MAY_TRIGGER_AUTOCOMPLETE(s->c);
}
break; break;
case Ctrl_U: // delete all inserted text in current line case Ctrl_U: // delete all inserted text in current line
@@ -891,6 +923,9 @@ static int insert_handle_key(InsertState *s)
s->did_backspace = ins_bs(s->c, BACKSPACE_LINE, &s->inserted_space); s->did_backspace = ins_bs(s->c, BACKSPACE_LINE, &s->inserted_space);
auto_format(false, true); auto_format(false, true);
s->inserted_space = false; s->inserted_space = false;
if (s->did_backspace) {
MAY_TRIGGER_AUTOCOMPLETE(s->c);
}
} }
break; break;
@@ -1244,11 +1279,7 @@ normalchar:
foldOpenCursor(); foldOpenCursor();
// Trigger autocompletion // Trigger autocompletion
if (ins_compl_has_autocomplete() && !char_avail() && vim_isprintc(s->c)) { if (ins_compl_has_autocomplete() && !char_avail() && vim_isprintc(s->c)) {
redraw_later(curwin, UPD_VALID); TRIGGER_AUTOCOMPLETE();
update_screen(); // Show character immediately
ui_flush();
ins_compl_enable_autocomplete();
insert_do_complete(s);
} }
break; break;

View File

@@ -5528,10 +5528,33 @@ func Test_autocomplete_trigger()
call assert_equal(['fodabc', 'fodxyz'], b:matches->mapnew('v:val.word')) call assert_equal(['fodabc', 'fodxyz'], b:matches->mapnew('v:val.word'))
call assert_equal(-1, b:selected) call assert_equal(-1, b:selected)
" Test 8: Ctrl_W / Ctrl_U (delete word/line) should restart autocompletion
func! TestComplete(findstart, base)
if a:findstart
return col('.') - 1
endif
return ['fooze', 'faberge']
endfunc
set omnifunc=TestComplete
set complete+=o
call feedkeys("Sprefix->fo\<F2>\<Esc>0", 'tx!')
call assert_equal(['fodabc', 'fodxyz', 'foobar', 'fooze'], b:matches->mapnew('v:val.word'))
call feedkeys("Sprefix->fo\<C-W>\<F2>\<Esc>0", 'tx!')
call assert_equal(['fooze', 'faberge'], b:matches->mapnew('v:val.word'))
call feedkeys("Sprefix->\<Esc>afo\<C-U>\<F2>\<Esc>0", 'tx!')
call assert_equal(['fooze', 'faberge'], b:matches->mapnew('v:val.word'))
" Test 9: Trigger autocomplete immediately upon entering Insert mode
call feedkeys("Sprefix->foo\<Esc>a\<F2>\<Esc>0", 'tx!')
call assert_equal(['foobar', 'fooze', 'faberge'], b:matches->mapnew('v:val.word'))
call feedkeys("Sprefix->fooxx\<Esc>hcw\<F2>\<Esc>0", 'tx!')
call assert_equal(['foobar', 'fooze', 'faberge'], b:matches->mapnew('v:val.word'))
bw! bw!
call Ntest_override("char_avail", 0) call Ntest_override("char_avail", 0)
delfunc NonKeywordComplete delfunc NonKeywordComplete
set autocomplete& delfunc TestComplete
set autocomplete& omnifunc& complete&
unlet g:CallCount unlet g:CallCount
endfunc endfunc