diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 8ae849c430..8f9061cbf2 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -277,6 +277,8 @@ LSP • Add cmp field to opts of |vim.lsp.completion.enable()| for custom completion ordering. • |vim.lsp.enable()| when `enable == false` now force stops the client after 3000 milliseconds when it takes too long to shutdown after being disabled. +• Push diagnostics (|vim.lsp.diagnostic.on_publish_diagnostics()|) now respect + the `version` property in the notification params. LUA diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 60d4bc26f4..75ff8ca200 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -222,7 +222,8 @@ end --- @param client_id? integer --- @param diagnostics lsp.Diagnostic[] --- @param is_pull boolean -local function handle_diagnostics(uri, client_id, diagnostics, is_pull) +--- @param version integer? +local function handle_diagnostics(uri, client_id, diagnostics, is_pull, version) local fname = vim.uri_to_fname(uri) if #diagnostics == 0 and vim.fn.bufexists(fname) == 0 then @@ -234,6 +235,10 @@ local function handle_diagnostics(uri, client_id, diagnostics, is_pull) return end + if version and util.buf_versions[bufnr] ~= version then + return + end + client_id = client_id or DEFAULT_CLIENT_ID local namespace = M.get_namespace(client_id, is_pull) @@ -249,7 +254,7 @@ end ---@param params lsp.PublishDiagnosticsParams ---@param ctx lsp.HandlerContext function M.on_publish_diagnostics(_, params, ctx) - handle_diagnostics(params.uri, ctx.client_id, params.diagnostics, false) + handle_diagnostics(params.uri, ctx.client_id, params.diagnostics, false, params.version) end --- |lsp-handler| for the method "textDocument/diagnostic" diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index f367c0a7c3..786a9d243c 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -560,6 +560,7 @@ function protocol.make_client_capabilities() valueSet = get_value_set(constants.DiagnosticTag), }, dataSupport = true, + versionSupport = true, }, callHierarchy = { dynamicRegistration = false, diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 6c30029ad2..61c0f60eaa 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -148,6 +148,40 @@ describe('vim.lsp.diagnostic', function() ) end) + it('ignores outdated diagnostics', function() + local result = exec_lua(function() + vim.lsp.diagnostic.on_publish_diagnostics(nil, { + uri = fake_uri, + version = vim.lsp.util.buf_versions[diagnostic_bufnr] - 1, + diagnostics = { + _G.make_error('Error', 0, 0, 1, 0), + }, + }, { client_id = client_id }) + + local diags = vim.diagnostic.get(diagnostic_bufnr) + return diags + end) + + -- Ignored: outdated version. + eq(0, #result) + + result = exec_lua(function() + vim.lsp.diagnostic.on_publish_diagnostics(nil, { + uri = fake_uri, + version = vim.lsp.util.buf_versions[diagnostic_bufnr], + diagnostics = { + _G.make_error('Error', 0, 0, 1, 0), + }, + }, { client_id = client_id }) + + local diags = vim.diagnostic.get(diagnostic_bufnr) + return diags + end) + + -- Applied: up-to-date version. + eq(1, #result) + end) + it('does not create buffer on empty diagnostics', function() -- No buffer is created without diagnostics eq(