From 25170ca02d94087793613b10bea30237ace6737e Mon Sep 17 00:00:00 2001 From: glepnir Date: Tue, 7 Apr 2026 01:22:39 +0800 Subject: [PATCH] fix(diagnostic): virtual_lines should anchor at end_lnum, not lnum #38701 Problem: Multi-line diagnostics always render virtual lines below lnum. Solution: Use end_lnum when placing the virt_lines extmark. (cherry picked from commit af707dd24261f34a72ba7bbea5cf2e802f81837d) --- runtime/lua/vim/diagnostic.lua | 7 ++++++- test/functional/lua/diagnostic_spec.lua | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index e2f712bb62..81e25e57ed 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -2018,6 +2018,7 @@ local function render_virtual_lines(namespace, bufnr, diagnostics) local ElementType = { Space = 1, Diagnostic = 2, Overlap = 3, Blank = 4 } ---@enum ElementType ---@type table local line_stacks = {} + local line_anchor = {} ---@type table local prev_lnum = -1 local prev_col = 0 for _, diag in ipairs(diagnostics) do @@ -2026,6 +2027,10 @@ local function render_virtual_lines(namespace, bufnr, diagnostics) end local stack = line_stacks[diag.lnum] + local end_lnum = diag.end_lnum or diag.lnum + if not line_anchor[diag.lnum] or end_lnum > line_anchor[diag.lnum] then + line_anchor[diag.lnum] = end_lnum + end if diag.lnum ~= prev_lnum then table.insert(stack, { @@ -2152,7 +2157,7 @@ local function render_virtual_lines(namespace, bufnr, diagnostics) end end - api.nvim_buf_set_extmark(bufnr, namespace, lnum, 0, { + api.nvim_buf_set_extmark(bufnr, namespace, line_anchor[lnum] or lnum, 0, { virt_lines_overflow = 'scroll', virt_lines = virt_lines, }) diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index ee0292d6a2..515e25c8c1 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -2395,13 +2395,13 @@ describe('vim.diagnostic', function() eq(error_offset, result[1][1][1]:len()) end) - it('highlights diagnostics in multiple lines by default', function() + it('highlights diagnostics in multiple lines by default #38685', function() local result = exec_lua(function() vim.diagnostic.config({ virtual_lines = true }) vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { _G.make_error('Error here!', 0, 0, 0, 0, 'foo_server'), - _G.make_error('Another error there!', 1, 0, 1, 0, 'foo_server'), + _G.make_error('Another error there!', 1, 0, 3, 0, 'foo_server'), }) local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns) @@ -2411,6 +2411,8 @@ describe('vim.diagnostic', function() eq(2, #result) eq('Error here!', result[1][4].virt_lines[1][3][1]) eq('Another error there!', result[2][4].virt_lines[1][3][1]) + eq(0, result[1][2]) + eq(3, result[2][2]) end) it('highlights multiple diagnostics in a single line by default', function()