From b23fbb37044b2c2aed4c0e65f8ef261be789a03c Mon Sep 17 00:00:00 2001 From: Oscar Wallberg Date: Sun, 19 Apr 2026 00:41:05 +0200 Subject: [PATCH] fix(lsp.completion): add logging for request failures --- lua/lsp/completion/init.lua | 46 ++++++++++++------ lua/lsp/completion/popup.lua | 41 +++++++++------- lua/lsp/completion/session.lua | 88 ++++++++++++++++++---------------- 3 files changed, 101 insertions(+), 74 deletions(-) diff --git a/lua/lsp/completion/init.lua b/lua/lsp/completion/init.lua index 75a063c..b1d06fb 100644 --- a/lua/lsp/completion/init.lua +++ b/lua/lsp/completion/init.lua @@ -1,5 +1,6 @@ local Item = require("lsp.completion.item") local Popup = require("lsp.completion.popup") +local log = require("log") local session = require("lsp.completion.session") local GROUP = vim.api.nvim_create_augroup("ow.lsp.completion", { clear = true }) @@ -113,6 +114,7 @@ function M.setup() return end + ---@param target ow.lsp.completion.Item local function apply(target) local raw = target.raw if raw.additionalTextEdits then @@ -123,10 +125,22 @@ function M.setup() ) end if raw.command then - client:request("workspace/executeCommand", { + local method = + vim.lsp.protocol.Methods.workspace_executeCommand + client:request(method, { command = raw.command.command, arguments = raw.command.arguments, - }, nil, ev.buf) + }, function(err) + if err then + log.warning( + "client %d: %s failed for %s: %s", + client.id, + method, + raw.command.title, + err.message + ) + end + end, ev.buf) end if target.snippet then local word = completed.word or "" @@ -157,18 +171,22 @@ function M.setup() and not item.raw.additionalTextEdits and not item.raw.command then - client:request( - vim.lsp.protocol.Methods.completionItem_resolve, - item.raw, - function(err, resolved) - if err or not resolved then - return - end - item:apply_resolved(resolved) - apply(item) - end, - ev.buf - ) + local method = vim.lsp.protocol.Methods.completionItem_resolve + client:request(method, item.raw, function(err, resolved) + if err then + log.warning( + "client %d: %s failed: %s", + client.id, + method, + err.message + ) + end + if err or not resolved then + return + end + item:apply_resolved(resolved) + apply(item) + end, ev.buf) else apply(item) end diff --git a/lua/lsp/completion/popup.lua b/lua/lsp/completion/popup.lua index ef5b3c1..888698a 100644 --- a/lua/lsp/completion/popup.lua +++ b/lua/lsp/completion/popup.lua @@ -1,3 +1,4 @@ +local log = require("log") local MAX_WIDTH = 80 local MAX_HEIGHT = 20 local HALF_HEIGHT = math.floor(MAX_HEIGHT / 2) @@ -114,24 +115,28 @@ end function Popup:dispatch_resolve(client, item, ft, pum, word, buf) self:cancel_pending() self.resolved = nil - local _, request_id = client:request( - vim.lsp.protocol.Methods.completionItem_resolve, - item.raw, - function(err, result) - self.pending = nil - if err or not result then - return - end - local cur = vim.fn.complete_info({ "completed" }) - if (vim.tbl_get(cur, "completed", "word") or "") ~= word then - return - end - item:apply_resolved(result) - self.resolved = { word = word, item = item } - self:show(item, ft, pum) - end, - buf - ) + local method = vim.lsp.protocol.Methods.completionItem_resolve + local _, request_id = client:request(method, item.raw, function(err, result) + if err then + log.warning( + "client %d: %s failed: %s", + client.id, + method, + err.message + ) + end + self.pending = nil + if err or not result then + return + end + local cur = vim.fn.complete_info({ "completed" }) + if (vim.tbl_get(cur, "completed", "word") or "") ~= word then + return + end + item:apply_resolved(result) + self.resolved = { word = word, item = item } + self:show(item, ft, pum) + end, buf) if request_id then self.pending = { client = client, id = request_id } end diff --git a/lua/lsp/completion/session.lua b/lua/lsp/completion/session.lua index 81e991e..159c379 100644 --- a/lua/lsp/completion/session.lua +++ b/lua/lsp/completion/session.lua @@ -3,6 +3,7 @@ local Item = require("lsp.completion.item") local kind = require("lsp.kind") +local log = require("log") local util = require("util") local REQUEST_DEBOUNCE_MS = 50 @@ -198,53 +199,56 @@ function Session:dispatch(trigger_kind, trigger_char, manual) triggerKind = trigger_kind, triggerCharacter = trigger_char, } - self.cancel = vim.lsp.buf_request_all( - buf, - vim.lsp.protocol.Methods.textDocument_completion, - params, - function(result) + local method = vim.lsp.protocol.Methods.textDocument_completion + self.cancel = vim.lsp.buf_request_all(buf, method, params, function(result) + if self.generation ~= gen then + return + end + vim.schedule(function() + -- Re-check: another dispatch may have fired between response + -- and the scheduled callback running. if self.generation ~= gen then return end - vim.schedule(function() - -- Re-check: another dispatch may have fired between response - -- and the scheduled callback running. - if self.generation ~= gen then - return + if vim.fn.mode() ~= "i" then + return + end + local word_start, cursor = word_bounds() + if + not self.manual + and not self.trigger_char + and word_start == cursor + then + return + end + self.is_incomplete = false + for client_id, response in pairs(result) do + if response.err then + log.warning( + "client %d: %s failed: %s", + client_id, + method, + response.err.message + ) end - if vim.fn.mode() ~= "i" then - return + local r = response.result + if type(r) == "table" and r.isIncomplete then + self.is_incomplete = true + break end - local word_start, cursor = word_bounds() - if - not self.manual - and not self.trigger_char - and word_start == cursor - then - return + end + local start = word_start + for _, response in pairs(result) do + local pos = edit_start(response) + if pos then + start = pos.character + break end - self.is_incomplete = false - for _, response in pairs(result) do - local r = response.result - if type(r) == "table" and r.isIncomplete then - self.is_incomplete = true - break - end - end - local start = word_start - for _, response in pairs(result) do - local pos = edit_start(response) - if pos then - start = pos.character - break - end - end - local base = - vim.api.nvim_get_current_line():sub(start + 1, cursor) - vim.fn.complete(start + 1, build_items(result, base)) - end) - end - ) + end + local base = vim.api.nvim_get_current_line():sub(start + 1, cursor) + vim.fn.complete(start + 1, build_items(result, base)) + end) + end) end local session = Session.new() @@ -284,7 +288,7 @@ function M.on_insert_char_pre() local kind_num = is_trigger and vim.lsp.protocol.CompletionTriggerKind.TriggerCharacter or vim.lsp.protocol.CompletionTriggerKind.Invoked - dispatcher:call(nil, kind_num, is_trigger and char or nil) + dispatcher(kind_num, is_trigger and char or nil) end return M