diff options
Diffstat (limited to 'runtime/lua/vim/diagnostic.lua')
-rw-r--r-- | runtime/lua/vim/diagnostic.lua | 289 |
1 files changed, 111 insertions, 178 deletions
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index ef00a1fa51..4fb8c6a686 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -71,9 +71,9 @@ local M = {} --- (default: `false`) --- @field update_in_insert? boolean --- ---- Sort diagnostics by severity. This affects the order in which signs and ---- virtual text are displayed. When true, higher severities are displayed ---- before lower severities (e.g. ERROR is displayed before WARN). +--- Sort diagnostics by severity. This affects the order in which signs, +--- virtual text, and highlights are displayed. When true, higher severities are +--- displayed before lower severities (e.g. ERROR is displayed before WARN). --- Options: --- - {reverse}? (boolean) Reverse sort order --- (default: `false`) @@ -282,6 +282,11 @@ M.severity = { [2] = 'WARN', [3] = 'INFO', [4] = 'HINT', + --- Mappings from qflist/loclist error types to severities + E = 1, + W = 2, + I = 3, + N = 4, } --- @alias vim.diagnostic.SeverityInt 1|2|3|4 @@ -289,12 +294,6 @@ M.severity = { --- See |diagnostic-severity| and |vim.diagnostic.get()| --- @alias vim.diagnostic.SeverityFilter vim.diagnostic.Severity|vim.diagnostic.Severity[]|{min:vim.diagnostic.Severity,max:vim.diagnostic.Severity} --- Mappings from qflist/loclist error types to severities -M.severity.E = M.severity.ERROR -M.severity.W = M.severity.WARN -M.severity.I = M.severity.INFO -M.severity.N = M.severity.HINT - --- @type vim.diagnostic.Opts local global_diagnostic_options = { signs = true, @@ -320,7 +319,7 @@ local global_diagnostic_options = { --- @type table<string,vim.diagnostic.Handler> M.handlers = setmetatable({}, { __newindex = function(t, name, handler) - vim.validate({ handler = { handler, 't' } }) + vim.validate('handler', handler, 'table') rawset(t, name, handler) if global_diagnostic_options[name] == nil then global_diagnostic_options[name] = true @@ -477,10 +476,8 @@ end --- @param diagnostics vim.Diagnostic[] --- @return vim.Diagnostic[] local function reformat_diagnostics(format, diagnostics) - vim.validate({ - format = { format, 'f' }, - diagnostics = { diagnostics, 't' }, - }) + vim.validate('format', format, 'function') + vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics') local formatted = vim.deepcopy(diagnostics, true) for _, diagnostic in ipairs(formatted) do @@ -659,6 +656,28 @@ local function save_extmarks(namespace, bufnr) api.nvim_buf_get_extmarks(bufnr, namespace, 0, -1, { details = true }) end +--- Create a function that converts a diagnostic severity to an extmark priority. +--- @param priority integer Base priority +--- @param opts vim.diagnostic.OptsResolved +--- @return fun(severity: vim.diagnostic.Severity): integer +local function severity_to_extmark_priority(priority, opts) + if opts.severity_sort then + if type(opts.severity_sort) == 'table' and opts.severity_sort.reverse then + return function(severity) + return priority + (severity - vim.diagnostic.severity.ERROR) + end + end + + return function(severity) + return priority + (vim.diagnostic.severity.HINT - severity) + end + end + + return function() + return priority + end +end + --- @type table<string,true> local registered_autocmds = {} @@ -871,14 +890,14 @@ local function next_diagnostic(search_forward, opts) if opts.win_id then vim.deprecate('opts.win_id', 'opts.winid', '0.13') opts.winid = opts.win_id - opts.win_id = nil + opts.win_id = nil --- @diagnostic disable-line end -- Support deprecated cursor_position alias if opts.cursor_position then vim.deprecate('opts.cursor_position', 'opts.pos', '0.13') opts.pos = opts.cursor_position - opts.cursor_position = nil + opts.cursor_position = nil --- @diagnostic disable-line end local winid = opts.winid or api.nvim_get_current_win() @@ -959,7 +978,7 @@ local function goto_diagnostic(diagnostic, opts) if opts.win_id then vim.deprecate('opts.win_id', 'opts.winid', '0.13') opts.winid = opts.win_id - opts.win_id = nil + opts.win_id = nil --- @diagnostic disable-line end local winid = opts.winid or api.nvim_get_current_win() @@ -972,8 +991,9 @@ local function goto_diagnostic(diagnostic, opts) vim.cmd('normal! zv') end) - if opts.float then - local float_opts = type(opts.float) == 'table' and opts.float or {} + local float_opts = opts.float + if float_opts then + float_opts = type(float_opts) == 'table' and float_opts or {} vim.schedule(function() M.open_float(vim.tbl_extend('keep', float_opts, { bufnr = api.nvim_win_get_buf(winid), @@ -1012,10 +1032,8 @@ end --- When omitted, update the global diagnostic options. ---@return vim.diagnostic.Opts? : Current diagnostic config if {opts} is omitted. function M.config(opts, namespace) - vim.validate({ - opts = { opts, 't', true }, - namespace = { namespace, 'n', true }, - }) + vim.validate('opts', opts, 'table', true) + vim.validate('namespace', namespace, 'number', true) local t --- @type vim.diagnostic.Opts if namespace then @@ -1058,16 +1076,10 @@ end ---@param diagnostics vim.Diagnostic[] ---@param opts? vim.diagnostic.Opts Display options to pass to |vim.diagnostic.show()| function M.set(namespace, bufnr, diagnostics, opts) - vim.validate({ - namespace = { namespace, 'n' }, - bufnr = { bufnr, 'n' }, - diagnostics = { - diagnostics, - vim.islist, - 'a list of diagnostics', - }, - opts = { opts, 't', true }, - }) + vim.validate('namespace', namespace, 'number') + vim.validate('bufnr', bufnr, 'number') + vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics') + vim.validate('opts', opts, 'table', true) bufnr = get_bufnr(bufnr) @@ -1092,7 +1104,7 @@ end ---@param namespace integer Diagnostic namespace ---@return vim.diagnostic.NS : Namespace metadata function M.get_namespace(namespace) - vim.validate({ namespace = { namespace, 'n' } }) + vim.validate('namespace', namespace, 'number') if not all_namespaces[namespace] then local name --- @type string? for k, v in pairs(api.nvim_get_namespaces()) do @@ -1131,10 +1143,8 @@ end ---@return vim.Diagnostic[] : Fields `bufnr`, `end_lnum`, `end_col`, and `severity` --- are guaranteed to be present. function M.get(bufnr, opts) - vim.validate({ - bufnr = { bufnr, 'n', true }, - opts = { opts, 't', true }, - }) + vim.validate('bufnr', bufnr, 'number', true) + vim.validate('opts', opts, 'table', true) return vim.deepcopy(get_diagnostics(bufnr, opts, false), true) end @@ -1147,10 +1157,8 @@ end ---@return table : Table with actually present severity values as keys --- (see |diagnostic-severity|) and integer counts as values. function M.count(bufnr, opts) - vim.validate({ - bufnr = { bufnr, 'n', true }, - opts = { opts, 't', true }, - }) + vim.validate('bufnr', bufnr, 'number', true) + vim.validate('opts', opts, 'table', true) local diagnostics = get_diagnostics(bufnr, opts, false) local count = {} --- @type table<integer,integer> @@ -1309,7 +1317,7 @@ function M.jump(opts) if opts.cursor_position then vim.deprecate('opts.cursor_position', 'opts.pos', '0.13') opts.pos = opts.cursor_position - opts.cursor_position = nil + opts.cursor_position = nil --- @diagnostic disable-line end local diag = nil @@ -1348,16 +1356,10 @@ end M.handlers.signs = { show = function(namespace, bufnr, diagnostics, opts) - vim.validate({ - namespace = { namespace, 'n' }, - bufnr = { bufnr, 'n' }, - diagnostics = { - diagnostics, - vim.islist, - 'a list of diagnostics', - }, - opts = { opts, 't', true }, - }) + vim.validate('namespace', namespace, 'number') + vim.validate('bufnr', bufnr, 'number') + vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics') + vim.validate('opts', opts, 'table', true) bufnr = get_bufnr(bufnr) opts = opts or {} @@ -1372,22 +1374,7 @@ M.handlers.signs = { -- 10 is the default sign priority when none is explicitly specified local priority = opts.signs and opts.signs.priority or 10 - local get_priority --- @type function - if opts.severity_sort then - if type(opts.severity_sort) == 'table' and opts.severity_sort.reverse then - get_priority = function(severity) - return priority + (severity - vim.diagnostic.severity.ERROR) - end - else - get_priority = function(severity) - return priority + (vim.diagnostic.severity.HINT - severity) - end - end - else - get_priority = function() - return priority - end - end + local get_priority = severity_to_extmark_priority(priority, opts) local ns = M.get_namespace(namespace) if not ns.user_data.sign_ns then @@ -1475,16 +1462,10 @@ M.handlers.signs = { M.handlers.underline = { show = function(namespace, bufnr, diagnostics, opts) - vim.validate({ - namespace = { namespace, 'n' }, - bufnr = { bufnr, 'n' }, - diagnostics = { - diagnostics, - vim.islist, - 'a list of diagnostics', - }, - opts = { opts, 't', true }, - }) + vim.validate('namespace', namespace, 'number') + vim.validate('bufnr', bufnr, 'number') + vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics') + vim.validate('opts', opts, 'table', true) bufnr = get_bufnr(bufnr) opts = opts or {} @@ -1504,15 +1485,12 @@ M.handlers.underline = { end local underline_ns = ns.user_data.underline_ns + local get_priority = severity_to_extmark_priority(vim.hl.priorities.diagnostics, opts) + for _, diagnostic in ipairs(diagnostics) do - --- @type string? + -- Default to error if we don't have a highlight associated local higroup = underline_highlight_map[assert(diagnostic.severity)] - - if higroup == nil then - -- Default to error if we don't have a highlight associated - -- TODO(lewis6991): this is always nil since underline_highlight_map only has integer keys - higroup = underline_highlight_map.Error - end + or underline_highlight_map[vim.diagnostic.severity.ERROR] if diagnostic._tags then -- TODO(lewis6991): we should be able to stack these. @@ -1524,13 +1502,13 @@ M.handlers.underline = { end end - vim.highlight.range( + vim.hl.range( bufnr, underline_ns, higroup, { diagnostic.lnum, diagnostic.col }, { diagnostic.end_lnum, diagnostic.end_col }, - { priority = vim.highlight.priorities.diagnostics } + { priority = get_priority(diagnostic.severity) } ) end save_extmarks(underline_ns, bufnr) @@ -1548,16 +1526,10 @@ M.handlers.underline = { M.handlers.virtual_text = { show = function(namespace, bufnr, diagnostics, opts) - vim.validate({ - namespace = { namespace, 'n' }, - bufnr = { bufnr, 'n' }, - diagnostics = { - diagnostics, - vim.islist, - 'a list of diagnostics', - }, - opts = { opts, 't', true }, - }) + vim.validate('namespace', namespace, 'number') + vim.validate('bufnr', bufnr, 'number') + vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics') + vim.validate('opts', opts, 'table', true) bufnr = get_bufnr(bufnr) opts = opts or {} @@ -1681,10 +1653,8 @@ end ---@param bufnr integer? Buffer number, or 0 for current buffer. When --- omitted, hide diagnostics in all buffers. function M.hide(namespace, bufnr) - vim.validate({ - namespace = { namespace, 'n', true }, - bufnr = { bufnr, 'n', true }, - }) + vim.validate('namespace', namespace, 'number', true) + vim.validate('bufnr', bufnr, 'number', true) local buffers = bufnr and { get_bufnr(bufnr) } or vim.tbl_keys(diagnostic_cache) for _, iter_bufnr in ipairs(buffers) do @@ -1741,18 +1711,10 @@ end --- or {bufnr} is nil. ---@param opts? vim.diagnostic.Opts Display options. function M.show(namespace, bufnr, diagnostics, opts) - vim.validate({ - namespace = { namespace, 'n', true }, - bufnr = { bufnr, 'n', true }, - diagnostics = { - diagnostics, - function(v) - return v == nil or vim.islist(v) - end, - 'a list of diagnostics', - }, - opts = { opts, 't', true }, - }) + vim.validate('namespace', namespace, 'number', true) + vim.validate('bufnr', bufnr, 'number', true) + vim.validate('diagnostics', diagnostics, vim.islist, true, 'a list of diagnostics') + vim.validate('opts', opts, 'table', true) if not bufnr or not namespace then assert(not diagnostics, 'Cannot show diagnostics without a buffer and namespace') @@ -1825,9 +1787,7 @@ function M.open_float(opts, ...) bufnr = opts opts = ... --- @type vim.diagnostic.Opts.Float else - vim.validate({ - opts = { opts, 't', true }, - }) + vim.validate('opts', opts, 'table', true) end opts = opts or {} @@ -1905,13 +1865,7 @@ function M.open_float(opts, ...) local highlights = {} --- @type table[] local header = if_nil(opts.header, 'Diagnostics:') if header then - vim.validate({ - header = { - header, - { 'string', 'table' }, - "'string' or 'table'", - }, - }) + vim.validate('header', header, { 'string', 'table' }, "'string' or 'table'") if type(header) == 'table' then -- Don't insert any lines for an empty string if string.len(if_nil(header[1], '')) > 0 then @@ -1939,13 +1893,12 @@ function M.open_float(opts, ...) local prefix, prefix_hl_group --- @type string?, string? if prefix_opt then - vim.validate({ - prefix = { - prefix_opt, - { 'string', 'table', 'function' }, - "'string' or 'table' or 'function'", - }, - }) + vim.validate( + 'prefix', + prefix_opt, + { 'string', 'table', 'function' }, + "'string' or 'table' or 'function'" + ) if type(prefix_opt) == 'string' then prefix, prefix_hl_group = prefix_opt, 'NormalFloat' elseif type(prefix_opt) == 'table' then @@ -1959,13 +1912,12 @@ function M.open_float(opts, ...) local suffix, suffix_hl_group --- @type string?, string? if suffix_opt then - vim.validate({ - suffix = { - suffix_opt, - { 'string', 'table', 'function' }, - "'string' or 'table' or 'function'", - }, - }) + vim.validate( + 'suffix', + suffix_opt, + { 'string', 'table', 'function' }, + "'string' or 'table' or 'function'" + ) if type(suffix_opt) == 'string' then suffix, suffix_hl_group = suffix_opt, 'NormalFloat' elseif type(suffix_opt) == 'table' then @@ -2038,10 +1990,8 @@ end ---@param bufnr integer? Remove diagnostics for the given buffer. When omitted, --- diagnostics are removed for all buffers. function M.reset(namespace, bufnr) - vim.validate({ - namespace = { namespace, 'n', true }, - bufnr = { bufnr, 'n', true }, - }) + vim.validate('namespace', namespace, 'number', true) + vim.validate('bufnr', bufnr, 'number', true) local buffers = bufnr and { get_bufnr(bufnr) } or vim.tbl_keys(diagnostic_cache) for _, iter_bufnr in ipairs(buffers) do @@ -2144,10 +2094,8 @@ function M.enable(enable, filter) '0.12' ) - vim.validate({ - enable = { enable, 'n', true }, -- Legacy `bufnr` arg. - filter = { filter, 'n', true }, -- Legacy `namespace` arg. - }) + vim.validate('enable', enable, 'number', true) -- Legacy `bufnr` arg. + vim.validate('filter', filter, 'number', true) -- Legacy `namespace` arg. local ns_id = type(filter) == 'number' and filter or nil filter = {} @@ -2156,17 +2104,16 @@ function M.enable(enable, filter) enable = true else filter = filter or {} - vim.validate({ - enable = { enable, 'b', true }, - filter = { filter, 't', true }, - }) + vim.validate('enable', enable, 'boolean', true) + vim.validate('filter', filter, 'table', true) end enable = enable == nil and true or enable local bufnr = filter.bufnr + local ns_id = filter.ns_id - if bufnr == nil then - if filter.ns_id == nil then + if not bufnr then + if not ns_id then diagnostic_disabled = ( enable -- Enable everything by setting diagnostic_disabled to an empty table. @@ -2180,12 +2127,12 @@ function M.enable(enable, filter) }) ) else - local ns = M.get_namespace(filter.ns_id) + local ns = M.get_namespace(ns_id) ns.disabled = not enable end else bufnr = get_bufnr(bufnr) - if filter.ns_id == nil then + if not ns_id then diagnostic_disabled[bufnr] = (not enable) and true or nil else if type(diagnostic_disabled[bufnr]) ~= 'table' then @@ -2195,14 +2142,14 @@ function M.enable(enable, filter) diagnostic_disabled[bufnr] = {} end end - diagnostic_disabled[bufnr][filter.ns_id] = (not enable) and true or nil + diagnostic_disabled[bufnr][ns_id] = (not enable) and true or nil end end if enable then - M.show(filter.ns_id, bufnr) + M.show(ns_id, bufnr) else - M.hide(filter.ns_id, bufnr) + M.hide(ns_id, bufnr) end end @@ -2234,13 +2181,11 @@ end --- ERROR. ---@return vim.Diagnostic?: |vim.Diagnostic| structure or `nil` if {pat} fails to match {str}. function M.match(str, pat, groups, severity_map, defaults) - vim.validate({ - str = { str, 's' }, - pat = { pat, 's' }, - groups = { groups, 't' }, - severity_map = { severity_map, 't', true }, - defaults = { defaults, 't', true }, - }) + vim.validate('str', str, 'string') + vim.validate('pat', pat, 'string') + vim.validate('groups', groups, 'table') + vim.validate('severity_map', severity_map, 'table', true) + vim.validate('defaults', defaults, 'table', true) --- @type table<string,vim.diagnostic.Severity> severity_map = severity_map or M.severity @@ -2283,13 +2228,7 @@ local errlist_type_map = { ---@param diagnostics vim.Diagnostic[] ---@return table[] : Quickfix list items |setqflist-what| function M.toqflist(diagnostics) - vim.validate({ - diagnostics = { - diagnostics, - vim.islist, - 'a list of diagnostics', - }, - }) + vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics') local list = {} --- @type table[] for _, v in ipairs(diagnostics) do @@ -2323,13 +2262,7 @@ end ---@param list table[] List of quickfix items from |getqflist()| or |getloclist()|. ---@return vim.Diagnostic[] function M.fromqflist(list) - vim.validate({ - list = { - list, - vim.islist, - 'a list of quickfix items', - }, - }) + vim.validate('list', list, 'table') local diagnostics = {} --- @type vim.Diagnostic[] for _, item in ipairs(list) do |