From da2dabc6f740b1ed3397797af8a8b0b2ec02bc31 Mon Sep 17 00:00:00 2001 From: Girish Palya Date: Sun, 12 Oct 2025 14:37:02 +0000 Subject: [PATCH] patch 9.1.1850: completion: not triggered after i_Ctrl-W/i_Ctrl-U Problem: completion: not triggered after i_Ctrl-W/i_Ctrl-U Solution: Trigger autocomplete when entering Insert mode (Girish Palya). fixes: #18535 closes: #18543 Signed-off-by: Girish Palya Signed-off-by: Christian Brabandt --- runtime/doc/insert.txt | 11 ++--- src/edit.c | 70 +++++++++++++++++++++++-------- src/testdir/test_ins_complete.vim | 25 ++++++++++- src/version.c | 2 + 4 files changed, 84 insertions(+), 24 deletions(-) diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index 914e9fc83a..5ed3e803a7 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -1,4 +1,4 @@ -*insert.txt* For Vim version 9.1. Last change: 2025 Sep 16 +*insert.txt* For Vim version 9.1. Last change: 2025 Oct 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -80,10 +80,11 @@ CTRL-W Delete the word before the cursor (see |i_backspacing| about joining lines). See the section "word motions", |word-motions|, for the definition of a word. *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/edit.c b/src/edit.c index 2a765467d6..891d51cf95 100644 --- a/src/edit.c +++ b/src/edit.c @@ -100,6 +100,25 @@ static int ins_need_undo; // call u_save() before inserting a static int dont_sync_undo = FALSE; // CTRL-G U prevents syncing undo for // the next left/right cursor key +#define TRIGGER_AUTOCOMPLETE() \ + do { \ + update_screen(UPD_VALID); /* Show char (deletion) immediately */ \ + out_flush(); \ + ins_compl_enable_autocomplete(); \ + goto docomplete; \ + } 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) + /* * edit(): Start inserting text. * @@ -146,6 +165,7 @@ edit( #ifdef FEAT_CONCEAL int cursor_line_was_concealed; #endif + int ins_just_started = TRUE; // Remember whether editing was restarted after CTRL-O. did_restart_edit = restart_edit; @@ -593,6 +613,30 @@ edit( // Got here from normal mode when bracketed paste started. c = K_PS; else + { + // Trigger autocomplete when entering Insert mode, either directly + // or via change commands like 'ciw', 'cw', etc., before the first + // character is typed. + if (ins_just_started) + { + ins_just_started = FALSE; + if (ins_compl_has_autocomplete() && !char_avail() + && curwin->w_cursor.col > 0) + { + c = char_before_cursor(); + if (vim_isprintc(c)) + { + ins_compl_enable_autocomplete(); + ins_compl_init_get_longest(); +#ifdef FEAT_RIGHTLEFT + if (p_hkmap) + c = hkmap(c); // Hebrew mode mapping +#endif + goto docomplete; + } + } + } + do { c = safe_vgetc(); @@ -622,6 +666,7 @@ edit( goto doESCkey; } } while (c == K_IGNORE || c == K_NOP); + } // Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. did_cursorhold = TRUE; @@ -991,18 +1036,8 @@ doESCkey: case Ctrl_H: did_backspace = ins_bs(c, BACKSPACE_CHAR, &inserted_space); auto_format(FALSE, TRUE); - if (did_backspace && ins_compl_has_autocomplete() && !char_avail() - && curwin->w_cursor.col > 0) - { - c = char_before_cursor(); - if (vim_isprintc(c)) - { - update_screen(UPD_VALID); // Show char deletion immediately - out_flush(); - ins_compl_enable_autocomplete(); - goto docomplete; // Trigger autocompletion - } - } + if (did_backspace) + MAY_TRIGGER_AUTOCOMPLETE(c); break; case Ctrl_W: // delete word before the cursor @@ -1020,6 +1055,8 @@ doESCkey: #endif did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space); auto_format(FALSE, TRUE); + if (did_backspace) + MAY_TRIGGER_AUTOCOMPLETE(c); break; case Ctrl_U: // delete all inserted text in current line @@ -1031,6 +1068,8 @@ doESCkey: did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space); auto_format(FALSE, TRUE); inserted_space = FALSE; + if (did_backspace) + MAY_TRIGGER_AUTOCOMPLETE(c); break; case K_LEFTMOUSE: // mouse keys @@ -1424,12 +1463,7 @@ normalchar: // Trigger autocompletion if (ins_compl_has_autocomplete() && !char_avail() && vim_isprintc(c)) - { - update_screen(UPD_VALID); // Show character immediately - out_flush(); - ins_compl_enable_autocomplete(); - goto docomplete; - } + TRIGGER_AUTOCOMPLETE(); break; } // end of switch (c) diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index 23c84b28b1..6d492373c4 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -5416,10 +5416,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 test_override("char_avail", 0) delfunc NonKeywordComplete - set autocomplete& + delfunc TestComplete + set autocomplete& omnifunc& complete& unlet g:CallCount endfunc diff --git a/src/version.c b/src/version.c index c28ce040a6..3f6baf6bb2 100644 --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1850, /**/ 1849, /**/