feat(diagnostic): format() can filter diagnostics by returning nil #32302

This commit is contained in:
Maria José Solano 2025-02-03 00:54:31 -08:00 committed by GitHub
parent 3a28930157
commit 445ecca398
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 67 additions and 22 deletions

View File

@ -376,6 +376,10 @@ Where possible, these patterns apply to _both_ Lua and the API:
- See |vim.lsp.inlay_hint.enable()| and |vim.lsp.inlay_hint.is_enabled()|
for a reference implementation of these "best practices".
- NOTE: open questions: https://github.com/neovim/neovim/issues/28603
- Transformation functions should also have a filter functionality when
appropriate. That is, when the function returns a nil value it "filters" its
input, otherwise the transformed value is used.
- Example: |vim.diagnostic.config.format()|
API DESIGN GUIDELINES *dev-api*

View File

@ -532,11 +532,13 @@ Lua module: vim.diagnostic *diagnostic-api*
the buffer. Otherwise, any truthy value means to
always show the diagnostic source. Overrides the
setting from |vim.diagnostic.config()|.
• {format}? (`fun(diagnostic:vim.Diagnostic): string`) A
• {format}? (`fun(diagnostic:vim.Diagnostic): string?`) A
function that takes a diagnostic as input and
returns a string. The return value is the text used
to display the diagnostic. Overrides the setting
from |vim.diagnostic.config()|.
returns a string or nil. If the return value is nil,
the diagnostic is not displayed by the handler. Else
the output text is used to display the diagnostic.
Overrides the setting from
|vim.diagnostic.config()|.
• {prefix}? (`string|table|(fun(diagnostic:vim.Diagnostic,i:integer,total:integer): string, string)`)
Prefix each diagnostic in the floating window:
• If a `function`, {i} is the index of the
@ -607,10 +609,11 @@ Lua module: vim.diagnostic *diagnostic-api*
Fields: ~
• {current_line}? (`boolean`, default: `false`) Only show diagnostics
for the current line.
• {format}? (`fun(diagnostic:vim.Diagnostic): string`) A function
that takes a diagnostic as input and returns a
string. The return value is the text used to display
the diagnostic.
• {format}? (`fun(diagnostic:vim.Diagnostic): string?`) A
function that takes a diagnostic as input and returns
a string or nil. If the return value is nil, the
diagnostic is not displayed by the handler. Else the
output text is used to display the diagnostic.
*vim.diagnostic.Opts.VirtualText*
@ -635,9 +638,9 @@ Lua module: vim.diagnostic *diagnostic-api*
• {suffix}? (`string|(fun(diagnostic:vim.Diagnostic): string)`)
Append diagnostic message with suffix. This can
be used to render an LSP diagnostic error code.
• {format}? (`fun(diagnostic:vim.Diagnostic): string`) The
return value is the text used to display the
diagnostic. Example: >lua
• {format}? (`fun(diagnostic:vim.Diagnostic): string?`) If
not nil, the return value is the text used to
display the diagnostic. Example: >lua
function(diagnostic)
if diagnostic.severity == vim.diagnostic.severity.ERROR then
return string.format("E: %s", diagnostic.message)
@ -645,6 +648,9 @@ Lua module: vim.diagnostic *diagnostic-api*
return diagnostic.message
end
<
If the return value is nil, the diagnostic is
not displayed by the handler.
• {hl_mode}? (`'replace'|'combine'|'blend'`) See
|nvim_buf_set_extmark()|.
• {virt_text}? (`[string,any][]`) See |nvim_buf_set_extmark()|.

View File

@ -150,10 +150,11 @@ end
--- Overrides the setting from |vim.diagnostic.config()|.
--- @field source? boolean|'if_many'
---
--- A function that takes a diagnostic as input and returns a string.
--- The return value is the text used to display the diagnostic.
--- A function that takes a diagnostic as input and returns a string or nil.
--- If the return value is nil, the diagnostic is not displayed by the handler.
--- Else the output text is used to display the diagnostic.
--- Overrides the setting from |vim.diagnostic.config()|.
--- @field format? fun(diagnostic:vim.Diagnostic): string
--- @field format? fun(diagnostic:vim.Diagnostic): string?
---
--- Prefix each diagnostic in the floating window:
--- - If a `function`, {i} is the index of the diagnostic being evaluated and
@ -207,7 +208,7 @@ end
--- This can be used to render an LSP diagnostic error code.
--- @field suffix? string|(fun(diagnostic:vim.Diagnostic): string)
---
--- The return value is the text used to display the diagnostic. Example:
--- If not nil, the return value is the text used to display the diagnostic. Example:
--- ```lua
--- function(diagnostic)
--- if diagnostic.severity == vim.diagnostic.severity.ERROR then
@ -216,7 +217,8 @@ end
--- return diagnostic.message
--- end
--- ```
--- @field format? fun(diagnostic:vim.Diagnostic): string
--- If the return value is nil, the diagnostic is not displayed by the handler.
--- @field format? fun(diagnostic:vim.Diagnostic): string?
---
--- See |nvim_buf_set_extmark()|.
--- @field hl_mode? 'replace'|'combine'|'blend'
@ -239,9 +241,10 @@ end
--- (default: `false`)
--- @field current_line? boolean
---
--- A function that takes a diagnostic as input and returns a string.
--- The return value is the text used to display the diagnostic.
--- @field format? fun(diagnostic:vim.Diagnostic): string
--- A function that takes a diagnostic as input and returns a string or nil.
--- If the return value is nil, the diagnostic is not displayed by the handler.
--- Else the output text is used to display the diagnostic.
--- @field format? fun(diagnostic:vim.Diagnostic): string?
--- @class vim.diagnostic.Opts.Signs
---
@ -503,15 +506,21 @@ local function prefix_source(diagnostics)
end, diagnostics)
end
--- @param format fun(vim.Diagnostic): string?
--- @param diagnostics vim.Diagnostic[]
--- @return vim.Diagnostic[]
local function reformat_diagnostics(format, diagnostics)
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
diagnostic.message = format(diagnostic)
local formatted = {}
for _, diagnostic in ipairs(diagnostics) do
local message = format(diagnostic)
if message ~= nil then
local formatted_diagnostic = vim.deepcopy(diagnostic, true)
formatted_diagnostic.message = message
table.insert(formatted, formatted_diagnostic)
end
end
return formatted
end

View File

@ -2134,6 +2134,32 @@ describe('vim.diagnostic', function()
end)
)
end)
it('can filter diagnostics by returning nil when formatting', function()
local result = exec_lua(function()
vim.diagnostic.config {
virtual_text = {
format = function(diagnostic)
if diagnostic.code == 'foo_err' then
return nil
end
return diagnostic.message
end,
},
}
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
_G.make_error('An error here!', 0, 0, 0, 0, 'foo_server', 'foo_err'),
_G.make_error('An error there!', 1, 1, 1, 1, 'bar_server', 'bar_err'),
})
local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
return extmarks
end)
eq(1, #result)
eq(' An error there!', result[1][4].virt_text[3][1])
end)
end)
describe('handlers.virtual_lines', function()