fix(completion): fix inconsistent Enter behavior (#30196)

Problem:  Behavior of Enter in completion depends on typing speed.
Solution: Don't make whether Enter selects original text depend on
          whether completion has been interrupted, which can happen
          interactively with a slow completion function.
This commit is contained in:
zeertzjq 2024-08-31 04:03:30 +08:00 committed by GitHub
parent 42ed0ffad9
commit 55dc482e75
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 71 additions and 5 deletions

View File

@ -1792,6 +1792,13 @@ int ins_compl_bs(void)
return NUL;
}
/// Check if the complete function returned "always" in the "refresh" dictionary item.
static bool ins_compl_refresh_always(void)
FUNC_ATTR_PURE
{
return (ctrl_x_mode_function() || ctrl_x_mode_omni()) && compl_opt_refresh_always;
}
/// Check that we need to find matches again, ins_compl_restart() is to
/// be called.
static bool ins_compl_need_restart(void)
@ -1799,9 +1806,7 @@ static bool ins_compl_need_restart(void)
{
// Return true if we didn't complete finding matches or when the
// "completefunc" returned "always" in the "refresh" dictionary item.
return compl_was_interrupted
|| ((ctrl_x_mode_function() || ctrl_x_mode_omni())
&& compl_opt_refresh_always);
return compl_was_interrupted || ins_compl_refresh_always();
}
/// Called after changing "compl_leader".
@ -1834,7 +1839,7 @@ static void ins_compl_new_leader(void)
// Don't let Enter select the original text when there is no popup menu.
// Don't let Enter select when use user function and refresh_always is set
if (compl_match_array == NULL || ins_compl_need_restart()) {
if (compl_match_array == NULL || ins_compl_refresh_always()) {
compl_enter_selects = false;
}
}

View File

@ -327,7 +327,7 @@ describe('completion', function()
end
end)
describe('refresh:always', function()
describe('with refresh:always and noselect', function()
before_each(function()
source([[
function! TestCompletion(findstart, base) abort
@ -459,6 +459,67 @@ describe('completion', function()
June
June]])
end)
it('Enter does not select original text', function()
feed('iJ<C-x><C-u>')
poke_eventloop()
feed('u')
poke_eventloop()
feed('<CR>')
expect([[
Ju
]])
feed('J<C-x><C-u>')
poke_eventloop()
feed('<CR>')
expect([[
Ju
J
]])
end)
end)
describe('with noselect but not refresh:always', function()
before_each(function()
source([[
function! TestCompletion(findstart, base) abort
if a:findstart
let line = getline('.')
let start = col('.') - 1
while start > 0 && line[start - 1] =~ '\a'
let start -= 1
endwhile
return start
else
let ret = []
for m in split("January February March April May June July August September October November December")
if m =~ a:base " match by regex
call add(ret, m)
endif
endfor
return {'words':ret}
endif
endfunction
set completeopt=menuone,noselect
set completefunc=TestCompletion
]])
end)
it('Enter selects original text after adding leader', function()
feed('iJ<C-x><C-u>')
poke_eventloop()
feed('u')
poke_eventloop()
feed('<CR>')
expect('Ju')
feed('<Esc>')
poke_eventloop()
-- The behavior should be the same when completion has been interrupted,
-- which can happen interactively if the completion function is slow.
feed('SJ<C-x><C-u>u<CR>')
expect('Ju')
end)
end)
describe('with a lot of items', function()