diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index a02eb2773a..b61d40b77a 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -284,6 +284,7 @@ LSP • |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 +- Support for dynamic registration for `textDocument/diagnostic` LUA diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 3a3a1c8c0c..48cf3c0364 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -358,7 +358,7 @@ end ---@param bufnr integer buffer number ---@param client_id? integer Client ID to refresh (default: all clients) ---@param only_visible? boolean Whether to only refresh for the visible regions of the buffer (default: false) -local function refresh(bufnr, client_id, only_visible) +function M._refresh(bufnr, client_id, only_visible) if only_visible and vim.iter(api.nvim_list_wins()):all(function(window) @@ -407,7 +407,7 @@ function M.on_refresh(err, _, ctx) else for bufnr in pairs(client.attached_buffers or {}) do if bufstates[bufnr] and bufstates[bufnr].pull_kind == 'document' then - refresh(bufnr) + M._refresh(bufnr) end end end @@ -442,7 +442,7 @@ function M._enable(bufnr) end if bufstates[bufnr] and bufstates[bufnr].pull_kind == 'document' then local client_id = opts.data.client_id --- @type integer? - refresh(bufnr, client_id, true) + M._refresh(bufnr, client_id, true) end end, group = augroup, @@ -451,7 +451,7 @@ function M._enable(bufnr) api.nvim_buf_attach(bufnr, false, { on_reload = function() if bufstates[bufnr] and bufstates[bufnr].pull_kind == 'document' then - refresh(bufnr) + M._refresh(bufnr) end end, on_detach = function() diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 4bfe09af57..0f0a6bac15 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -158,6 +158,11 @@ RSC['client/registerCapability'] = function(_, params, ctx) end end end + if reg.method == 'textDocument/diagnostic' then + for bufnr in pairs(client.attached_buffers) do + vim.lsp.diagnostic._refresh(bufnr, client.id) + end + end end return vim.NIL end diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 9b525cce4d..06bdb55144 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -352,7 +352,7 @@ function protocol.make_client_capabilities() }, textDocument = { diagnostic = { - dynamicRegistration = false, + dynamicRegistration = true, tagSupport = { valueSet = get_value_set(constants.DiagnosticTag), }, diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 94f2a59af0..25c549d2a7 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -498,6 +498,42 @@ describe('vim.lsp.diagnostic', function() ) end) + it('supports dynamic registration', function() + exec_lua(create_server_definition) + exec_lua(function() + _G.server2 = _G._create_server({ + diagnosticProvider = { + documentSelector = vim.NIL, + }, + handlers = { + ['textDocument/diagnostic'] = function(_, _, callback) + callback(nil, { + kind = 'full', + items = { + _G.make_error('Dynamic Diagnostic', 4, 4, 4, 4), + }, + }) + end, + }, + }) + + local client_id2 = assert(vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd })) + + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { id = 'diagnostic', method = 'textDocument/diagnostic' }, + }, + }, { client_id = client_id2, method = 'client/registerCapability' }) + end) + + eq( + 1, + exec_lua(function() + return #vim.diagnostic.get(diagnostic_bufnr) + end) + ) + end) + it('requests with the `previousResultId`', function() -- Full reports eq(