From 8151fc59cf28d8a4ba1693379d06726015b61aa9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 3 Oct 2025 21:10:05 +0800 Subject: [PATCH] vim-patch:9.1.1820: completion: some issues with 'acl' (#36007) Problem: completion: some issues with 'acl' when "preinsert" and "longest" is in 'completeopt' (musonius, after v9.1.1638) Solution: Fix various issues (see details below) (Girish Palya) This commit addresses multiple issues in the 'autocompletedelay' behavior with "preinsert" and "longest": - Prevents spurious characters from being inserted. - Ensures the completion menu is not shown until `autocompletedelay` has expired. - Shows the "preinsert" effect immediately. - Keeps the "preinsert" effect visible even when a character is deleted. fixes: vim/vim#18443 closes: vim/vim#18460 https://github.com/vim/vim/commit/f77c187277c3fd2af7a48f8b15093a3e40ca95a0 Co-authored-by: Girish Palya --- src/nvim/insexpand.c | 16 +++- test/functional/editor/completion_spec.lua | 95 ++++++++++++++++++++++ test/old/testdir/test_ins_complete.vim | 43 +++++++++- 3 files changed, 150 insertions(+), 4 deletions(-) diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 758c2f84dc..9917f34ac4 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -4392,7 +4392,7 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_ st->cur_match_pos, &len, &cont_s_ipos); } if (ptr == NULL || (ins_compl_has_preinsert() - && strcmp(ptr, compl_pattern.data) == 0)) { + && strcmp(ptr, ins_compl_leader()) == 0)) { continue; } @@ -5375,6 +5375,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match || (compl_autocomplete && !ins_compl_has_preinsert()); bool compl_fuzzy_match = (cur_cot_flags & kOptCotFlagFuzzy) != 0; bool compl_preinsert = ins_compl_has_preinsert(); + bool has_autocomplete_delay = (compl_autocomplete && p_acl > 0); // When user complete function return -1 for findstart which is next // time of 'always', compl_shown_match become NULL. @@ -5421,6 +5422,9 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match // Insert the text of the new completion, or the compl_leader. if (!started && ins_compl_preinsert_longest()) { ins_compl_insert(true, true); + if (has_autocomplete_delay) { + update_screen(); // Show the inserted text right away + } } else if (compl_no_insert && !started && !compl_preinsert) { ins_compl_insert_bytes(compl_orig_text.data + get_compl_len(), -1); compl_used_match = false; @@ -5445,8 +5449,10 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match // redraw to show the user what was inserted update_screen(); // TODO(bfredl): no! - // display the updated popup menu - ins_compl_show_pum(); + if (!has_autocomplete_delay) { + // display the updated popup menu + ins_compl_show_pum(); + } // Delete old text to be replaced, since we're still searching and // don't want to match ourselves! @@ -6273,6 +6279,10 @@ int ins_complete(int c, bool enable_pum) ui_flush(); do { if (char_avail()) { + if (ins_compl_preinsert_effect() && ins_compl_win_active(curwin)) { + ins_compl_delete(false); // Remove pre-inserted text + compl_ins_end_col = compl_col; + } ins_compl_restart(); compl_interrupted = true; break; diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index 7dfdb50be9..51d2ba6755 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -1591,6 +1591,7 @@ describe('completion', function() feed('') end) + -- oldtest: Test_fuzzy_select_item_when_acl() it([[first item isn't selected with "fuzzy" and 'acl']], function() screen:try_resize(60, 10) source([[ @@ -1634,4 +1635,98 @@ describe('completion', function() {5:-- INSERT --} | ]]) end) + + -- oldtest: Test_autocompletedelay_longest_preinsert() + it("'autocompletedelay' with 'completeopt' longest/preinsert", function() + source([[ + call setline(1, ['autocomplete', 'autocomxxx']) + set autocomplete completeopt+=longest autocompletedelay=500 + ]]) + screen:expect([[ + ^autocomplete | + autocomxxx | + {1:~ }|*5 + | + ]]) + screen.timeout = 400 + + -- No spurious characters when autocompletedelay is in effect + feed('Goau') + screen:expect([[ + autocomplete | + autocomxxx | + au{102:^tocom} | + {1:~ }|*4 + {5:-- INSERT --} | + ]]) + feed('toc') + screen:expect([[ + autocomplete | + autocomxxx | + autoc{102:^om} | + {1:~ }|*4 + {5:-- INSERT --} | + ]]) + vim.uv.sleep(500) + screen:expect([[ + autocomplete | + autocomxxx | + autoc{102:^om} | + {4:autocomxxx }{1: }| + {4:autocomplete }{1: }| + {1:~ }|*2 + {5:-- INSERT --} | + ]]) + + -- Deleting a char should still show longest text + feed('Saut') + screen:expect([[ + autocomplete | + autocomxxx | + aut{102:^ocom} | + {1:~ }|*4 + {5:-- INSERT --} | + ]]) + feed('') + screen:expect([[ + autocomplete | + autocomxxx | + au{102:^tocom} | + {1:~ }|*4 + {5:-- INSERT --} | + ]]) + vim.uv.sleep(500) + screen:expect([[ + autocomplete | + autocomxxx | + au{102:^tocom} | + {4:autocomxxx }{1: }| + {4:autocomplete }{1: }| + {1:~ }|*2 + {5:-- INSERT --} | + ]]) + + -- Preinsert + command('set completeopt& completeopt+=preinsert') + + -- Show preinserted text right away but display popup later + feed('Sau') + screen:expect([[ + autocomplete | + autocomxxx | + au{102:^tocomplete} | + {1:~ }|*4 + {5:-- INSERT --} | + ]]) + vim.uv.sleep(500) + screen:expect([[ + autocomplete | + autocomxxx | + au{102:^tocomplete} | + {12:autocomplete }{1: }| + {4:autocomxxx }{1: }| + {1:~ }|*2 + {5:-- INSERT --} | + ]]) + end) end) diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim index 60407ad270..2292a0a26d 100644 --- a/test/old/testdir/test_ins_complete.vim +++ b/test/old/testdir/test_ins_complete.vim @@ -5869,7 +5869,7 @@ func Test_autocomplete_longest() call Ntest_override("char_avail", 1) new inoremap =GetLine() - set completeopt=longest autocomplete + set completeopt+=longest autocomplete call setline(1, ["foobar", "foozbar"]) call feedkeys("Go\", 'tx') @@ -6109,4 +6109,45 @@ func Test_refresh_always_with_fuzzy() call Ntest_override("char_avail", 0) endfunc +func Test_autocompletedelay_longest_preinsert() + CheckScreendump + let lines =<< trim [SCRIPT] + call setline(1, ['autocomplete', 'autocomxxx']) + set autocomplete completeopt+=longest autocompletedelay=500 + [SCRIPT] + call writefile(lines, 'XTest_autocompletedelay', 'D') + let buf = RunVimInTerminal('-S XTest_autocompletedelay', {'rows': 10}) + + " No spurious characters when autocompletedelay is in effect + call term_sendkeys(buf, "Goau") + sleep 10m + call term_sendkeys(buf, "toc") + sleep 100m + call VerifyScreenDump(buf, 'Test_autocompletedelay_longest_1', {}) + sleep 500m + call VerifyScreenDump(buf, 'Test_autocompletedelay_longest_2', {}) + + " Deleting a char should still show longest text + call term_sendkeys(buf, "\Saut") + sleep 10m + call term_sendkeys(buf, "\") + sleep 100m + call VerifyScreenDump(buf, 'Test_autocompletedelay_longest_3', {}) + sleep 500m + call VerifyScreenDump(buf, 'Test_autocompletedelay_longest_4', {}) + + " Preinsert + call term_sendkeys(buf, "\:set completeopt& completeopt+=preinsert\") + + " Show preinserted text right away but display popup later + call term_sendkeys(buf, "\Sau") + sleep 100m + call VerifyScreenDump(buf, 'Test_autocompletedelay_preinsert_1', {}) + sleep 500m + call VerifyScreenDump(buf, 'Test_autocompletedelay_preinsert_2', {}) + + call term_sendkeys(buf, "\") + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab nofoldenable