fix(highlight): use multiline extmark for hl_eol with start-position clearing
Problem: single-row extmarks (`end_row = buf_line, end_col = len`) do not trigger `hl_eol` — Neovim requires `end_row > start_row`. Line backgrounds stopped at the last character instead of extending to the window edge. Solution: use `end_row = buf_line + 1, end_col = 0` for line bg extmarks. Replace per-hunk `nvim_buf_clear_namespace` with `clear_ns_by_start` that queries extmarks by start position only, so adjacent hunks' trailing `end_row` is never killed.
This commit is contained in:
parent
eccb4785ed
commit
803e08b6d5
3 changed files with 65 additions and 6 deletions
|
|
@ -636,10 +636,9 @@ function M.highlight_hunk(bufnr, ns, hunk, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
if opts.highlights.background and is_diff_line then
|
if opts.highlights.background and is_diff_line then
|
||||||
local bg_end_col = raw_len or (line_len + qw)
|
|
||||||
pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, buf_line, 0, {
|
pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, buf_line, 0, {
|
||||||
end_row = buf_line,
|
end_row = buf_line + 1,
|
||||||
end_col = bg_end_col,
|
end_col = 0,
|
||||||
hl_group = line_hl,
|
hl_group = line_hl,
|
||||||
hl_eol = true,
|
hl_eol = true,
|
||||||
priority = p.line_bg,
|
priority = p.line_bg,
|
||||||
|
|
|
||||||
|
|
@ -437,7 +437,10 @@ local function ensure_cache(bufnr)
|
||||||
if config.highlights.context.enabled then
|
if config.highlights.context.enabled then
|
||||||
compute_hunk_context(hunks, config.highlights.context.lines)
|
compute_hunk_context(hunks, config.highlights.context.lines)
|
||||||
end
|
end
|
||||||
local carried = entry and not entry.pending_clear and carry_forward_highlighted(entry, hunks)
|
local carried = entry
|
||||||
|
and not entry.pending_clear
|
||||||
|
and #entry.hunks == #hunks
|
||||||
|
and carry_forward_highlighted(entry, hunks)
|
||||||
hunk_cache[bufnr] = {
|
hunk_cache[bufnr] = {
|
||||||
hunks = hunks,
|
hunks = hunks,
|
||||||
tick = tick,
|
tick = tick,
|
||||||
|
|
@ -514,6 +517,18 @@ local function find_visible_hunks(hunks, toprow, botrow)
|
||||||
return first, last
|
return first, last
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param bufnr integer
|
||||||
|
---@param ns_id integer
|
||||||
|
---@param start_row integer
|
||||||
|
---@param end_row integer
|
||||||
|
local function clear_ns_by_start(bufnr, ns_id, start_row, end_row)
|
||||||
|
local marks =
|
||||||
|
vim.api.nvim_buf_get_extmarks(bufnr, ns_id, { start_row, 0 }, { end_row - 1, 2147483647 }, {})
|
||||||
|
for _, m in ipairs(marks) do
|
||||||
|
vim.api.nvim_buf_del_extmark(bufnr, ns_id, m[1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function compute_highlight_groups(is_default)
|
local function compute_highlight_groups(is_default)
|
||||||
local normal = vim.api.nvim_get_hl(0, { name = 'Normal' })
|
local normal = vim.api.nvim_get_hl(0, { name = 'Normal' })
|
||||||
local diff_add = vim.api.nvim_get_hl(0, { name = 'DiffAdd' })
|
local diff_add = vim.api.nvim_get_hl(0, { name = 'DiffAdd' })
|
||||||
|
|
@ -945,7 +960,7 @@ local function init()
|
||||||
if hunk.header_start_line then
|
if hunk.header_start_line then
|
||||||
clear_start = hunk.header_start_line - 1
|
clear_start = hunk.header_start_line - 1
|
||||||
end
|
end
|
||||||
vim.api.nvim_buf_clear_namespace(bufnr, ns, clear_start, clear_end)
|
clear_ns_by_start(bufnr, ns, clear_start, clear_end)
|
||||||
highlight.highlight_hunk(bufnr, ns, hunk, fast_hl_opts)
|
highlight.highlight_hunk(bufnr, ns, hunk, fast_hl_opts)
|
||||||
entry.highlighted[i] = true
|
entry.highlighted[i] = true
|
||||||
count = count + 1
|
count = count + 1
|
||||||
|
|
@ -1185,6 +1200,7 @@ M._test = {
|
||||||
invalidate_cache = invalidate_cache,
|
invalidate_cache = invalidate_cache,
|
||||||
hunks_eq = hunks_eq,
|
hunks_eq = hunks_eq,
|
||||||
process_pending_clear = process_pending_clear,
|
process_pending_clear = process_pending_clear,
|
||||||
|
clear_ns_by_start = clear_ns_by_start,
|
||||||
ft_retry_pending = ft_retry_pending,
|
ft_retry_pending = ft_retry_pending,
|
||||||
compute_hunk_context = compute_hunk_context,
|
compute_hunk_context = compute_hunk_context,
|
||||||
compute_highlight_groups = compute_highlight_groups,
|
compute_highlight_groups = compute_highlight_groups,
|
||||||
|
|
|
||||||
|
|
@ -397,7 +397,7 @@ describe('highlight', function()
|
||||||
delete_buffer(bufnr)
|
delete_buffer(bufnr)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('line bg extmark survives adjacent clear_namespace starting at next row', function()
|
it('nvim_buf_clear_namespace kills line bg extmark whose end_row bleeds into cleared range', function()
|
||||||
local bufnr = create_buffer({
|
local bufnr = create_buffer({
|
||||||
'diff --git a/foo.py b/foo.py',
|
'diff --git a/foo.py b/foo.py',
|
||||||
'@@ -1,2 +1,2 @@',
|
'@@ -1,2 +1,2 @@',
|
||||||
|
|
@ -423,6 +423,50 @@ describe('highlight', function()
|
||||||
local last_body_row = hunk.start_line + #hunk.lines - 1
|
local last_body_row = hunk.start_line + #hunk.lines - 1
|
||||||
vim.api.nvim_buf_clear_namespace(bufnr, ns, last_body_row + 1, last_body_row + 10)
|
vim.api.nvim_buf_clear_namespace(bufnr, ns, last_body_row + 1, last_body_row + 10)
|
||||||
|
|
||||||
|
local marks = vim.api.nvim_buf_get_extmarks(
|
||||||
|
bufnr,
|
||||||
|
ns,
|
||||||
|
{ last_body_row, 0 },
|
||||||
|
{ last_body_row, -1 },
|
||||||
|
{ details = true }
|
||||||
|
)
|
||||||
|
local has_line_bg = false
|
||||||
|
for _, mark in ipairs(marks) do
|
||||||
|
if mark[4] and mark[4].hl_group == 'DiffsAdd' then
|
||||||
|
has_line_bg = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert.is_false(has_line_bg)
|
||||||
|
delete_buffer(bufnr)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('clear_ns_by_start preserves line bg extmark whose end_row bleeds past cleared range', function()
|
||||||
|
local bufnr = create_buffer({
|
||||||
|
'diff --git a/foo.py b/foo.py',
|
||||||
|
'@@ -1,2 +1,2 @@',
|
||||||
|
'-old',
|
||||||
|
'+new',
|
||||||
|
})
|
||||||
|
|
||||||
|
local hunk = {
|
||||||
|
filename = 'foo.py',
|
||||||
|
header_start_line = 1,
|
||||||
|
start_line = 2,
|
||||||
|
lines = { '-old', '+new' },
|
||||||
|
prefix_width = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
highlight.highlight_hunk(
|
||||||
|
bufnr,
|
||||||
|
ns,
|
||||||
|
hunk,
|
||||||
|
default_opts({ highlights = { background = true, treesitter = { enabled = false } } })
|
||||||
|
)
|
||||||
|
|
||||||
|
local last_body_row = hunk.start_line + #hunk.lines - 1
|
||||||
|
local clear_ns_by_start = require('diffs')._test.clear_ns_by_start
|
||||||
|
clear_ns_by_start(bufnr, ns, last_body_row + 1, last_body_row + 10)
|
||||||
|
|
||||||
local marks = vim.api.nvim_buf_get_extmarks(
|
local marks = vim.api.nvim_buf_get_extmarks(
|
||||||
bufnr,
|
bufnr,
|
||||||
ns,
|
ns,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue