diff options
author | Lewis Russell <lewis6991@gmail.com> | 2023-03-30 14:49:58 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-30 14:49:58 +0100 |
commit | 226a6c3eaef2a7220841d3d5e69e1baf543b3d6f (patch) | |
tree | 394cafe6a57a124635941517b2acd94d9d850efa | |
parent | 8fa7d833cf3a6c906c91c5acf9187b4544cf94be (diff) | |
download | rneovim-226a6c3eaef2a7220841d3d5e69e1baf543b3d6f.tar.gz rneovim-226a6c3eaef2a7220841d3d5e69e1baf543b3d6f.tar.bz2 rneovim-226a6c3eaef2a7220841d3d5e69e1baf543b3d6f.zip |
feat(diagnostic): add support for tags
The LSP spec supports two tags that can be added to diagnostics:
unnecessary and deprecated. Extend vim.diagnostic to be able to handle
these.
-rw-r--r-- | runtime/doc/lsp.txt | 3 | ||||
-rw-r--r-- | runtime/doc/news.txt | 3 | ||||
-rw-r--r-- | runtime/lua/vim/diagnostic.lua | 12 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/diagnostic.lua | 54 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/protocol.lua | 2 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/types.lua | 17 | ||||
-rw-r--r-- | src/nvim/highlight_group.c | 2 | ||||
-rw-r--r-- | test/functional/lua/diagnostic_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/plugin/lsp/diagnostic_spec.lua | 4 |
9 files changed, 83 insertions, 16 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 0164b34efb..f5695669ae 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1113,7 +1113,8 @@ code_action({options}) *vim.lsp.buf.code_action()* • {options} (table|nil) Optional table which holds the following optional fields: • context: (table|nil) Corresponds to `CodeActionContext` of the LSP specification: - • diagnostics (table|nil): LSP`Diagnostic[]` . Inferred from the current position if not provided. + • diagnostics (table|nil): LSP `Diagnostic[]`. Inferred + from the current position if not provided. • only (table|nil): List of LSP `CodeActionKind`s used to filter the code actions. Most language servers support values like `refactor` or `quickfix`. diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 890a033268..401719b432 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -226,6 +226,9 @@ The following new APIs or features were added. • Added |nvim_get_hl()| for getting highlight group definitions in a format compatible with |nvim_set_hl()|. +• |vim.diagnostic| now supports LSP DiagnosticsTag. + See: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnosticTag + ============================================================================== CHANGED FEATURES *news-changes* diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 56532d0184..714038f8e4 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -483,6 +483,7 @@ local function next_diagnostic(position, search_forward, bufnr, opts, namespace) local diagnostics = get_diagnostics(bufnr, vim.tbl_extend('keep', opts, { namespace = namespace }), true) local line_diagnostics = diagnostic_lines(diagnostics) + for i = 0, line_count do local offset = i * (search_forward and 1 or -1) local lnum = position[1] + offset @@ -752,6 +753,7 @@ end ---@field message string ---@field source nil|string ---@field code nil|string +---@field _tags { deprecated: boolean, unnecessary: boolean} ---@field user_data nil|any arbitrary data plugins can add --- Get current diagnostics. @@ -948,6 +950,16 @@ M.handlers.underline = { higroup = underline_highlight_map.Error end + if diagnostic._tags then + -- TODO(lewis6991): we should be able to stack these. + if diagnostic._tags.unnecessary then + higroup = 'DiagnosticUnnecessary' + end + if diagnostic._tags.deprecated then + higroup = 'DiagnosticDeprecated' + end + end + vim.highlight.range( bufnr, underline_ns, diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index b27bf6e425..dcc8f6549c 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -1,13 +1,6 @@ ---@brief lsp-diagnostic ---- ----@class Diagnostic ----@field range Range ----@field message string ----@field severity DiagnosticSeverity|nil ----@field code integer | string ----@field source string ----@field tags DiagnosticTag[] ----@field relatedInformation DiagnosticRelatedInformation[] + +local protocol = require('vim.lsp.protocol') local M = {} @@ -22,14 +15,16 @@ local function get_client_id(client_id) end ---@private +---@param severity lsp.DiagnosticSeverity local function severity_lsp_to_vim(severity) if type(severity) == 'string' then - severity = vim.lsp.protocol.DiagnosticSeverity[severity] + severity = protocol.DiagnosticSeverity[severity] end return severity end ---@private +---@return lsp.DiagnosticSeverity local function severity_vim_to_lsp(severity) if type(severity) == 'string' then severity = vim.diagnostic.severity[severity] @@ -38,6 +33,7 @@ local function severity_vim_to_lsp(severity) end ---@private +---@return integer local function line_byte_from_position(lines, lnum, col, offset_encoding) if not lines or offset_encoding == 'utf-8' then return col @@ -77,12 +73,41 @@ local function get_buf_lines(bufnr) return lines end +--- @private +--- @param diagnostic lsp.Diagnostic +--- @param client_id integer +--- @return table? +local function tags_lsp_to_vim(diagnostic, client_id) + local tags ---@type table? + for _, tag in ipairs(diagnostic.tags or {}) do + if tag == protocol.DiagnosticTag.Unnecessary then + tags = tags or {} + tags.unnecessary = true + elseif tag == protocol.DiagnosticTag.Deprecated then + tags = tags or {} + tags.deprecated = true + else + vim.notify_once( + string.format('Unknown DiagnosticTag %d from LSP client %d', tag, client_id), + vim.log.levels.WARN + ) + end + end + return tags +end + ---@private +---@param diagnostics lsp.Diagnostic[] +---@param bufnr integer +---@param client_id integer +---@return Diagnostic[] local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) local buf_lines = get_buf_lines(bufnr) local client = vim.lsp.get_client_by_id(client_id) local offset_encoding = client and client.offset_encoding or 'utf-16' + ---@diagnostic disable-next-line:no-unknown return vim.tbl_map(function(diagnostic) + ---@cast diagnostic lsp.Diagnostic local start = diagnostic.range.start local _end = diagnostic.range['end'] return { @@ -94,12 +119,12 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) message = diagnostic.message, 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 code = diagnostic.code, codeDescription = diagnostic.codeDescription, - tags = diagnostic.tags, relatedInformation = diagnostic.relatedInformation, data = diagnostic.data, }, @@ -108,9 +133,13 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) end, diagnostics) end ----@private +--- @private +--- @param diagnostics Diagnostic[] +--- @return lsp.Diagnostic[] local function diagnostic_vim_to_lsp(diagnostics) + ---@diagnostic disable-next-line:no-unknown return vim.tbl_map(function(diagnostic) + ---@cast diagnostic Diagnostic return vim.tbl_extend('keep', { -- "keep" the below fields over any duplicate fields in diagnostic.user_data.lsp range = { @@ -131,6 +160,7 @@ local function diagnostic_vim_to_lsp(diagnostics) end, diagnostics) end +---@type table<integer,integer> local _client_namespaces = {} --- Get the diagnostic namespace associated with an LSP client |vim.diagnostic|. diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 1686e22c48..f4489ad17d 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -21,6 +21,7 @@ end --]=] local constants = { + --- @enum lsp.DiagnosticSeverity DiagnosticSeverity = { -- Reports an error. Error = 1, @@ -32,6 +33,7 @@ local constants = { Hint = 4, }, + --- @enum lsp.DiagnosticTag DiagnosticTag = { -- Unused or unnecessary code Unnecessary = 1, diff --git a/runtime/lua/vim/lsp/types.lua b/runtime/lua/vim/lsp/types.lua index 1aea6841ee..779f313aa7 100644 --- a/runtime/lua/vim/lsp/types.lua +++ b/runtime/lua/vim/lsp/types.lua @@ -18,3 +18,20 @@ ---@class lsp.FileEvent ---@field uri string ---@field type lsp.FileChangeType + +---@class lsp.Position +---@field line integer +---@field character integer + +---@class lsp.Range +---@field start lsp.Position +---@field end lsp.Position + +---@class lsp.Diagnostic +---@field range lsp.Range +---@field message string +---@field severity? lsp.DiagnosticSeverity +---@field code integer | string +---@field source string +---@field tags? lsp.DiagnosticTag[] +---@field relatedInformation DiagnosticRelatedInformation[] diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 38af2a708a..057447c9f4 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -218,6 +218,8 @@ static const char *highlight_init_both[] = { "default link DiagnosticSignInfo DiagnosticInfo", "default link DiagnosticSignHint DiagnosticHint", "default link DiagnosticSignOk DiagnosticOk", + "default DiagnosticDeprecated cterm=strikethrough gui=strikethrough guisp=Red", + "default link DiagnosticUnnecessary Comment", // Text "default link @text.literal Comment", diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index d364986ad7..7b4d68c9cd 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -86,6 +86,7 @@ describe('vim.diagnostic', function() it('creates highlight groups', function() command('runtime plugin/diagnostic.vim') eq({ + 'DiagnosticDeprecated', 'DiagnosticError', 'DiagnosticFloatingError', 'DiagnosticFloatingHint', @@ -105,6 +106,7 @@ describe('vim.diagnostic', function() 'DiagnosticUnderlineInfo', 'DiagnosticUnderlineOk', 'DiagnosticUnderlineWarn', + 'DiagnosticUnnecessary', 'DiagnosticVirtualTextError', 'DiagnosticVirtualTextHint', 'DiagnosticVirtualTextInfo', diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index f73ffc29b0..f58016bf01 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -97,7 +97,6 @@ describe('vim.lsp.diagnostic', function() } diagnostics[1].code = 42 - diagnostics[1].tags = {"foo", "bar"} diagnostics[1].data = "Hello world" vim.lsp.diagnostic.on_publish_diagnostics(nil, { @@ -110,10 +109,9 @@ describe('vim.lsp.diagnostic', function() vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)[1], } ]] - eq({code = 42, tags = {"foo", "bar"}, data = "Hello world"}, result[1].user_data.lsp) + eq({code = 42, data = "Hello world"}, result[1].user_data.lsp) eq(42, result[1].code) eq(42, result[2].code) - eq({"foo", "bar"}, result[2].tags) eq("Hello world", result[2].data) end) end) |