mirror of
https://github.com/neovim/neovim.git
synced 2026-03-31 04:42:03 +00:00
feat(diagnostic): custom status format function #36696
Problem: Statusline component of diagnostics allows only the default
format "sign:count".
Solution: Extend vim.diagnostic.Opts.Status to allow a custom signs
or formatting function that provides the status presentation.
This commit is contained in:
@@ -666,9 +666,37 @@ Lua module: vim.diagnostic *diagnostic-api*
|
||||
*vim.diagnostic.Opts.Status*
|
||||
|
||||
Fields: ~
|
||||
• {text}? (`table<vim.diagnostic.Severity,string>`) A table mapping
|
||||
|diagnostic-severity| to the text to use for each severity
|
||||
section.
|
||||
• {format}? (`table<vim.diagnostic.Severity,string>|(fun(counts:table<vim.diagnostic.Severity,integer>): string)`)
|
||||
Either:
|
||||
• a table mapping |diagnostic-severity| to the text to use
|
||||
for each existing severity section.
|
||||
• a function that accepts a mapping of
|
||||
|diagnostic-severity| to the number of diagnostics of the
|
||||
corresponding severity (only those severity levels that
|
||||
have at least 1 diagnostic) and returns a 'statusline'
|
||||
component. In this case highlights must be applied by the
|
||||
user in the `format` function. Example: >lua
|
||||
local signs = {
|
||||
[vim.diagnostic.severity.ERROR] = "A",
|
||||
-- ...
|
||||
}
|
||||
local hl_map = {
|
||||
[vim.diagnostic.severity.ERROR] = 'DiagnosticSignError',
|
||||
-- ...
|
||||
}
|
||||
vim.diagnostic.config({
|
||||
status = {
|
||||
format = function(counts)
|
||||
local items = {}
|
||||
for level, _ in ipairs(vim.diagnostic.severity) do
|
||||
local count = counts[level] or 0
|
||||
table.insert(items, ("%%#%s#%s %s"):format(hl_map[level], signs[level], count))
|
||||
end
|
||||
return table.concat(items, " ")
|
||||
end
|
||||
}
|
||||
})
|
||||
<
|
||||
|
||||
*vim.diagnostic.Opts.Underline*
|
||||
|
||||
@@ -1033,11 +1061,7 @@ status({bufnr}) *vim.diagnostic.status()*
|
||||
Returns formatted string with diagnostics for the current buffer. The
|
||||
severities with 0 diagnostics are left out. Example `E:2 W:3 I:4 H:5`
|
||||
|
||||
To customise appearance, set diagnostic text for each severity with >lua
|
||||
vim.diagnostic.config({
|
||||
status = { text = { [vim.diagnostic.severity.ERROR] = 'e', ... } }
|
||||
})
|
||||
<
|
||||
To customise appearance, see |vim.diagnostic.Opts.Status|.
|
||||
|
||||
Parameters: ~
|
||||
• {bufnr} (`integer?`) Buffer number to get diagnostics from. Defaults
|
||||
|
||||
@@ -31,6 +31,11 @@ LSP
|
||||
• |vim.lsp.buf.selection_range()| now accepts an integer which specifies its
|
||||
direction, rather than a string `'outer'` or `'inner'`.
|
||||
|
||||
DIAGNOSTICS
|
||||
|
||||
• |vim.diagnostic.Opts.Status|.text was removed in favour of
|
||||
|vim.diagnostic.Opts.Status|.format.
|
||||
|
||||
OPTIONS
|
||||
|
||||
• `'completefuzzycollect'` and `'isexpand'` have been removed.
|
||||
|
||||
@@ -189,8 +189,37 @@ end
|
||||
|
||||
--- @class vim.diagnostic.Opts.Status
|
||||
---
|
||||
--- A table mapping |diagnostic-severity| to the text to use for each severity section.
|
||||
--- @field text? table<vim.diagnostic.Severity,string>
|
||||
--- Either:
|
||||
--- - a table mapping |diagnostic-severity| to the text to use for each
|
||||
--- existing severity section.
|
||||
--- - a function that accepts a mapping of |diagnostic-severity| to the
|
||||
--- number of diagnostics of the corresponding severity (only those
|
||||
--- severity levels that have at least 1 diagnostic) and returns
|
||||
--- a 'statusline' component. In this case highlights must be applied
|
||||
--- by the user in the `format` function. Example:
|
||||
--- ```lua
|
||||
--- local signs = {
|
||||
--- [vim.diagnostic.severity.ERROR] = "A",
|
||||
--- -- ...
|
||||
--- }
|
||||
--- local hl_map = {
|
||||
--- [vim.diagnostic.severity.ERROR] = 'DiagnosticSignError',
|
||||
--- -- ...
|
||||
--- }
|
||||
--- vim.diagnostic.config({
|
||||
--- status = {
|
||||
--- format = function(counts)
|
||||
--- local items = {}
|
||||
--- for level, _ in ipairs(vim.diagnostic.severity) do
|
||||
--- local count = counts[level] or 0
|
||||
--- table.insert(items, ("%%#%s#%s %s"):format(hl_map[level], signs[level], count))
|
||||
--- end
|
||||
--- return table.concat(items, " ")
|
||||
--- end
|
||||
--- }
|
||||
--- })
|
||||
--- ```
|
||||
--- @field format? table<vim.diagnostic.Severity,string>|(fun(counts:table<vim.diagnostic.Severity,integer>): string)
|
||||
|
||||
--- @class vim.diagnostic.Opts.Underline
|
||||
---
|
||||
@@ -2969,17 +2998,19 @@ local hl_map = {
|
||||
[M.severity.INFO] = 'DiagnosticSignInfo',
|
||||
[M.severity.HINT] = 'DiagnosticSignHint',
|
||||
}
|
||||
local default_status_signs = {
|
||||
[M.severity.ERROR] = 'E',
|
||||
[M.severity.WARN] = 'W',
|
||||
[M.severity.INFO] = 'I',
|
||||
[M.severity.HINT] = 'H',
|
||||
}
|
||||
|
||||
--- Returns formatted string with diagnostics for the current buffer.
|
||||
--- The severities with 0 diagnostics are left out.
|
||||
--- Example `E:2 W:3 I:4 H:5`
|
||||
---
|
||||
--- To customise appearance, set diagnostic text for each severity with
|
||||
--- ```lua
|
||||
--- vim.diagnostic.config({
|
||||
--- status = { text = { [vim.diagnostic.severity.ERROR] = 'e', ... } }
|
||||
--- })
|
||||
--- ```
|
||||
--- To customise appearance, see |vim.diagnostic.Opts.Status|.
|
||||
---
|
||||
---@param bufnr? integer Buffer number to get diagnostics from.
|
||||
--- Defaults to 0 for the current buffer
|
||||
---
|
||||
@@ -2987,20 +3018,26 @@ local hl_map = {
|
||||
function M.status(bufnr)
|
||||
vim.validate('bufnr', bufnr, 'number', true)
|
||||
bufnr = bufnr or 0
|
||||
local config = assert(M.config()).status or {}
|
||||
vim.validate('config.format', config.format, { 'table', 'function' }, true)
|
||||
local counts = M.count(bufnr)
|
||||
local user_signs = vim.tbl_get(M.config() --[[@as vim.diagnostic.Opts]], 'status', 'text') or {}
|
||||
local signs = vim.tbl_extend('keep', user_signs, { 'E', 'W', 'I', 'H' })
|
||||
local result_str = vim
|
||||
.iter(pairs(counts))
|
||||
:map(function(severity, count)
|
||||
return ('%%#%s#%s:%s'):format(hl_map[severity], signs[severity], count)
|
||||
end)
|
||||
:join(' ')
|
||||
|
||||
local format = config.format or default_status_signs
|
||||
--- @type string
|
||||
local result_str
|
||||
if type(format) == 'table' then
|
||||
local signs = vim.tbl_extend('keep', format, default_status_signs)
|
||||
result_str = vim
|
||||
.iter(pairs(counts))
|
||||
:map(function(severity, count)
|
||||
return ('%%#%s#%s:%s'):format(hl_map[severity], signs[severity], count)
|
||||
end)
|
||||
:join(' ')
|
||||
elseif type(format) == 'function' then
|
||||
result_str = format(counts)
|
||||
end
|
||||
if result_str:len() > 0 then
|
||||
result_str = result_str .. '%##'
|
||||
end
|
||||
|
||||
return result_str
|
||||
end
|
||||
|
||||
|
||||
@@ -4205,11 +4205,11 @@ describe('vim.diagnostic', function()
|
||||
)
|
||||
end)
|
||||
|
||||
it('uses text from diagnostic.config().status.text[severity]', function()
|
||||
it('uses text from diagnostic.config().status.format[severity]', function()
|
||||
local result = exec_lua(function()
|
||||
vim.diagnostic.config({
|
||||
status = {
|
||||
text = {
|
||||
format = {
|
||||
[vim.diagnostic.severity.ERROR] = '⨯',
|
||||
[vim.diagnostic.severity.WARN] = '⚠︎',
|
||||
},
|
||||
@@ -4226,6 +4226,45 @@ describe('vim.diagnostic', function()
|
||||
|
||||
eq('%#DiagnosticSignError#⨯:1 %#DiagnosticSignWarn#⚠︎:1%##', result)
|
||||
end)
|
||||
|
||||
it('uses format function diagnostic.config().status.format', function()
|
||||
local result = exec_lua(function()
|
||||
local signs = {
|
||||
[vim.diagnostic.severity.ERROR] = 'EE',
|
||||
[vim.diagnostic.severity.WARN] = 'WW',
|
||||
[vim.diagnostic.severity.INFO] = 'II',
|
||||
[vim.diagnostic.severity.HINT] = 'HH',
|
||||
}
|
||||
local hl_map = {
|
||||
[vim.diagnostic.severity.ERROR] = 'ERROR',
|
||||
[vim.diagnostic.severity.WARN] = 'WARN',
|
||||
[vim.diagnostic.severity.INFO] = 'INFO',
|
||||
[vim.diagnostic.severity.HINT] = 'HINT',
|
||||
}
|
||||
vim.diagnostic.config({
|
||||
status = {
|
||||
format = function(counts)
|
||||
local items = {}
|
||||
for severity, sign in ipairs(signs) do
|
||||
local count = counts[severity] or 0
|
||||
local hl = hl_map[severity]
|
||||
table.insert(items, ('%%#%s#%s %s'):format(hl, sign, count))
|
||||
end
|
||||
return table.concat(items, ' ')
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
vim.diagnostic.set(_G.diagnostic_ns, 0, {
|
||||
_G.make_error('Error 1', 0, 1, 0, 1),
|
||||
_G.make_warning('Warning 1', 2, 2, 2, 2),
|
||||
})
|
||||
|
||||
return vim.diagnostic.status()
|
||||
end)
|
||||
|
||||
eq('%#ERROR#EE 1 %#WARN#WW 1 %#INFO#II 0 %#HINT#HH 0%##', result)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('handlers', function()
|
||||
|
||||
Reference in New Issue
Block a user