commit 03d6cf7aae4a72c7221a4fb8ebb14a7c8603ba18
parent 5bb8734fb63921bd2b970da882e0a54d03130966
Author: Riley Bruins <ribru17@hotmail.com>
Date: Sat, 29 Nov 2025 20:38:11 -0800
feat(lsp): support `version` in `textDocument/publishDiagnostics` #36754
This commit makes it so that push diagnostics received for an outdated
document version are ignored.
Diffstat:
4 files changed, 44 insertions(+), 2 deletions(-)
diff --git 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
@@ -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
@@ -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
@@ -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(