From f90cd620c56b7e03337ec166fe5dfe298f1d2e11 Mon Sep 17 00:00:00 2001 From: glepnir Date: Mon, 23 Feb 2026 03:43:32 +0800 Subject: fix(lsp): vim.lsp.completion clean up triggers on client detach (#38009) Problem: LspDetach didn't clean up stale client refs in triggers table. Solution: create LspDetach autocmd and call disable_completion. --- runtime/lua/vim/lsp/completion.lua | 52 ++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 22 deletions(-) (limited to 'runtime/lua/vim/lsp/completion.lua') diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index f8df714278..119d1d77bb 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -778,6 +778,28 @@ local function get_augroup(bufnr) return string.format('nvim.lsp.completion_%d', bufnr) end +--- @param client_id integer +--- @param bufnr integer +local function disable_completions(client_id, bufnr) + local handle = buf_handles[bufnr] + if not handle then + return + end + + handle.clients[client_id] = nil + if not next(handle.clients) then + buf_handles[bufnr] = nil + api.nvim_del_augroup_by_name(get_augroup(bufnr)) + else + for char, clients in pairs(handle.triggers) do + --- @param c vim.lsp.Client + handle.triggers[char] = vim.tbl_filter(function(c) + return c.id ~= client_id + end, clients) + end + end +end + --- @inlinedoc --- @class vim.lsp.completion.BufferOpts --- @field autotrigger? boolean (default: false) When true, completion triggers automatically based on the server's `triggerCharacters`. @@ -805,6 +827,14 @@ local function enable_completions(client_id, bufnr, opts) -- Set up autocommands. local group = api.nvim_create_augroup(get_augroup(bufnr), { clear = true }) + api.nvim_create_autocmd('LspDetach', { + group = group, + buffer = bufnr, + desc = 'vim.lsp.completion: clean up client on detach', + callback = function(args) + disable_completions(args.data.client_id, args.buf) + end, + }) api.nvim_create_autocmd('CompleteDone', { group = group, buffer = bufnr, @@ -861,28 +891,6 @@ local function enable_completions(client_id, bufnr, opts) end end ---- @param client_id integer ---- @param bufnr integer -local function disable_completions(client_id, bufnr) - local handle = buf_handles[bufnr] - if not handle then - return - end - - handle.clients[client_id] = nil - if not next(handle.clients) then - buf_handles[bufnr] = nil - api.nvim_del_augroup_by_name(get_augroup(bufnr)) - else - for char, clients in pairs(handle.triggers) do - --- @param c vim.lsp.Client - handle.triggers[char] = vim.tbl_filter(function(c) - return c.id ~= client_id - end, clients) - end - end -end - --- Enables or disables completions from the given language client in the given --- buffer. Effects of enabling completions are: --- -- cgit