feat(lsp): diagnostic related documents support

This commit is contained in:
Riley Bruins
2025-07-08 18:41:50 -07:00
parent 1d8e9b5d07
commit 371aa1c566
4 changed files with 72 additions and 0 deletions

View File

@@ -214,6 +214,8 @@ LSP
jump to the problematic location.
• Support for `textDocument/linkedEditingRange`: |lsp-linked_editing_range|
https://microsoft.github.io/language-server-protocol/specification/#textDocument_linkedEditingRange
• Support for related documents in pull diagnostics:
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#relatedFullDocumentDiagnosticReport
LUA

View File

@@ -283,6 +283,22 @@ function M.on_diagnostic(error, result, ctx)
end
handle_diagnostics(ctx.params.textDocument.uri, client_id, result.items, true)
for uri, related_result in pairs(result.relatedDocuments or {}) do
if related_result.kind == 'full' then
handle_diagnostics(uri, client_id, related_result.items, true)
end
local related_bufnr = vim.uri_to_bufnr(uri)
local related_bufstate = bufstates[related_bufnr]
-- Create a new bufstate if it doesn't exist for the related document. This will not enable
-- diagnostic pulling by itself, but will allow previous result IDs to be passed correctly the
-- next time this buffer's diagnostics are pulled.
or { pull_kind = 'document', client_result_id = {} }
bufstates[related_bufnr] = related_bufstate
related_bufstate.client_result_id[client_id] = related_result.resultId
end
end
--- Clear push diagnostics and diagnostic cache.

View File

@@ -350,6 +350,7 @@ function protocol.make_client_capabilities()
},
dataSupport = true,
relatedInformation = true,
relatedDocumentSupport = true,
},
inlayHint = {
dynamicRegistration = true,

View File

@@ -525,5 +525,58 @@ describe('vim.lsp.diagnostic', function()
end)
)
end)
it('handles relatedDocuments diagnostics', function()
local fake_uri_2 = 'file:///fake/uri2'
---@type vim.Diagnostic[], vim.Diagnostic[], string?
local diagnostics, related_diagnostics, relatedPreviousResultId = exec_lua(function()
local second_buf = vim.uri_to_bufnr(fake_uri_2)
vim.fn.bufload(second_buf)
-- Attach the client to both buffers.
vim.api.nvim_win_set_buf(0, second_buf)
vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
vim.lsp.diagnostic.on_diagnostic(nil, {
kind = 'full',
relatedDocuments = {
[fake_uri_2] = {
kind = 'full',
resultId = 'spongebob',
items = {
{
range = _G.make_range(4, 4, 4, 4),
message = 'related bad!',
},
},
},
},
items = {},
}, {
params = {
textDocument = { uri = fake_uri },
},
uri = fake_uri,
client_id = client_id,
bufnr = diagnostic_bufnr,
}, {})
vim.api.nvim_exec_autocmds('LspNotify', {
buffer = second_buf,
data = {
method = vim.lsp.protocol.Methods.textDocument_didChange,
client_id = client_id,
},
})
return vim.diagnostic.get(diagnostic_bufnr),
vim.diagnostic.get(second_buf),
_G.params.previousResultId
end)
eq(0, #diagnostics)
eq(1, #related_diagnostics)
eq('related bad!', related_diagnostics[1].message)
eq('spongebob', relatedPreviousResultId)
end)
end)
end)