fix(diagnostic): skip out-of-range lnum in underline handler #40839

Problem:
`vim.diagnostic.handlers.underline.show` throws `E565: Index out of bounds` when
it tries to underline a diagnostic whose `lnum` is past the end of the buffer.
This happens with stale diagnostics set on an unloaded buffer (e.g. via
`bufadd()`) that are drawn only after the buffer is loaded: by then the file on
disk can be shorter than the `lnum` the diagnostic carried. File pickers
(snacks.nvim) that open files via `bufadd` + `:buffer` hit this whenever an LSP
server has already emitted diagnostics for that URI.


Solution:
Skip diagnostics with an out-of-range `lnum` in the underline handler.

Other handlers `M.virtual_text.show()`, `M.signs.show()`, have a similar condition.
This commit is contained in:
penglei
2026-07-20 18:59:21 +08:00
committed by GitHub
parent 09a4cc8c50
commit 84fd9214cc

View File

@@ -265,29 +265,34 @@ function M.underline.show(namespace, bufnr, diagnostics, opts)
local underline_ns = ns.user_data.underline_ns
local get_priority = severity_to_extmark_priority(vim.hl.priorities.diagnostics, opts)
-- skip diagnostics with an out-of-range lnum.
local line_count = api.nvim_buf_line_count(bufnr)
for _, diagnostic0 in ipairs(diagnostics) do
local higroups = { underline_highlight_map[diagnostic0.severity] }
if diagnostic0.lnum < line_count then
local higroups = { underline_highlight_map[diagnostic0.severity] }
if diagnostic0._tags then
if diagnostic0._tags.unnecessary then
table.insert(higroups, 'DiagnosticUnnecessary')
end
if diagnostic0._tags.deprecated then
table.insert(higroups, 'DiagnosticDeprecated')
if diagnostic0._tags then
if diagnostic0._tags.unnecessary then
table.insert(higroups, 'DiagnosticUnnecessary')
end
if diagnostic0._tags.deprecated then
table.insert(higroups, 'DiagnosticDeprecated')
end
end
local lines =
api.nvim_buf_get_lines(diagnostic0.bufnr, diagnostic0.lnum, diagnostic0.lnum + 1, true)
vim.hl.range(
bufnr,
underline_ns,
higroups,
{ diagnostic0.lnum, math.min(diagnostic0.col, #lines[1] - 1) },
{ diagnostic0.end_lnum, diagnostic0.end_col },
{ priority = get_priority(diagnostic0.severity) }
)
end
local lines =
api.nvim_buf_get_lines(diagnostic0.bufnr, diagnostic0.lnum, diagnostic0.lnum + 1, true)
vim.hl.range(
bufnr,
underline_ns,
higroups,
{ diagnostic0.lnum, math.min(diagnostic0.col, #lines[1] - 1) },
{ diagnostic0.end_lnum, diagnostic0.end_col },
{ priority = get_priority(diagnostic0.severity) }
)
end
save_extmarks(underline_ns, bufnr)