From 706bcab75eaad2c370d61bf828531054439d3a3e Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Tue, 7 Mar 2023 15:17:52 +0900 Subject: docs(lsp): change type annotations from number → integer (#22510) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- runtime/lua/vim/lsp/diagnostic.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/lsp/diagnostic.lua') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 5e2bf75f1b..b27bf6e425 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -4,7 +4,7 @@ ---@field range Range ---@field message string ---@field severity DiagnosticSeverity|nil ----@field code number | string +---@field code integer | string ---@field source string ---@field tags DiagnosticTag[] ---@field relatedInformation DiagnosticRelatedInformation[] @@ -135,7 +135,7 @@ local _client_namespaces = {} --- Get the diagnostic namespace associated with an LSP client |vim.diagnostic|. --- ----@param client_id number The id of the LSP client +---@param client_id integer The id of the LSP client function M.get_namespace(client_id) vim.validate({ client_id = { client_id, 'n' } }) if not _client_namespaces[client_id] then @@ -212,7 +212,7 @@ end --- this method signature is still used internally in some parts of the LSP --- implementation so it's simply marked @private rather than @deprecated. --- ----@param client_id number +---@param client_id integer ---@param buffer_client_map table map of buffers to active clients ---@private function M.reset(client_id, buffer_client_map) @@ -232,14 +232,14 @@ end --- Marked private as this is used internally by the LSP subsystem, but --- most users should instead prefer |vim.diagnostic.get()|. --- ----@param bufnr number|nil The buffer number ----@param line_nr number|nil The line number +---@param bufnr integer|nil The buffer number +---@param line_nr integer|nil The line number ---@param opts table|nil Configuration keys --- - severity: (DiagnosticSeverity, default nil) --- - Only return diagnostics with this severity. Overrides severity_limit --- - severity_limit: (DiagnosticSeverity, default nil) --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. ----@param client_id|nil number the client id +---@param client_id integer|nil the client id ---@return table Table with map of line number to list of diagnostics. --- Structured: { [1] = {...}, [5] = {.... } } ---@private -- cgit From 226a6c3eaef2a7220841d3d5e69e1baf543b3d6f Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 30 Mar 2023 14:49:58 +0100 Subject: 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. --- runtime/lua/vim/lsp/diagnostic.lua | 54 +++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) (limited to 'runtime/lua/vim/lsp/diagnostic.lua') 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 local _client_namespaces = {} --- Get the diagnostic namespace associated with an LSP client |vim.diagnostic|. -- cgit From ed10e4ef60c63d924b9969abdf77adaad506b676 Mon Sep 17 00:00:00 2001 From: Akin <22454918+akinsho@users.noreply.github.com> Date: Fri, 31 Mar 2023 11:23:19 +0100 Subject: fix(diagnostic): use correct field name for tags (#22835) LSP tags are added to the diagnostic as "tags" but referred to as "_tags" in the diagnostic underline handler --- runtime/lua/vim/lsp/diagnostic.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp/diagnostic.lua') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index dcc8f6549c..3efa5c51ff 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -119,7 +119,7 @@ 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), + _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 -- cgit From be74807eef13ff8c90d55cf8b22b01d6d33b1641 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 18 Jul 2023 15:42:30 +0100 Subject: docs(lua): more improvements (#24387) * docs(lua): teach lua2dox how to table * docs(lua): teach gen_vimdoc.py about local functions No more need to mark local functions with @private * docs(lua): mention @nodoc and @meta in dev-lua-doc * fixup! Co-authored-by: Justin M. Keyes --------- Co-authored-by: Justin M. Keyes --- runtime/lua/vim/lsp/diagnostic.lua | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'runtime/lua/vim/lsp/diagnostic.lua') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 3efa5c51ff..c2cf7c6ba5 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -5,7 +5,7 @@ local protocol = require('vim.lsp.protocol') local M = {} local DEFAULT_CLIENT_ID = -1 ----@private + local function get_client_id(client_id) if client_id == nil then client_id = DEFAULT_CLIENT_ID @@ -14,7 +14,6 @@ local function get_client_id(client_id) return client_id end ----@private ---@param severity lsp.DiagnosticSeverity local function severity_lsp_to_vim(severity) if type(severity) == 'string' then @@ -23,7 +22,6 @@ local function severity_lsp_to_vim(severity) return severity end ----@private ---@return lsp.DiagnosticSeverity local function severity_vim_to_lsp(severity) if type(severity) == 'string' then @@ -32,7 +30,6 @@ local function severity_vim_to_lsp(severity) return 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 @@ -48,7 +45,6 @@ local function line_byte_from_position(lines, lnum, col, offset_encoding) return col end ----@private local function get_buf_lines(bufnr) if vim.api.nvim_buf_is_loaded(bufnr) then return vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) @@ -73,7 +69,6 @@ local function get_buf_lines(bufnr) return lines end ---- @private --- @param diagnostic lsp.Diagnostic --- @param client_id integer --- @return table? @@ -96,7 +91,6 @@ local function tags_lsp_to_vim(diagnostic, client_id) return tags end ----@private ---@param diagnostics lsp.Diagnostic[] ---@param bufnr integer ---@param client_id integer @@ -133,7 +127,6 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) end, diagnostics) end ---- @private --- @param diagnostics Diagnostic[] --- @return lsp.Diagnostic[] local function diagnostic_vim_to_lsp(diagnostics) -- cgit From 63b3408551561127f7845470eb51404bcd6f547b Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Thu, 20 Jul 2023 03:03:48 -0400 Subject: feat(lsp): implement textDocument/diagnostic (#24128) --- runtime/lua/vim/lsp/diagnostic.lua | 187 ++++++++++++++++++++++++++++++++++--- 1 file changed, 175 insertions(+), 12 deletions(-) (limited to 'runtime/lua/vim/lsp/diagnostic.lua') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index c2cf7c6ba5..34be13096d 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -1,9 +1,14 @@ ---@brief lsp-diagnostic +local util = require('vim.lsp.util') local protocol = require('vim.lsp.protocol') +local api = vim.api + local M = {} +local augroup = api.nvim_create_augroup('vim_lsp_diagnostic', {}) + local DEFAULT_CLIENT_ID = -1 local function get_client_id(client_id) @@ -154,19 +159,43 @@ local function diagnostic_vim_to_lsp(diagnostics) end ---@type table -local _client_namespaces = {} +local _client_push_namespaces = {} +---@type table +local _client_pull_namespaces = {} ---- Get the diagnostic namespace associated with an LSP client |vim.diagnostic|. +--- Get the diagnostic namespace associated with an LSP client |vim.diagnostic| for diagnostics --- ---@param client_id integer The id of the LSP client -function M.get_namespace(client_id) +---@param is_pull boolean Whether the namespace is for a pull or push client +function M.get_namespace(client_id, is_pull) vim.validate({ client_id = { client_id, 'n' } }) - if not _client_namespaces[client_id] then - local client = vim.lsp.get_client_by_id(client_id) - local name = string.format('vim.lsp.%s.%d', client and client.name or 'unknown', client_id) - _client_namespaces[client_id] = vim.api.nvim_create_namespace(name) + + local namespace_table + local key + local name + local client = vim.lsp.get_client_by_id(client_id) + + if is_pull then + namespace_table = _client_pull_namespaces + local server_id = vim.tbl_get(client.server_capabilities, 'diagnosticProvider', 'identifier') + key = string.format('%d:%s', client_id, server_id or 'nil') + name = string.format( + 'vim.lsp.%s.%d.%s', + client and client.name or 'unknown', + client_id, + server_id or 'nil' + ) + else + namespace_table = _client_push_namespaces + key = client_id + name = string.format('vim.lsp.%s.%d', client and client.name or 'unknown', client_id) end - return _client_namespaces[client_id] + + if not namespace_table[key] then + namespace_table[key] = api.nvim_create_namespace(name) + end + + return namespace_table[key] end --- |lsp-handler| for the method "textDocument/publishDiagnostics" @@ -209,7 +238,7 @@ function M.on_publish_diagnostics(_, result, ctx, config) end client_id = get_client_id(client_id) - local namespace = M.get_namespace(client_id) + local namespace = M.get_namespace(client_id, false) if config then for _, opt in pairs(config) do @@ -229,7 +258,75 @@ function M.on_publish_diagnostics(_, result, ctx, config) vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)) end ---- Clear diagnostics and diagnostic cache. +--- |lsp-handler| for the method "textDocument/diagnostic" +--- +--- See |vim.diagnostic.config()| for configuration options. Handler-specific +--- configuration can be set using |vim.lsp.with()|: +---
lua
+--- vim.lsp.handlers["textDocument/diagnostic"] = vim.lsp.with(
+---   vim.lsp.diagnostic.on_diagnostic, {
+---     -- Enable underline, use default values
+---     underline = true,
+---     -- Enable virtual text, override spacing to 4
+---     virtual_text = {
+---       spacing = 4,
+---     },
+---     -- Use a function to dynamically turn signs off
+---     -- and on, using buffer local variables
+---     signs = function(namespace, bufnr)
+---       return vim.b[bufnr].show_signs == true
+---     end,
+---     -- Disable a feature
+---     update_in_insert = false,
+---   }
+--- )
+--- 
+--- +---@param config table Configuration table (see |vim.diagnostic.config()|). +function M.on_diagnostic(_, result, ctx, config) + local client_id = ctx.client_id + local uri = ctx.params.textDocument.uri + local fname = vim.uri_to_fname(uri) + + if result == nil then + return + end + + if result.kind == 'unchanged' then + return + end + + local diagnostics = result.items + if #diagnostics == 0 and vim.fn.bufexists(fname) == 0 then + return + end + local bufnr = vim.fn.bufadd(fname) + + if not bufnr then + return + end + + client_id = get_client_id(client_id) + + local namespace = M.get_namespace(client_id, true) + + if config then + for _, opt in pairs(config) do + if type(opt) == 'table' and not opt.severity and opt.severity_limit then + opt.severity = { min = severity_lsp_to_vim(opt.severity_limit) } + end + end + + -- Persist configuration to ensure buffer reloads use the same + -- configuration. To make lsp.with configuration work (See :help + -- lsp-handler-configuration) + vim.diagnostic.config(config, namespace) + end + + vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)) +end + +--- Clear push diagnostics and diagnostic cache. --- --- Diagnostic producers should prefer |vim.diagnostic.reset()|. However, --- this method signature is still used internally in some parts of the LSP @@ -243,7 +340,7 @@ function M.reset(client_id, buffer_client_map) vim.schedule(function() for bufnr, client_ids in pairs(buffer_client_map) do if client_ids[client_id] then - local namespace = M.get_namespace(client_id) + local namespace = M.get_namespace(client_id, false) vim.diagnostic.reset(namespace, bufnr) end end @@ -275,7 +372,7 @@ function M.get_line_diagnostics(bufnr, line_nr, opts, client_id) end if client_id then - opts.namespace = M.get_namespace(client_id) + opts.namespace = M.get_namespace(client_id, false) end if not line_nr then @@ -287,4 +384,70 @@ function M.get_line_diagnostics(bufnr, line_nr, opts, client_id) return diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, opts)) end +--- Clear diagnostics from pull based clients +--- @private +local function clear(bufnr) + for _, namespace in pairs(_client_pull_namespaces) do + vim.diagnostic.reset(namespace, bufnr) + end +end + +--- autocmd ids for LspNotify handlers per buffer +--- @private +--- @type table +local _autocmd_ids = {} + +--- Disable pull diagnostics for a buffer +--- @private +local function disable(bufnr) + if not _autocmd_ids[bufnr] then + return + end + api.nvim_del_autocmd(_autocmd_ids[bufnr]) + _autocmd_ids[bufnr] = nil + clear(bufnr) +end + +--- Enable pull diagnostics for a buffer +---@param bufnr (integer) Buffer handle, or 0 for current +---@private +function M._enable(bufnr) + if bufnr == nil or bufnr == 0 then + bufnr = api.nvim_get_current_buf() + end + + if _autocmd_ids[bufnr] then + return + end + + _autocmd_ids[bufnr] = api.nvim_create_autocmd('LspNotify', { + buffer = bufnr, + callback = function(opts) + if opts.data.method ~= 'textDocument/didChange' then + return + end + util._refresh('textDocument/diagnostic', { bufnr = bufnr, only_visible = true }) + end, + group = augroup, + }) + + api.nvim_buf_attach(bufnr, false, { + on_reload = function() + util._refresh('textDocument/diagnostic', { bufnr = bufnr }) + end, + on_detach = function() + disable(bufnr) + end, + }) + + api.nvim_create_autocmd('LspDetach', { + buffer = bufnr, + callback = function() + disable(bufnr) + end, + once = true, + group = augroup, + }) +end + return M -- cgit From e55e80d51ca5d85770981bffb9254badc3662e0c Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Tue, 1 Aug 2023 08:13:52 -0400 Subject: fix(lsp): inlay hints: "Failed to delete autocmd" when closing buffer #24469 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: "Failed to delete autocmd" error when deleting LspNotify autocmd. #24456 Solution: Change a few things in the inlay_hint and diagnostic LSP code: 1. Re-introduce the `enabled` flag for the buffer state tables. Previously I was relying on the presence of an autocmd id in the state table to track whether inlay_hint / diagnostic was enabled for a buffer. There are two reasons why this doesn't work well: - Each time inlay_hint / diagnostic is enabled, we call `nvim_buf_attach` on the buffer, resulting in multiple `on_reload` or `on_detach` callbacks being registered. - Commands like `bwipeout` delete buffer local autocmds, sometimes before our `on_detach` callbacks have a chance to delete them first. This causes the - Use module local enabled state for diagnostic as well. bwipeout can race with on_detach callbacks for deleting autocmds. Error referenced in #24456. 2. Change the `LspDetach` autocmd to run each time (i.e., remove the `once` flag). Since we're only registering autocmds once per buffer now, we need to make sure that we set the enabled flag properly each time the LSP client detaches from the buffer. - Remove `once` from the LspDetach autocmds for inlay_hint and diagnostic. We only set up the autocmd once now. Gets removed when buffer is deleted. 3. Have the `LspNotify` handler also refresh the inlay_hint / diagnostics when receiving the `textDocument/didOpen` event. Before this point, the LSP backend doesn't have the contents of the buffer, so can't provide inlay hints or diagnostics. Downsides of this approach: * When inlay_hint / diagnostics are disabled on a buffer, it will continue to receive `LspNotify` events for that buffer. The callback exits early since the `enabled` flag is false. Alternatives: * Can we wrap the call to `nvim_del_autocmd` in `pcall` to swallow any errors resulting from trying to delete the autocmd? Fixes #24456 Helped-by: Maria José Solano --- runtime/lua/vim/lsp/diagnostic.lua | 85 +++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 39 deletions(-) (limited to 'runtime/lua/vim/lsp/diagnostic.lua') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 34be13096d..44bb90d985 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -392,19 +392,18 @@ local function clear(bufnr) end end ---- autocmd ids for LspNotify handlers per buffer ---- @private ---- @type table -local _autocmd_ids = {} +---@class lsp.diagnostic.bufstate +---@field enabled boolean Whether inlay hints are enabled for this buffer +---@type table +local bufstates = {} --- Disable pull diagnostics for a buffer --- @private local function disable(bufnr) - if not _autocmd_ids[bufnr] then - return + local bufstate = bufstates[bufnr] + if bufstate then + bufstate.enabled = false end - api.nvim_del_autocmd(_autocmd_ids[bufnr]) - _autocmd_ids[bufnr] = nil clear(bufnr) end @@ -416,38 +415,46 @@ function M._enable(bufnr) bufnr = api.nvim_get_current_buf() end - if _autocmd_ids[bufnr] then - return + if not bufstates[bufnr] then + bufstates[bufnr] = { enabled = true } + + api.nvim_create_autocmd('LspNotify', { + buffer = bufnr, + callback = function(opts) + if + opts.data.method ~= 'textDocument/didChange' + and opts.data.method ~= 'textDocument/didOpen' + then + return + end + if bufstates[bufnr] and bufstates[bufnr].enabled then + util._refresh('textDocument/diagnostic', { bufnr = bufnr, only_visible = true }) + end + end, + group = augroup, + }) + + api.nvim_buf_attach(bufnr, false, { + on_reload = function() + if bufstates[bufnr] and bufstates[bufnr].enabled then + util._refresh('textDocument/diagnostic', { bufnr = bufnr }) + end + end, + on_detach = function() + disable(bufnr) + end, + }) + + api.nvim_create_autocmd('LspDetach', { + buffer = bufnr, + callback = function() + disable(bufnr) + end, + group = augroup, + }) + else + bufstates[bufnr].enabled = true end - - _autocmd_ids[bufnr] = api.nvim_create_autocmd('LspNotify', { - buffer = bufnr, - callback = function(opts) - if opts.data.method ~= 'textDocument/didChange' then - return - end - util._refresh('textDocument/diagnostic', { bufnr = bufnr, only_visible = true }) - end, - group = augroup, - }) - - api.nvim_buf_attach(bufnr, false, { - on_reload = function() - util._refresh('textDocument/diagnostic', { bufnr = bufnr }) - end, - on_detach = function() - disable(bufnr) - end, - }) - - api.nvim_create_autocmd('LspDetach', { - buffer = bufnr, - callback = function() - disable(bufnr) - end, - once = true, - group = augroup, - }) end return M -- cgit From f1772272b4fda43c093fc495f54b5e7c11968d62 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 3 Aug 2023 19:03:48 +0800 Subject: refactor(lsp): use protocol.Methods instead of strings #24537 --- runtime/lua/vim/lsp/diagnostic.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim/lsp/diagnostic.lua') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 44bb90d985..a0568bc09c 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -2,6 +2,7 @@ local util = require('vim.lsp.util') local protocol = require('vim.lsp.protocol') +local ms = protocol.Methods local api = vim.api @@ -422,13 +423,13 @@ function M._enable(bufnr) buffer = bufnr, callback = function(opts) if - opts.data.method ~= 'textDocument/didChange' - and opts.data.method ~= 'textDocument/didOpen' + opts.data.method ~= ms.textDocument_didChange + and opts.data.method ~= ms.textDocument_didOpen then return end if bufstates[bufnr] and bufstates[bufnr].enabled then - util._refresh('textDocument/diagnostic', { bufnr = bufnr, only_visible = true }) + util._refresh(ms.textDocument_diagnostic, { bufnr = bufnr, only_visible = true }) end end, group = augroup, @@ -437,7 +438,7 @@ function M._enable(bufnr) api.nvim_buf_attach(bufnr, false, { on_reload = function() if bufstates[bufnr] and bufstates[bufnr].enabled then - util._refresh('textDocument/diagnostic', { bufnr = bufnr }) + util._refresh(ms.textDocument_diagnostic, { bufnr = bufnr }) end end, on_detach = function() -- cgit From c235959fd909d75248c066a781475e207606c5aa Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Thu, 31 Aug 2023 04:00:24 -0400 Subject: fix(lsp): only disable inlay hints / diagnostics if no other clients are connected (#24535) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the issue where the LspNotify handlers for inlay_hint / diagnostics would end up refreshing all attached clients. The handler would call util._refresh, which called vim.lsp.buf_request, which calls the method on all attached clients. Now util._refresh takes an optional client_id parameter, which is used to specify a specific client to update. This commit also fixes util._refresh's handling of the `only_visible` flag. Previously if `only_visible` was false, two requests would be made to the server: one for the visible region, and one for the entire file. Co-authored-by: Stanislav Asunkin <1353637+stasjok@users.noreply.github.com> Co-authored-by: Mathias Fußenegger --- runtime/lua/vim/lsp/diagnostic.lua | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim/lsp/diagnostic.lua') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index a0568bc09c..2a77992c4d 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -408,6 +408,16 @@ local function disable(bufnr) clear(bufnr) end +--- Refresh diagnostics, only if we have attached clients that support it +---@param bufnr (integer) buffer number +---@param opts? table Additional options to pass to util._refresh +---@private +local function _refresh(bufnr, opts) + opts = opts or {} + opts['bufnr'] = bufnr + util._refresh(ms.textDocument_diagnostic, opts) +end + --- Enable pull diagnostics for a buffer ---@param bufnr (integer) Buffer handle, or 0 for current ---@private @@ -429,7 +439,7 @@ function M._enable(bufnr) return end if bufstates[bufnr] and bufstates[bufnr].enabled then - util._refresh(ms.textDocument_diagnostic, { bufnr = bufnr, only_visible = true }) + _refresh(bufnr, { only_visible = true, client_id = opts.data.client_id }) end end, group = augroup, @@ -438,7 +448,7 @@ function M._enable(bufnr) api.nvim_buf_attach(bufnr, false, { on_reload = function() if bufstates[bufnr] and bufstates[bufnr].enabled then - util._refresh(ms.textDocument_diagnostic, { bufnr = bufnr }) + _refresh(bufnr) end end, on_detach = function() @@ -448,8 +458,16 @@ function M._enable(bufnr) api.nvim_create_autocmd('LspDetach', { buffer = bufnr, - callback = function() - disable(bufnr) + callback = function(args) + 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) + then + disable(bufnr) + end end, group = augroup, }) -- cgit From 2e92065686f62851318150a315591c30b8306a4b Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Thu, 14 Sep 2023 08:23:01 -0500 Subject: docs: replace
 with ``` (#25136)

---
 runtime/lua/vim/lsp/diagnostic.lua | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

(limited to 'runtime/lua/vim/lsp/diagnostic.lua')

diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index 2a77992c4d..73ffa1a46c 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -203,7 +203,8 @@ end
 ---
 --- See |vim.diagnostic.config()| for configuration options. Handler-specific
 --- configuration can be set using |vim.lsp.with()|:
---- 
lua
+---
+--- ```lua
 --- vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
 ---   vim.lsp.diagnostic.on_publish_diagnostics, {
 ---     -- Enable underline, use default values
@@ -221,7 +222,7 @@ end
 ---     update_in_insert = false,
 ---   }
 --- )
---- 
+--- ``` --- ---@param config table Configuration table (see |vim.diagnostic.config()|). function M.on_publish_diagnostics(_, result, ctx, config) @@ -263,7 +264,8 @@ end --- --- See |vim.diagnostic.config()| for configuration options. Handler-specific --- configuration can be set using |vim.lsp.with()|: ----
lua
+---
+--- ```lua
 --- vim.lsp.handlers["textDocument/diagnostic"] = vim.lsp.with(
 ---   vim.lsp.diagnostic.on_diagnostic, {
 ---     -- Enable underline, use default values
@@ -281,7 +283,7 @@ end
 ---     update_in_insert = false,
 ---   }
 --- )
---- 
+--- ``` --- ---@param config table Configuration table (see |vim.diagnostic.config()|). function M.on_diagnostic(_, result, ctx, config) -- cgit From 712adacdf546fbaccd9f2134534889a3f6f36dbc Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 14 Oct 2023 09:47:20 +0200 Subject: refactor(lsp): make is_pull in lsp.diagnostic.get_namespace optional (#25156) Follw up to https://github.com/neovim/neovim/commit/63b3408551561127f7845470eb51404bcd6f547b `is_pull` should be optional, otherwise it is an API change that introduces warnings in consumers. Also fixes the type annotation of `_client_pull_namespaces` where the key is a string. --- runtime/lua/vim/lsp/diagnostic.lua | 41 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'runtime/lua/vim/lsp/diagnostic.lua') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 73ffa1a46c..73444d8c6a 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -159,44 +159,45 @@ local function diagnostic_vim_to_lsp(diagnostics) end, diagnostics) end ----@type table +---@type table local _client_push_namespaces = {} ----@type table + +---@type table local _client_pull_namespaces = {} --- Get the diagnostic namespace associated with an LSP client |vim.diagnostic| for diagnostics --- ---@param client_id integer The id of the LSP client ----@param is_pull boolean Whether the namespace is for a pull or push client +---@param is_pull boolean? Whether the namespace is for a pull or push client. Defaults to push function M.get_namespace(client_id, is_pull) vim.validate({ client_id = { client_id, 'n' } }) - local namespace_table - local key - local name local client = vim.lsp.get_client_by_id(client_id) - if is_pull then - namespace_table = _client_pull_namespaces - local server_id = vim.tbl_get(client.server_capabilities, 'diagnosticProvider', 'identifier') - key = string.format('%d:%s', client_id, server_id or 'nil') - name = string.format( + local server_id = + 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', client and client.name or 'unknown', client_id, server_id or 'nil' ) + local ns = _client_pull_namespaces[key] + if not ns then + ns = api.nvim_create_namespace(name) + _client_pull_namespaces[key] = ns + end + return ns else - namespace_table = _client_push_namespaces - key = client_id - name = string.format('vim.lsp.%s.%d', client and client.name or 'unknown', client_id) - end - - if not namespace_table[key] then - namespace_table[key] = api.nvim_create_namespace(name) + local name = string.format('vim.lsp.%s.%d', client and client.name or 'unknown', client_id) + local ns = _client_push_namespaces[client_id] + if not ns then + ns = api.nvim_create_namespace(name) + _client_push_namespaces[client_id] = ns + end + return ns end - - return namespace_table[key] end --- |lsp-handler| for the method "textDocument/publishDiagnostics" -- cgit From 330444994616e48e5e4d15bbf72d7c5346943565 Mon Sep 17 00:00:00 2001 From: Jorge Mederos <46798594+jmederosalvarado@users.noreply.github.com> Date: Sat, 21 Oct 2023 08:47:14 +0200 Subject: fix(lsp): log unknown diagnostic tags instead of showing a warning (#25705) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To be more in line with the specification: > To support the evolution of enumerations the using side of an enumeration shouldn’t fail on an enumeration value it doesn’t know. It should simply ignore it as a value it can use and try to do its best to preserve the value on round trips --- runtime/lua/vim/lsp/diagnostic.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim/lsp/diagnostic.lua') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 73444d8c6a..b6f0cfa0b3 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -2,6 +2,7 @@ local util = require('vim.lsp.util') local protocol = require('vim.lsp.protocol') +local log = require('vim.lsp.log') local ms = protocol.Methods local api = vim.api @@ -88,10 +89,7 @@ local function tags_lsp_to_vim(diagnostic, client_id) 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 - ) + log.info(string.format('Unknown DiagnosticTag %d from LSP client %d', tag, client_id)) end end return tags -- cgit