aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/diagnostic.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/diagnostic.lua')
-rw-r--r--runtime/lua/vim/diagnostic.lua289
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