feat(highlight): add character-level intra-line diff highlighting
Line-level backgrounds (DiffsAdd/DiffsDelete) now get a second tier:
changed characters within modified lines receive an intense background
overlay (DiffsAddText/DiffsDeleteText at 70% alpha vs 40% for lines).
Treesitter foreground colors show through since the extmarks only set bg.
diff.lua extracts contiguous -/+ change groups from hunk lines and diffs
each group byte-by-byte using vim.diff(). An optional libvscodediff FFI
backend (lib.lua) auto-downloads the .so from codediff.nvim releases and
falls back to native if unavailable.
New config: highlights.intra.{enabled, algorithm, max_lines}. Gated by
max_lines (default 200) to avoid stalling on huge hunks. Priority 201
sits above treesitter (200) so the character bg always wins.
Closes #60
This commit is contained in:
parent
294cbad749
commit
997bc49f8b
7 changed files with 842 additions and 0 deletions
|
|
@ -1,6 +1,7 @@
|
|||
local M = {}
|
||||
|
||||
local dbg = require('diffs.log').dbg
|
||||
local diff = require('diffs.diff')
|
||||
|
||||
---@param bufnr integer
|
||||
---@param ns integer
|
||||
|
|
@ -282,6 +283,30 @@ function M.highlight_hunk(bufnr, ns, hunk, opts)
|
|||
|
||||
local syntax_applied = extmark_count > 0
|
||||
|
||||
---@type diffs.IntraChanges?
|
||||
local intra = nil
|
||||
local intra_cfg = opts.highlights.intra
|
||||
if intra_cfg and intra_cfg.enabled and #hunk.lines <= intra_cfg.max_lines then
|
||||
intra = diff.compute_intra_hunks(hunk.lines, intra_cfg.algorithm)
|
||||
end
|
||||
|
||||
---@type table<integer, diffs.CharSpan[]>
|
||||
local char_spans_by_line = {}
|
||||
if intra then
|
||||
for _, span in ipairs(intra.add_spans) do
|
||||
if not char_spans_by_line[span.line] then
|
||||
char_spans_by_line[span.line] = {}
|
||||
end
|
||||
table.insert(char_spans_by_line[span.line], span)
|
||||
end
|
||||
for _, span in ipairs(intra.del_spans) do
|
||||
if not char_spans_by_line[span.line] then
|
||||
char_spans_by_line[span.line] = {}
|
||||
end
|
||||
table.insert(char_spans_by_line[span.line], span)
|
||||
end
|
||||
end
|
||||
|
||||
for i, line in ipairs(hunk.lines) do
|
||||
local buf_line = hunk.start_line + i - 1
|
||||
local line_len = #line
|
||||
|
|
@ -317,6 +342,18 @@ function M.highlight_hunk(bufnr, ns, hunk, opts)
|
|||
priority = 199,
|
||||
})
|
||||
end
|
||||
|
||||
if char_spans_by_line[i] then
|
||||
local char_hl = prefix == '+' and 'DiffsAddText' or 'DiffsDeleteText'
|
||||
for _, span in ipairs(char_spans_by_line[i]) do
|
||||
pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, buf_line, span.col_start, {
|
||||
end_col = span.col_end,
|
||||
hl_group = char_hl,
|
||||
priority = 201,
|
||||
})
|
||||
extmark_count = extmark_count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
dbg('hunk %s:%d applied %d extmarks', hunk.filename, hunk.start_line, extmark_count)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue