From b42dc232c53211e718a39d8df2f80402f7ad9ac6 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Thu, 13 Feb 2025 05:08:11 -0500 Subject: fix(lsp): autotrigger should only trigger on client's triggerCharacters (#32266) Problem: autotrigger option of vim.lsp.completion.enable() would trigger all clients, as long as it matched at least one client's triggerCharacters. Solution: trigger only the clients with triggerCharacters matching the character. overtriggering still happens if any client returns isIncomplete=true (this case is more involved). Co-authored-by: Mathias Fussenegger --- runtime/lua/vim/lsp/completion.lua | 7 +++-- test/functional/plugin/lsp/completion_spec.lua | 39 ++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index cf6d07745f..09d38bbce3 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -518,11 +518,14 @@ local function on_insert_char_pre(handle) end local char = api.nvim_get_vvar('char') - if not completion_timer and handle.triggers[char] then + local matched_clients = handle.triggers[char] + if not completion_timer and matched_clients then completion_timer = assert(vim.uv.new_timer()) completion_timer:start(25, 0, function() reset_timer() - vim.schedule(M.trigger) + vim.schedule(function() + trigger(api.nvim_get_current_buf(), matched_clients) + end) end) end end diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 4e90c2fd1b..0b202724ed 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -770,13 +770,14 @@ end) --- @param name string --- @param completion_result lsp.CompletionList +--- @param trigger_chars? string[] --- @return integer -local function create_server(name, completion_result) +local function create_server(name, completion_result, trigger_chars) return exec_lua(function() local server = _G._create_server({ capabilities = { completionProvider = { - triggerCharacters = { '.' }, + triggerCharacters = trigger_chars or { '.' }, }, }, handlers = { @@ -793,6 +794,7 @@ local function create_server(name, completion_result) cmd = server.cmd, on_attach = function(client, bufnr0) vim.lsp.completion.enable(true, client.id, bufnr0, { + autotrigger = trigger_chars ~= nil, convert = function(item) return { abbr = item.label:gsub('%b()', '') } end, @@ -957,6 +959,39 @@ describe('vim.lsp.completion: protocol', function() end) end) + it('insert char triggers clients matching trigger characters', function() + local results1 = { + isIncomplete = false, + items = { + { + label = 'hello', + }, + }, + } + create_server('dummy1', results1, { 'e' }) + local results2 = { + isIncomplete = false, + items = { + { + label = 'hallo', + }, + }, + } + create_server('dummy2', results2, { 'h' }) + + feed('h') + exec_lua(function() + vim.v.char = 'h' + vim.cmd.startinsert() + vim.api.nvim_exec_autocmds('InsertCharPre', {}) + end) + + assert_matches(function(matches) + eq(1, #matches) + eq('hallo', matches[1].word) + end) + end) + it('executes commands', function() local completion_list = { isIncomplete = false, -- cgit