feat(diagnostics)!: sort underline severity_sort (#30898)

feat(diagnostics)!: sort underline with severity_sort

BREAKING CHANGE: underline will be applied with a higher value than `vim.hl.priorities.diagnostics`
This commit is contained in:
Donatas 2024-10-27 18:36:39 +02:00 committed by GitHub
parent adf7c98d60
commit a9e725b26e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 69 additions and 24 deletions

View File

@ -445,10 +445,10 @@ Lua module: vim.diagnostic *diagnostic-api*
updated on |InsertLeave|) updated on |InsertLeave|)
• {severity_sort}? (`boolean|{reverse?:boolean}`, default: `false`) • {severity_sort}? (`boolean|{reverse?:boolean}`, default: `false`)
Sort diagnostics by severity. This affects the Sort diagnostics by severity. This affects the
order in which signs and virtual text are order in which signs, virtual text, and
displayed. When true, higher severities are highlights are displayed. When true, higher
displayed before lower severities (e.g. ERROR is severities are displayed before lower severities
displayed before WARN). Options: (e.g. ERROR is displayed before WARN). Options:
• {reverse}? (boolean) Reverse sort order • {reverse}? (boolean) Reverse sort order
• {jump}? (`vim.diagnostic.Opts.Jump`) Default values for • {jump}? (`vim.diagnostic.Opts.Jump`) Default values for
|vim.diagnostic.jump()|. See |vim.diagnostic.jump()|. See

View File

@ -55,6 +55,8 @@ DIAGNOSTICS
• |vim.diagnostic.config()| accepts a "jump" table to specify defaults for • |vim.diagnostic.config()| accepts a "jump" table to specify defaults for
|vim.diagnostic.jump()|. |vim.diagnostic.jump()|.
• The "underline" diagnostics handler sorts diagnostics by severity when using
the "severity_sort" option.
EDITOR EDITOR

View File

@ -71,9 +71,9 @@ local M = {}
--- (default: `false`) --- (default: `false`)
--- @field update_in_insert? boolean --- @field update_in_insert? boolean
--- ---
--- Sort diagnostics by severity. This affects the order in which signs and --- Sort diagnostics by severity. This affects the order in which signs,
--- virtual text are displayed. When true, higher severities are displayed --- virtual text, and highlights are displayed. When true, higher severities are
--- before lower severities (e.g. ERROR is displayed before WARN). --- displayed before lower severities (e.g. ERROR is displayed before WARN).
--- Options: --- Options:
--- - {reverse}? (boolean) Reverse sort order --- - {reverse}? (boolean) Reverse sort order
--- (default: `false`) --- (default: `false`)
@ -657,6 +657,28 @@ local function save_extmarks(namespace, bufnr)
api.nvim_buf_get_extmarks(bufnr, namespace, 0, -1, { details = true }) api.nvim_buf_get_extmarks(bufnr, namespace, 0, -1, { details = true })
end 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> --- @type table<string,true>
local registered_autocmds = {} local registered_autocmds = {}
@ -1352,22 +1374,7 @@ M.handlers.signs = {
-- 10 is the default sign priority when none is explicitly specified -- 10 is the default sign priority when none is explicitly specified
local priority = opts.signs and opts.signs.priority or 10 local priority = opts.signs and opts.signs.priority or 10
local get_priority --- @type function local get_priority = severity_to_extmark_priority(priority, opts)
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 ns = M.get_namespace(namespace) local ns = M.get_namespace(namespace)
if not ns.user_data.sign_ns then if not ns.user_data.sign_ns then
@ -1478,6 +1485,8 @@ M.handlers.underline = {
end end
local underline_ns = ns.user_data.underline_ns 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 for _, diagnostic in ipairs(diagnostics) do
--- @type string? --- @type string?
local higroup = underline_highlight_map[assert(diagnostic.severity)] local higroup = underline_highlight_map[assert(diagnostic.severity)]
@ -1504,7 +1513,7 @@ M.handlers.underline = {
higroup, higroup,
{ diagnostic.lnum, diagnostic.col }, { diagnostic.lnum, diagnostic.col },
{ diagnostic.end_lnum, diagnostic.end_col }, { diagnostic.end_lnum, diagnostic.end_col },
{ priority = vim.hl.priorities.diagnostics } { priority = get_priority(diagnostic.severity) }
) )
end end
save_extmarks(underline_ns, bufnr) save_extmarks(underline_ns, bufnr)

View File

@ -111,6 +111,19 @@ describe('vim.diagnostic', function()
{ details = true } { details = true }
) )
end end
---@param ns integer
function _G.get_underline_extmarks(ns)
---@type integer
local underline_ns = vim.diagnostic.get_namespace(ns).user_data.underline_ns
return vim.api.nvim_buf_get_extmarks(
_G.diagnostic_bufnr,
underline_ns,
0,
-1,
{ details = true }
)
end
end) end)
exec_lua(function() exec_lua(function()
@ -1813,6 +1826,21 @@ describe('vim.diagnostic', function()
_G.make_info('Info', 4, 4, 4, 4), _G.make_info('Info', 4, 4, 4, 4),
}) })
function _G.get_highest_underline_hl(severity_sort)
vim.diagnostic.config({
underline = true,
severity_sort = severity_sort,
})
local extmarks = _G.get_underline_extmarks(_G.diagnostic_ns)
table.sort(extmarks, function(a, b)
return a[4].priority > b[4].priority
end)
return extmarks[1][4].hl_group
end
function _G.get_virt_text_and_signs(severity_sort) function _G.get_virt_text_and_signs(severity_sort)
vim.diagnostic.config({ vim.diagnostic.config({
severity_sort = severity_sort, severity_sort = severity_sort,
@ -1864,6 +1892,12 @@ describe('vim.diagnostic', function()
result = exec_lua [[return _G.get_virt_text_and_signs({ reverse = true })]] result = exec_lua [[return _G.get_virt_text_and_signs({ reverse = true })]]
eq({ 'Error', 'Warn', 'Info' }, result[1]) eq({ 'Error', 'Warn', 'Info' }, result[1])
eq({ 'Info', 'Warn', 'Error' }, result[2]) eq({ 'Info', 'Warn', 'Error' }, result[2])
local underline_hl = exec_lua [[return _G.get_highest_underline_hl(true)]]
eq('DiagnosticUnderlineError', underline_hl)
underline_hl = exec_lua [[return _G.get_highest_underline_hl({ reverse = true })]]
eq('DiagnosticUnderlineInfo', underline_hl)
end) end)
it('can show diagnostic sources in virtual text', function() it('can show diagnostic sources in virtual text', function()