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 7, 2024
1 parent e948d7f commit b598c73
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 23 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 diagnostics, 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 @@ -264,6 +264,10 @@ The following new APIs and features were added.
respective capability can be unset.
|vim.lsp.start()| accepts a "silent" option for suppressing messages
if an LSP server failed to start.
• 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 diagnostics, 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
44 changes: 37 additions & 7 deletions runtime/lua/vim/lsp/diagnostic.lua
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,33 @@ 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.tbl_filter(function(item) return item ~= nil end,
--- @param related_information lsp.DiagnosticRelatedInformation
--- @return vim.DiagnosticRelatedInformation
vim.tbl_map(function(related_information)
local fname = vim.uri_to_fname(related_information.location.uri)
local bufnr = vim.fn.bufadd(fname)
if not bufnr then
return
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, related_informations))
end

---@param diagnostics lsp.Diagnostic[]
---@param bufnr integer
---@param client_id integer
Expand All @@ -118,12 +145,15 @@ 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.related_information,
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 Expand Up @@ -194,7 +224,7 @@ function M.get_namespace(client_id, is_pull)
local client = vim.lsp.get_client_by_id(client_id)
if is_pull then
local server_id =
vim.tbl_get((client or {}).server_capabilities, 'diagnosticProvider', 'identifier')
vim.tbl_get((client or {}).server_capabilities, 'diagnosticProvider', 'identifier')
local key = string.format('%d:%s', client_id, server_id or 'nil')
local name = string.format(
'vim.lsp.%s.%d.%s',
Expand Down Expand Up @@ -431,8 +461,8 @@ function M._enable(bufnr)
buffer = bufnr,
callback = function(opts)
if
opts.data.method ~= ms.textDocument_didChange
and opts.data.method ~= ms.textDocument_didOpen
opts.data.method ~= ms.textDocument_didChange
and opts.data.method ~= ms.textDocument_didOpen
then
return
end
Expand Down Expand Up @@ -461,9 +491,9 @@ function M._enable(bufnr)
local clients = vim.lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_diagnostic })

if
not vim.iter(clients):any(function(c)
return c.id ~= args.data.client_id
end)
not vim.iter(clients):any(function(c)
return c.id ~= args.data.client_id
end)
then
disable(bufnr)
end
Expand Down

0 comments on commit b598c73

Please sign in to comment.