fix(diagnostic): respect "if_many" source option for virtual text (#16697)

The `prefix_source` function only evaluates the sources from the
diagnostics passed to it; however, because each namespace draws its own
virtual text, its diagnostics will never contain more than a single
source (by definition). This requires changing the semantics of what
"if_many" means from "multiple sources in a single 'batch' of
diagnostics" to "multiple sources of all diagnostics within a buffer".
This commit is contained in:
github-actions[bot] 2021-12-17 19:44:16 -07:00 committed by GitHub
parent 9dae939b1f
commit 060eeaa14c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 27 deletions

View File

@ -345,9 +345,12 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
• severity: Only show virtual text for • severity: Only show virtual text for
diagnostics matching the given severity diagnostics matching the given severity
|diagnostic-severity| |diagnostic-severity|
• source: (string) Include the diagnostic • source: (boolean or string) Include the
source in virtual text. One of "always" diagnostic source in virtual text. Use
or "if_many". "if_many" to only show sources if there
is more than one diagnostic source in the
buffer. Otherwise, any truthy value means
to always show the diagnostic source.
• format: (function) A function that takes • format: (function) A function that takes
a diagnostic as input and returns a a diagnostic as input and returns a
string. The return value is the text used string. The return value is the text used
@ -606,9 +609,12 @@ open_float({opts}, {...}) *vim.diagnostic.open_float()*
is interpreted as a [text, hl_group] tuple. is interpreted as a [text, hl_group] tuple.
Overrides the setting from Overrides the setting from
|vim.diagnostic.config()|. |vim.diagnostic.config()|.
• source: (string) Include the diagnostic source • source: (boolean or string) Include the
in the message. One of "always" or "if_many". diagnostic source in the message. Use "if_many"
Overrides the setting from to only show sources if there is more than one
source of diagnostics in the buffer. Otherwise,
any truthy value means to always show the
diagnostic source. Overrides the setting from
|vim.diagnostic.config()|. |vim.diagnostic.config()|.
• format: (function) A function that takes a • format: (function) A function that takes a
diagnostic as input and returns a string. The diagnostic as input and returns a string. The

View File

@ -91,23 +91,22 @@ local function filter_by_severity(severity, diagnostics)
end end
---@private ---@private
local function prefix_source(source, diagnostics) local function count_sources(bufnr)
vim.validate { source = {source, function(v) local seen = {}
return v == "always" or v == "if_many" local count = 0
end, "'always' or 'if_many'" } } for _, namespace_diagnostics in pairs(diagnostic_cache[bufnr]) do
for _, diagnostic in ipairs(namespace_diagnostics) do
if source == "if_many" then if diagnostic.source and not seen[diagnostic.source] then
local sources = {} seen[diagnostic.source] = true
for _, d in pairs(diagnostics) do count = count + 1
if d.source then
sources[d.source] = true
end end
end end
if #vim.tbl_keys(sources) <= 1 then
return diagnostics
end
end end
return count
end
---@private
local function prefix_source(diagnostics)
return vim.tbl_map(function(d) return vim.tbl_map(function(d)
if not d.source then if not d.source then
return d return d
@ -557,8 +556,10 @@ end
--- - virtual_text: (default true) Use virtual text for diagnostics. Options: --- - virtual_text: (default true) Use virtual text for diagnostics. Options:
--- * severity: Only show virtual text for diagnostics matching the given --- * severity: Only show virtual text for diagnostics matching the given
--- severity |diagnostic-severity| --- severity |diagnostic-severity|
--- * source: (string) Include the diagnostic source in virtual --- * source: (boolean or string) Include the diagnostic source in virtual
--- text. One of "always" or "if_many". --- text. Use "if_many" to only show sources if there is more than
--- one diagnostic source in the buffer. Otherwise, any truthy value
--- means to always show the diagnostic source.
--- * format: (function) A function that takes a diagnostic as input and --- * format: (function) A function that takes a diagnostic as input and
--- returns a string. The return value is the text used to display --- returns a string. The return value is the text used to display
--- the diagnostic. Example: --- the diagnostic. Example:
@ -922,8 +923,11 @@ M.handlers.virtual_text = {
if opts.virtual_text.format then if opts.virtual_text.format then
diagnostics = reformat_diagnostics(opts.virtual_text.format, diagnostics) diagnostics = reformat_diagnostics(opts.virtual_text.format, diagnostics)
end end
if opts.virtual_text.source then if
diagnostics = prefix_source(opts.virtual_text.source, diagnostics) opts.virtual_text.source
and (opts.virtual_text.source ~= "if_many" or count_sources(bufnr) > 1)
then
diagnostics = prefix_source(diagnostics)
end end
if opts.virtual_text.severity then if opts.virtual_text.severity then
severity = opts.virtual_text.severity severity = opts.virtual_text.severity
@ -1148,8 +1152,11 @@ end
--- - header: (string or table) String to use as the header for the floating window. If a --- - header: (string or table) String to use as the header for the floating window. If a
--- table, it is interpreted as a [text, hl_group] tuple. Overrides the setting --- table, it is interpreted as a [text, hl_group] tuple. Overrides the setting
--- from |vim.diagnostic.config()|. --- from |vim.diagnostic.config()|.
--- - source: (string) Include the diagnostic source in the message. One of "always" or --- - source: (boolean or string) Include the diagnostic source in the message.
--- "if_many". Overrides the setting from |vim.diagnostic.config()|. --- Use "if_many" to only show sources if there is more than one source of
--- diagnostics in the buffer. Otherwise, any truthy value means to always show
--- the diagnostic source. Overrides the setting from
--- |vim.diagnostic.config()|.
--- - format: (function) A function that takes a diagnostic as input and returns a --- - format: (function) A function that takes a diagnostic as input and returns a
--- string. The return value is the text used to display the diagnostic. --- string. The return value is the text used to display the diagnostic.
--- Overrides the setting from |vim.diagnostic.config()|. --- Overrides the setting from |vim.diagnostic.config()|.
@ -1261,8 +1268,8 @@ function M.open_float(opts, ...)
diagnostics = reformat_diagnostics(opts.format, diagnostics) diagnostics = reformat_diagnostics(opts.format, diagnostics)
end end
if opts.source then if opts.source and (opts.source ~= "if_many" or count_sources(bufnr) > 1) then
diagnostics = prefix_source(opts.source, diagnostics) diagnostics = prefix_source(diagnostics)
end end
local prefix_opt = if_nil(opts.prefix, (scope == "cursor" and #diagnostics <= 1) and "" or function(_, i) local prefix_opt = if_nil(opts.prefix, (scope == "cursor" and #diagnostics <= 1) and "" or function(_, i)