Skip to content

Commit

Permalink
feat(lsp): add vim.lsp.diagnostic.relatedInformation field
Browse files Browse the repository at this point in the history
For now this just adds the field to the toplevel Diagnostic structure.
We can decide in a follow-up if and how we should display these to the
user.
  • Loading branch information
tom-anders committed May 10, 2024
1 parent 064f3e4 commit 6c5f2ce
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 19 deletions.
53 changes: 37 additions & 16 deletions runtime/doc/diagnostic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -350,22 +350,43 @@ Lua module: vim.diagnostic *diagnostic-api*
0-based rows and columns). |api-indexing|

Fields: ~
{bufnr}? (`integer`) Buffer number
{lnum} (`integer`) The starting line of the diagnostic
(0-indexed)
• {end_lnum}? (`integer`) The final line of the diagnostic (0-indexed)
{col} (`integer`) The starting column of the diagnostic
(0-indexed)
• {end_col}? (`integer`) The final column of the diagnostic
(0-indexed)
{severity}? (`vim.diagnostic.Severity`) The severity of the
diagnostic |vim.diagnostic.severity|
{message} (`string`) The diagnostic text
{source}? (`string`) The source of the diagnostic
{code}? (`string|integer`) The diagnostic code
• {_tags}? (`{ deprecated: boolean, unnecessary: boolean}`)
• {user_data}? (`any`) arbitrary data plugins can add
{namespace}? (`integer`)
{bufnr}? (`integer`) Buffer number
{lnum} (`integer`) The starting line of the
diagnostic (0-indexed)
• {end_lnum}? (`integer`) The final line of the diagnostic
(0-indexed)
{col} (`integer`) The starting column of the
diagnostic (0-indexed)
• {end_col}? (`integer`) The final column of the diagnostic
(0-indexed)
{severity}? (`vim.diagnostic.Severity`) The severity of
the diagnostic |vim.diagnostic.severity|
{message} (`string`) The diagnostic text
• {related_information}? (`vim.DiagnosticRelatedInformation[]`) An
array of related diagnostic information. See
|vim.DiagnosticRelatedInformation|.
{source}? (`string`) The source of the diagnostic
{code}? (`string|integer`) The diagnostic code
• {_tags}? (`{ deprecated: boolean, unnecessary: boolean}`)
• {user_data}? (`any`) arbitrary data plugins can add
{namespace}? (`integer`)

*vim.DiagnosticRelatedInformation*
Related message and location for a diagnostic. This can be used to point
to code locations that cause or are related to a diagnostic, e.g when
duplicating a symbol in a scope.

Fields: ~
{bufnr}? (`integer`) Buffer number
{lnum} (`integer`) The starting line of the related information
(0-indexed)
• {end_lnum}? (`integer`) The final line of the related information
(0-indexed)
{col} (`integer`) The starting column of the related
information (0-indexed)
• {end_col}? (`integer`) The final column of the related information
(0-indexed)
{message} (`string`) The related information text

*vim.diagnostic.GetOpts*
A table with the following keys:
Expand Down
4 changes: 4 additions & 0 deletions runtime/doc/news.txt
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ The following new APIs and features were added.
|vim.lsp.buf.definition()|, |vim.lsp.buf.declaration()|,
|vim.lsp.buf.type_definition()|, and |vim.lsp.buf.implementation()| now
support the `loclist` field of |vim.lsp.ListOpts|.
• Add `vim.Diagnostic.related_information` field and fill it with
`lsp.DiagnosticRelatedInformation[]`. Deprecate
`vim.Diagnostic.user_data.lsp.relatedInformation` in favor of this new
field.

• Treesitter
• Bundled parsers and queries (highlight, folds) for Markdown, Python, and
Expand Down
26 changes: 26 additions & 0 deletions runtime/lua/vim/diagnostic.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ local M = {}
--- The diagnostic text
--- @field message string
---
--- An array of related diagnostic information
--- @field related_information? vim.DiagnosticRelatedInformation[]
---
--- The source of the diagnostic
--- @field source? string
---
Expand All @@ -42,6 +45,29 @@ local M = {}
---
--- @field namespace? integer

--- Related message and location for a diagnostic.
--- This can be used to point to code locations that cause or are related to
--- a diagnostic, e.g when duplicating a symbol in a scope.
--- @class vim.DiagnosticRelatedInformation
---
--- Buffer number
--- @field bufnr? integer
---
--- The starting line of the related information (0-indexed)
--- @field lnum integer
---
--- The final line of the related information (0-indexed)
--- @field end_lnum? integer
---
--- The starting column of the related information (0-indexed)
--- @field col integer
---
--- The final column of the related information (0-indexed)
--- @field end_col? integer
---
--- The related information text
--- @field message string

--- Each of the configuration options below accepts one of the following:
--- - `false`: Disable this feature
--- - `true`: Enable this feature, use default settings.
Expand Down
38 changes: 37 additions & 1 deletion runtime/lua/vim/lsp/diagnostic.lua
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,37 @@ local function tags_lsp_to_vim(diagnostic, client_id)
return tags
end

---@param related_informations lsp.DiagnosticRelatedInformation[]
---@param offset_encoding string
---@return vim.DiagnosticRelatedInformation[]
local function related_information_lsp_to_vim(related_informations, offset_encoding)
return vim
.iter(related_informations or {})
:map(
--- @param related_information lsp.DiagnosticRelatedInformation
--- @return vim.DiagnosticRelatedInformation?
function(related_information)
local fname = vim.uri_to_fname(related_information.location.uri)
local bufnr = vim.fn.bufadd(fname)
if not bufnr then
return nil
end
local buf_lines = get_buf_lines(bufnr)
local start = related_information.location.range.start
local _end = related_information.location.range['end']
--- @type vim.DiagnosticRelatedInformation
return {
lnum = start.line,
col = line_byte_from_position(buf_lines, start.line, start.character, offset_encoding),
end_lnum = _end.line,
end_col = line_byte_from_position(buf_lines, _end.line, _end.character, offset_encoding),
message = related_information.message,
}
end
)
:totable()
end

---@param diagnostics lsp.Diagnostic[]
---@param bufnr integer
---@param client_id integer
Expand All @@ -118,12 +149,17 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)
end_col = line_byte_from_position(buf_lines, _end.line, _end.character, offset_encoding),
severity = severity_lsp_to_vim(diagnostic.severity),
message = diagnostic.message,
related_information = related_information_lsp_to_vim(
diagnostic.relatedInformation,
offset_encoding
),
source = diagnostic.source,
code = diagnostic.code,
_tags = tags_lsp_to_vim(diagnostic, client_id),
user_data = {
lsp = {
-- usage of user_data.lsp.code is deprecated in favor of the top-level code field
-- usage of user_data.lsp.code and user_data.lsp.relatedInformation is deprecated
-- in favor of the top-level code and related_information fields
code = diagnostic.code,
codeDescription = diagnostic.codeDescription,
relatedInformation = diagnostic.relatedInformation,
Expand Down
40 changes: 38 additions & 2 deletions test/functional/plugin/lsp/diagnostic_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ describe('vim.lsp.diagnostic', function()
}
end
make_related_information = function(msg, uri, x1, y1, x2, y2)
return {
location = {
uri = uri,
range = make_range(x1, y1, x2, y2),
},
message = msg,
}
end
function get_extmarks(bufnr, client_id)
local namespace = vim.lsp.diagnostic.get_namespace(client_id)
local ns = vim.diagnostic.get_namespace(namespace)
Expand Down Expand Up @@ -108,6 +118,10 @@ describe('vim.lsp.diagnostic', function()
diagnostics[1].code = 42
diagnostics[1].data = "Hello world"
diagnostics[1].relatedInformation = {
make_related_information("Related info", fake_uri, 1, 2, 3, 4),
}
vim.lsp.diagnostic.on_publish_diagnostics(nil, {
uri = fake_uri,
diagnostics = diagnostics,
Expand All @@ -118,8 +132,24 @@ describe('vim.lsp.diagnostic', function()
vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)[1],
}
]]
eq({ code = 42, data = 'Hello world' }, result[1].user_data.lsp)
eq({
code = 42,
data = 'Hello world',
relatedInformation = {
{
location = {
uri = fake_uri,
range = {
start = { line = 1, character = 2 },
['end'] = { line = 3, character = 4 },
},
},
message = 'Related info',
},
},
}, result[1].user_data.lsp)
eq(42, result[1].code)
eq('Related info', result[1].related_information[1].message)
eq(42, result[2].code)
eq('Hello world', result[2].data)
end)
Expand Down Expand Up @@ -321,11 +351,15 @@ describe('vim.lsp.diagnostic', function()

it('adds diagnostics to vim.diagnostics', function()
local diags = exec_lua([[
local error = make_error('Pull Diagnostic', 4, 4, 4, 4)
error.relatedInformation = {
make_related_information('Related info', fake_uri, 4, 4, 4, 4),
}
vim.lsp.diagnostic.on_diagnostic(nil,
{
kind = 'full',
items = {
make_error('Pull Diagnostic', 4, 4, 4, 4),
error
}
},
{
Expand All @@ -342,6 +376,8 @@ describe('vim.lsp.diagnostic', function()
]])
eq(1, #diags)
eq('Pull Diagnostic', diags[1].message)
eq(1, #diags[1].related_information)
eq('Related info', diags[1].related_information[1].message)
end)

it('allows configuring the virtual text via vim.lsp.with', function()
Expand Down

0 comments on commit 6c5f2ce

Please sign in to comment.