feat(highlight): wire highlights.context into treesitter pipeline (#151)
Some checks are pending
luarocks / quality (push) Waiting to run
luarocks / publish (push) Blocked by required conditions

## Problem

`highlights.context.enabled` and `highlights.context.lines` were
defined, validated, and range-checked but never read during
highlighting. Hunks inside incomplete constructs (e.g., a table literal
or function body whose opening is beyond the hunk's own context lines)
parsed incorrectly because treesitter had no surrounding code.

## Solution

`compute_hunk_context` in `init.lua` reads the working tree file using
the hunk's `@@ +start,count @@` line numbers to collect up to `lines`
(default 25) surrounding code lines in each direction. Files are read
once via `io.open` and cached across hunks in the same file.
`highlight_treesitter` in `highlight.lua` accepts an optional context
parameter that prepends/appends context lines to the parse string and
offsets capture rows by the prefix count, so extmarks only land on
actual hunk lines. Wired through `highlight_hunk` for the two
code-language treesitter calls (not headers, not `highlight_text`, not
vim syntax).

Closes #148.
This commit is contained in:
Barrett Ruth 2026-03-05 11:14:31 -05:00 committed by GitHub
parent 29e624d9f0
commit e7d56e3bbe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 534 additions and 17 deletions

View file

@ -67,6 +67,10 @@ end
---@field defer_vim_syntax? boolean
---@field syntax_only? boolean
---@class diffs.TSContext
---@field before string[]?
---@field after string[]?
---@param bufnr integer
---@param ns integer
---@param code_lines string[]
@ -76,6 +80,7 @@ end
---@param covered_lines? table<integer, true>
---@param priorities diffs.PrioritiesConfig
---@param force_high_priority? boolean
---@param context? diffs.TSContext
---@return integer
local function highlight_treesitter(
bufnr,
@ -86,9 +91,34 @@ local function highlight_treesitter(
col_offset,
covered_lines,
priorities,
force_high_priority
force_high_priority,
context
)
local code = table.concat(code_lines, '\n')
local prefix_count = 0
local parse_lines = code_lines
if context then
local before = context.before
local after = context.after
if (before and #before > 0) or (after and #after > 0) then
parse_lines = {}
if before then
prefix_count = #before
for _, l in ipairs(before) do
parse_lines[#parse_lines + 1] = l
end
end
for _, l in ipairs(code_lines) do
parse_lines[#parse_lines + 1] = l
end
if after then
for _, l in ipairs(after) do
parse_lines[#parse_lines + 1] = l
end
end
end
end
local code = table.concat(parse_lines, '\n')
if code == '' then
return 0
end
@ -118,6 +148,8 @@ local function highlight_treesitter(
if capture ~= 'spell' and capture ~= 'nospell' then
local capture_name = '@' .. capture .. '.' .. tree_lang
local sr, sc, er, ec = node:range()
sr = sr - prefix_count
er = er - prefix_count
local buf_sr = line_map[sr]
if buf_sr then
@ -329,10 +361,36 @@ function M.highlight_hunk(bufnr, ns, hunk, opts)
end
end
extmark_count =
highlight_treesitter(bufnr, ns, new_code, hunk.lang, new_map, pw + qw, covered_lines, p)
local ts_context = nil
if opts.highlights.context.enabled and (hunk.context_before or hunk.context_after) then
ts_context = { before = hunk.context_before, after = hunk.context_after }
end
extmark_count = highlight_treesitter(
bufnr,
ns,
new_code,
hunk.lang,
new_map,
pw + qw,
covered_lines,
p,
nil,
ts_context
)
extmark_count = extmark_count
+ highlight_treesitter(bufnr, ns, old_code, hunk.lang, old_map, pw + qw, covered_lines, p)
+ highlight_treesitter(
bufnr,
ns,
old_code,
hunk.lang,
old_map,
pw + qw,
covered_lines,
p,
nil,
ts_context
)
if hunk.header_context and hunk.header_context_col then
local header_extmarks = highlight_text(