Skip to content

Commit

Permalink
feat(diagnostics)!: sort underline severity_sort (neovim#30898)
Browse files Browse the repository at this point in the history
feat(diagnostics)!: sort underline with severity_sort

BREAKING CHANGE: underline will be applied with a higher value than `vim.hl.priorities.diagnostics`
  • Loading branch information
Tronikelis authored Oct 27, 2024
1 parent adf7c98 commit a9e725b
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 24 deletions.
8 changes: 4 additions & 4 deletions runtime/doc/diagnostic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -445,10 +445,10 @@ Lua module: vim.diagnostic *diagnostic-api*
updated on |InsertLeave|)
• {severity_sort}? (`boolean|{reverse?:boolean}`, default: `false`)
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). Options:
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
{jump}? (`vim.diagnostic.Opts.Jump`) Default values for
|vim.diagnostic.jump()|. See
Expand Down
2 changes: 2 additions & 0 deletions runtime/doc/news.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ DIAGNOSTICS

|vim.diagnostic.config()| accepts a "jump" table to specify defaults for
|vim.diagnostic.jump()|.
• The "underline" diagnostics handler sorts diagnostics by severity when using
the "severity_sort" option.

EDITOR

Expand Down
49 changes: 29 additions & 20 deletions runtime/lua/vim/diagnostic.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
Expand Down Expand Up @@ -657,6 +657,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 = {}

Expand Down Expand Up @@ -1352,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
Expand Down Expand Up @@ -1478,6 +1485,8 @@ 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?
local higroup = underline_highlight_map[assert(diagnostic.severity)]
Expand All @@ -1504,7 +1513,7 @@ M.handlers.underline = {
higroup,
{ diagnostic.lnum, diagnostic.col },
{ diagnostic.end_lnum, diagnostic.end_col },
{ priority = vim.hl.priorities.diagnostics }
{ priority = get_priority(diagnostic.severity) }
)
end
save_extmarks(underline_ns, bufnr)
Expand Down
34 changes: 34 additions & 0 deletions test/functional/lua/diagnostic_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ describe('vim.diagnostic', function()
{ details = true }
)
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)

exec_lua(function()
Expand Down Expand Up @@ -1813,6 +1826,21 @@ describe('vim.diagnostic', function()
_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)
vim.diagnostic.config({
severity_sort = severity_sort,
Expand Down Expand Up @@ -1864,6 +1892,12 @@ describe('vim.diagnostic', function()
result = exec_lua [[return _G.get_virt_text_and_signs({ reverse = true })]]
eq({ 'Error', 'Warn', 'Info' }, result[1])
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)

it('can show diagnostic sources in virtual text', function()
Expand Down

0 comments on commit a9e725b

Please sign in to comment.