fix(picker.lsp): some LSP servers notify completion before sending the actual result. See #2372

This commit is contained in:
Folke Lemaitre 2025-10-30 11:01:07 +01:00
parent 87804d67b9
commit aa8a318779
No known key found for this signature in database
GPG key ID: 9B52594D560070AB

View file

@ -128,6 +128,22 @@ function R.new()
return self
end
---@param clients vim.lsp.Client[]
---@param ctx lsp.HandlerContext
function R:debug(clients, ctx)
Snacks.debug.inspect({
error = "LSP request callback yielded after done.",
method = ctx.method,
requests = vim.deepcopy(self.requests),
pending = self.pending,
client_id = ctx.client_id,
---@param c vim.lsp.Client
clients = vim.tbl_map(function(c)
return { id = c.id, name = c.name }
end, clients),
})
end
---@param client_id number
---@param request_id number
---@param completed? boolean
@ -154,14 +170,14 @@ function R:cancel()
end
end
function R:autocmd()
function R:track_cancel()
if self.autocmd_id then
return
end
self.autocmd_id = vim.api.nvim_create_autocmd("LspRequest", {
group = vim.api.nvim_create_augroup("snacks.picker.lsp." .. R._id, { clear = true }),
group = vim.api.nvim_create_augroup("snacks.picker.lsp.cancel." .. R._id, { clear = true }),
callback = function(ev)
if ev.data.request.type == "complete" or ev.data.request.type == "cancel" then
if ev.data.request.type == "cancel" then
self:track(ev.data.client_id, ev.data.request_id, true)
end
end,
@ -176,31 +192,24 @@ end
function R:request(buf, method, params, cb)
self.pending = self.pending + 1
vim.schedule(function()
self:autocmd() -- setup autocmd here, since this must be called in the main loop
self:track_cancel() -- setup autocmd here, since this must be called in the main loop
---@diagnostic disable-next-line: param-type-mismatch
local clients = type(buf) == "number" and M.get_clients(buf, method) or { wrap(buf) }
for _, client in ipairs(clients) do
local p, done = params(client), false
local status, request_id = client:request(method, p, function(err, result)
local done = false
local status, request_id ---@type boolean, number?
status, request_id = client:request(method, params(client), function(err, result, ctx)
done = true
if not err and result and not self.async:aborted() then
if not self.async:running() then
Snacks.debug.inspect({
error = "LSP request callback yielded after done.",
method = method,
requests = vim.deepcopy(self.requests),
pending = self.pending,
client_id = client.id,
client_name = client.name,
---@param c vim.lsp.Client
clients = vim.tbl_map(function(c)
return { id = c.id, name = c.name }
end, clients),
})
if not self.async:running() or self.pending <= 0 then
self:debug(clients, ctx)
end
cb(client, result, p)
cb(client, result, ctx.params)
end
if request_id then
self:track(client.id, request_id, true)
end
end)
-- skip tracking if the request failed