From 2767eac320ef3f422236cbc8ce2228b02e11bd31 Mon Sep 17 00:00:00 2001 From: Grzegorz Rozdzialik Date: Mon, 17 Nov 2025 18:37:59 +0100 Subject: [PATCH] feat(diagnostics): stack DiagnosticUnnecessary,DiagnosticDeprecated highlights #36590 Problem: unnecessary and deprecated diagnostics use their own highlight groups (`DiagnosticUnnecessary` and `DiagnosticDeprecated`) which override the typical severity-based highlight groups (like `DiagnosticUnderlineWarn`). This can be misleading, since diagnostics about unused variables which are warnings or errors, are shown like comments, since then only the `DiagnosticUnnecessary` highlight group is used. Users do not see the more eye-catching red/yellow highlight. Solution: Instead of overriding the highlight group to `DiagnosticUnnecessary` or `DiagnosticDeprecated`, set them in addition to the normal severity-based highlights. --- runtime/lua/vim/diagnostic.lua | 25 +++++++++++---------- test/functional/lua/diagnostic_spec.lua | 29 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 031c99dd1b..9cc05b61a3 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -1734,29 +1734,30 @@ M.handlers.underline = { local get_priority = severity_to_extmark_priority(vim.hl.priorities.diagnostics, opts) for _, diagnostic in ipairs(diagnostics) do - local higroup = underline_highlight_map[diagnostic.severity] + local higroups = { underline_highlight_map[diagnostic.severity] } if diagnostic._tags then - -- TODO(lewis6991): we should be able to stack these. if diagnostic._tags.unnecessary then - higroup = 'DiagnosticUnnecessary' + table.insert(higroups, 'DiagnosticUnnecessary') end if diagnostic._tags.deprecated then - higroup = 'DiagnosticDeprecated' + table.insert(higroups, 'DiagnosticDeprecated') end end local lines = api.nvim_buf_get_lines(diagnostic.bufnr, diagnostic.lnum, diagnostic.lnum + 1, true) - vim.hl.range( - bufnr, - underline_ns, - higroup, - { diagnostic.lnum, math.min(diagnostic.col, #lines[1] - 1) }, - { diagnostic.end_lnum, diagnostic.end_col }, - { priority = get_priority(diagnostic.severity) } - ) + for _, higroup in ipairs(higroups) do + vim.hl.range( + bufnr, + underline_ns, + higroup, + { diagnostic.lnum, math.min(diagnostic.col, #lines[1] - 1) }, + { diagnostic.end_lnum, diagnostic.end_col }, + { priority = get_priority(diagnostic.severity) } + ) + end end save_extmarks(underline_ns, bufnr) end) diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index bf4cb02c4b..4a971ae515 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -2023,6 +2023,35 @@ describe('vim.diagnostic', function() eq('DiagnosticUnderlineInfo', underline_hl) end) + it( + 'shows deprecated and unnecessary highlights in addition to severity-based highlights', + function() + ---@type string[] + local result = exec_lua(function() + local diagnostic = _G.make_error('Some error', 0, 0, 0, 0, 'source x') + diagnostic._tags = { + deprecated = true, + unnecessary = true, + } + + local diagnostics = { diagnostic } + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics) + + local extmarks = _G.get_underline_extmarks(_G.diagnostic_ns) + local hl_groups = vim.tbl_map(function(extmark) + return extmark[4].hl_group + end, extmarks) + return hl_groups + end) + + eq({ + 'DiagnosticDeprecated', + 'DiagnosticUnnecessary', + 'DiagnosticUnderlineError', + }, result) + end + ) + it('can show diagnostic sources in virtual text', function() local result = exec_lua(function() local diagnostics = {