From 83c7193c119ffe5cef8a86ec290103921c15dc01 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 13 Oct 2025 08:08:53 +0800 Subject: [PATCH] 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 https://github.com/vim/vim/commit/da2dabc6f740b1ed3397797af8a8b0b2ec02bc31 Co-authored-by: Girish Palya --- runtime/doc/insert.txt | 9 ++-- src/nvim/edit.c | 63 +++++++++++++++++++------- test/old/testdir/test_ins_complete.vim | 25 +++++++++- 3 files changed, 76 insertions(+), 21 deletions(-) diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index 3647db389e..fa22b38df3 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -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. |default-mappings| *i_CTRL-U* -CTRL-U Delete all entered characters before the cursor in the current - line. If there are no newly entered characters and - 'backspace' is not empty, delete all characters before the - cursor in the current line. +CTRL-U Delete all characters that were entered after starting Insert + mode and before the cursor in the current line. + If there are no newly entered characters and 'backspace' is + not empty, delete all characters before the cursor in the + current line. If C-indenting is enabled the indent will be adjusted if the line becomes blank. See |i_backspacing| about joining lines. diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 2e75d70802..3a0cc09c10 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -88,6 +88,7 @@ typedef struct { int mincol; int cmdchar; int cmdchar_todo; // cmdchar to handle once in init_prompt + bool ins_just_started; int startln; int count; int c; @@ -144,12 +145,33 @@ static linenr_T o_lnum = 0; 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) { s->did_backspace = true; s->old_topfill = -1; s->replaceState = MODE_REPLACE; s->cmdchar_todo = s->cmdchar; + s->ins_just_started = true; // Remember whether editing was restarted after CTRL-O did_restart_edit = restart_edit; // 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; } + // 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; } @@ -855,17 +893,8 @@ static int insert_handle_key(InsertState *s) case Ctrl_H: s->did_backspace = ins_bs(s->c, BACKSPACE_CHAR, &s->inserted_space); auto_format(false, true); - if (s->did_backspace && ins_compl_has_autocomplete() && !char_avail() - && curwin->w_cursor.col > 0) { - 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; - } + if (s->did_backspace) { + MAY_TRIGGER_AUTOCOMPLETE(s->c); } break; @@ -881,6 +910,9 @@ static int insert_handle_key(InsertState *s) } s->did_backspace = ins_bs(s->c, BACKSPACE_WORD, &s->inserted_space); auto_format(false, true); + if (s->did_backspace) { + MAY_TRIGGER_AUTOCOMPLETE(s->c); + } break; 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); auto_format(false, true); s->inserted_space = false; + if (s->did_backspace) { + MAY_TRIGGER_AUTOCOMPLETE(s->c); + } } break; @@ -1244,11 +1279,7 @@ normalchar: foldOpenCursor(); // Trigger autocompletion if (ins_compl_has_autocomplete() && !char_avail() && vim_isprintc(s->c)) { - redraw_later(curwin, UPD_VALID); - update_screen(); // Show character immediately - ui_flush(); - ins_compl_enable_autocomplete(); - insert_do_complete(s); + TRIGGER_AUTOCOMPLETE(); } break; diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim index b70f6099ea..bfa0c6f2cd 100644 --- a/test/old/testdir/test_ins_complete.vim +++ b/test/old/testdir/test_ins_complete.vim @@ -5528,10 +5528,33 @@ func Test_autocomplete_trigger() call assert_equal(['fodabc', 'fodxyz'], b:matches->mapnew('v:val.word')) 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\\0", 'tx!') + call assert_equal(['fodabc', 'fodxyz', 'foobar', 'fooze'], b:matches->mapnew('v:val.word')) + call feedkeys("Sprefix->fo\\\0", 'tx!') + call assert_equal(['fooze', 'faberge'], b:matches->mapnew('v:val.word')) + call feedkeys("Sprefix->\afo\\\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\a\\0", 'tx!') + call assert_equal(['foobar', 'fooze', 'faberge'], b:matches->mapnew('v:val.word')) + call feedkeys("Sprefix->fooxx\hcw\\0", 'tx!') + call assert_equal(['foobar', 'fooze', 'faberge'], b:matches->mapnew('v:val.word')) + bw! call Ntest_override("char_avail", 0) delfunc NonKeywordComplete - set autocomplete& + delfunc TestComplete + set autocomplete& omnifunc& complete& unlet g:CallCount endfunc