From 02067a9892076a054e1756c7678c38ddd0d958e4 Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Wed, 26 Nov 2025 16:28:23 +0800 Subject: [PATCH] feat(lsp): support diagnostic refresh request --- runtime/doc/lsp.txt | 1 + runtime/doc/news.txt | 2 ++ runtime/lua/vim/lsp/diagnostic.lua | 20 +++++++++++++++++++ runtime/lua/vim/lsp/handlers.lua | 5 +++++ runtime/lua/vim/lsp/protocol.lua | 2 +- .../functional/plugin/lsp/diagnostic_spec.lua | 14 +++++++++++++ 6 files changed, 43 insertions(+), 1 deletion(-) diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index dd30bff204..88db9cdb87 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -360,6 +360,7 @@ They are also listed below. - `'workspace/applyEdit'` - `'workspace/configuration'` - `'workspace/executeCommand'` +- `'workspace/diagnostic/refresh'` - `'workspace/inlayHint/refresh'` - `'workspace/semanticTokens/refresh'` - `'workspace/symbol'` diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 3de53593f1..a02eb2773a 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -282,6 +282,8 @@ LSP • |vim.lsp.ClientConfig| has an `exit_timeout` field to control the timeout of client force stopping. Defaults to `false`. • |Client:stop()| now uses the `Client.exit_timeout` field to control the default of `force`. +• Support for `workspace/diagnostic/refresh`: + https://microsoft.github.io/language-server-protocol/specification/#diagnostic_refresh LUA diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 75ff8ca200..7ca5b633dc 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -388,6 +388,26 @@ local function refresh(bufnr, client_id, only_visible) end end +--- |lsp-handler| for the method `workspace/diagnostic/refresh` +---@param ctx lsp.HandlerContext +---@private +function M.on_refresh(err, _, ctx) + if err then + return vim.NIL + end + for bufnr in pairs(vim.lsp.get_client_by_id(ctx.client_id).attached_buffers or {}) do + for _, winid in ipairs(api.nvim_list_wins()) do + if api.nvim_win_get_buf(winid) == bufnr then + if bufstates[bufnr] and bufstates[bufnr].pull_kind == 'document' then + refresh(bufnr) + end + end + end + end + + return vim.NIL +end + --- Enable pull diagnostics for a buffer ---@param bufnr (integer) Buffer handle, or 0 for current function M._enable(bufnr) diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index e61edc7be6..4bfe09af57 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -649,6 +649,11 @@ RSC['window/showDocument'] = function(_, params, ctx) return { success = success or false } end +---@see https://microsoft.github.io/language-server-protocol/specification/#diagnostic_refresh +RSC['workspace/diagnostic/refresh'] = function(err, result, ctx) + return vim.lsp.diagnostic.on_refresh(err, result, ctx) +end + ---@see https://microsoft.github.io/language-server-protocol/specification/#workspace_inlayHint_refresh RSC['workspace/inlayHint/refresh'] = function(err, result, ctx) return vim.lsp.inlay_hint.on_refresh(err, result, ctx) diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index d5907666cb..9c4989b7b1 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -609,7 +609,7 @@ function protocol.make_client_capabilities() refreshSupport = true, }, diagnostics = { - refreshSupport = false, + refreshSupport = true, }, }, experimental = nil, diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 61c0f60eaa..6070aaafa5 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -607,5 +607,19 @@ describe('vim.lsp.diagnostic', function() eq('related bad!', related_diagnostics[1].message) eq('spongebob', relatedPreviousResultId) end) + + it('refreshes diagnostics on request', function() + eq( + 1, + exec_lua(function() + vim.lsp.diagnostic.on_refresh(nil, nil, { + method = 'workspace/diagnostic/refresh', + client_id = client_id, + }) + + return _G.requests + end) + ) + end) end) end)