diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index eea35c878f..42fe470f14 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -571,7 +571,10 @@ local function on_insert_char_pre(handle) local char = api.nvim_get_vvar('char') local matched_clients = handle.triggers[char] - if not completion_timer and matched_clients then + -- Discard pending trigger char, complete the "latest" one. + -- Can happen if a mapping inputs multiple trigger chars simultaneously. + reset_timer() + if matched_clients then completion_timer = assert(vim.uv.new_timer()) completion_timer:start(25, 0, function() reset_timer() diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index ec9760a068..6570bbb95c 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -1037,6 +1037,34 @@ describe('vim.lsp.completion: protocol', function() end) end) + it('treats 2-triggers-at-once as "last char wins"', function() + local results1 = { + isIncomplete = false, + items = { + { + label = 'first', + }, + }, + } + create_server('dummy1', results1, { trigger_chars = { '-' } }) + local results2 = { + isIncomplete = false, + items = { + { + label = 'second', + }, + }, + } + create_server('dummy2', results2, { trigger_chars = { '>' } }) + + feed('i->') + + assert_matches(function(matches) + eq(1, #matches) + eq('second', matches[1].word) + end) + end) + it('executes commands', function() local completion_list = { isIncomplete = false,