feat(highlight): warn when hunks exceed max_lines

Problem: when a hunk's highlighted lines exceed `max_lines`, syntax
highlighting is silently skipped. Users have no indication why parts
of their diff lack highlighting.

Solution: add `highlights.warn_max_lines` (default `true`) that emits
a `vim.notify` warning with the hunk index and line count vs threshold.
Also change `max_lines` to count only highlighted (`+`/`-`) lines
rather than total body lines including context.
This commit is contained in:
Barrett Ruth 2026-03-10 16:36:50 -04:00
parent c7cd8fc24c
commit 5199e72bd0
4 changed files with 74 additions and 22 deletions

View file

@ -26,6 +26,7 @@
---@field gutter boolean
---@field blend_alpha? number
---@field overrides? table<string, table>
---@field warn_max_lines boolean
---@field context diffs.ContextConfig
---@field treesitter diffs.TreesitterConfig
---@field vim diffs.VimConfig
@ -132,6 +133,7 @@ local default_config = {
highlights = {
background = true,
gutter = true,
warn_max_lines = true,
context = {
enabled = true,
lines = 25,
@ -203,6 +205,7 @@ local diff_windows = {}
---@field tick integer
---@field highlighted table<integer, true>
---@field pending_clear boolean
---@field warned_max_lines boolean
---@field line_count integer
---@field byte_count integer
@ -423,6 +426,7 @@ local function ensure_cache(bufnr)
tick = tick,
highlighted = carried or {},
pending_clear = not carried,
warned_max_lines = false,
line_count = lc,
byte_count = bc,
}
@ -703,6 +707,7 @@ local function init()
vim.validate('highlights.gutter', opts.highlights.gutter, 'boolean', true)
vim.validate('highlights.blend_alpha', opts.highlights.blend_alpha, 'number', true)
vim.validate('highlights.overrides', opts.highlights.overrides, 'table', true)
vim.validate('highlights.warn_max_lines', opts.highlights.warn_max_lines, 'boolean', true)
vim.validate('highlights.context', opts.highlights.context, 'table', true)
vim.validate('highlights.treesitter', opts.highlights.treesitter, 'table', true)
vim.validate('highlights.vim', opts.highlights.vim, 'table', true)
@ -890,6 +895,7 @@ local function init()
if entry and entry.pending_clear then
vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
entry.highlighted = {}
entry.warned_max_lines = {}
entry.pending_clear = false
end
if t0 then
@ -910,6 +916,7 @@ local function init()
end
local t0 = config.debug and vim.uv.hrtime() or nil
local deferred_syntax = {}
local skipped_warnings = {}
local count = 0
for i = first, last do
if not entry.highlighted[i] then
@ -926,10 +933,30 @@ local function init()
local has_syntax = hunk.lang and config.highlights.treesitter.enabled
local needs_vim = not hunk.lang and hunk.ft and config.highlights.vim.enabled
if has_syntax or needs_vim then
local max_lines = has_syntax and config.highlights.treesitter.max_lines
or config.highlights.vim.max_lines
local hl_count = hunk._hl_line_count or #hunk.lines
if hl_count > max_lines then
table.insert(skipped_warnings, { idx = i, hl_count = hl_count, max_lines = max_lines })
end
table.insert(deferred_syntax, hunk)
end
end
end
if not entry.warned_max_lines and #skipped_warnings > 0 and config.highlights.warn_max_lines then
entry.warned_max_lines = true
vim.schedule(function()
for _, info in ipairs(skipped_warnings) do
vim.notify(
('[diffs.nvim]: skipping hunk %d - too many lines (%d > %d).'
.. ' increase `vim.g.diffs.highlights.{vim,treesitter}.max_lines`'
.. ' or set `vim.g.diffs.highlights.warn_max_lines = false`'
.. ' to disable this warning'):format(info.idx, info.hl_count, info.max_lines),
vim.log.levels.WARN
)
end
end)
end
if #deferred_syntax > 0 then
local tick = entry.tick
dbg('deferred syntax scheduled: %d hunks tick=%d', #deferred_syntax, tick)
@ -1108,6 +1135,7 @@ local function process_pending_clear(bufnr)
if entry and entry.pending_clear then
vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
entry.highlighted = {}
entry.warned_max_lines = {}
entry.pending_clear = false
end
end