Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lsp): add related_information to vim.Diagnostic #28640

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 36 additions & 15 deletions runtime/doc/diagnostic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -350,21 +350,25 @@ 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
• {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.diagnostic.RelatedInformation[]`) An
array of related diagnostic information. See
|vim.diagnostic.RelatedInformation|.
• {source}? (`string`) The source of the diagnostic
• {code}? (`string|integer`) The diagnostic code
• {user_data}? (`any`) arbitrary data plugins can add
• {namespace}? (`integer`)

*vim.diagnostic.GetOpts*
A table with the following keys:
Expand Down Expand Up @@ -597,6 +601,23 @@ Lua module: vim.diagnostic *diagnostic-api*
• {virt_text_win_col}? (`integer`) See |nvim_buf_set_extmark()|.
• {virt_text_hide}? (`boolean`) See |nvim_buf_set_extmark()|.

*vim.diagnostic.RelatedInformation*
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


config({opts}, {namespace}) *vim.diagnostic.config()*
Configure diagnostic options globally or for a specific diagnostic
Expand Down
3 changes: 3 additions & 0 deletions runtime/doc/news.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ LSP
• Completion side effects (including snippet expansion, execution of commands
and application of additional text edits) is now built-in.
• |vim.lsp.util.locations_to_items()| sets `end_col` and `end_lnum` fields.
• Add a new `related_information` field to |vim.Diagnostic| in favor of
`vim.Diagnostic.user_data.lsp.relatedInformation` (now deprecated). See
|vim.diagnostic.RelatedInformation|.

LUA

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.diagnostic.RelatedInformation[]
---
--- 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.diagnostic.RelatedInformation
---
--- 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

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

---@param related_informations lsp.DiagnosticRelatedInformation[]
---@param offset_encoding string
---@return vim.diagnostic.RelatedInformation[]
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.diagnostic.RelatedInformation?
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.diagnostic.RelatedInformation
return {
bufnr = bufnr,
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 +150,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