feat(highlight): warn when hunks exceed max_lines (#184)
This commit is contained in:
parent
600d3757f2
commit
de04381298
5 changed files with 99 additions and 22 deletions
|
|
@ -93,6 +93,7 @@ Configuration is done via `vim.g.diffs`. Set this before the plugin loads:
|
||||||
background = true,
|
background = true,
|
||||||
gutter = true,
|
gutter = true,
|
||||||
blend_alpha = 0.6,
|
blend_alpha = 0.6,
|
||||||
|
warn_max_lines = true,
|
||||||
context = {
|
context = {
|
||||||
enabled = true,
|
enabled = true,
|
||||||
lines = 25,
|
lines = 25,
|
||||||
|
|
@ -249,6 +250,11 @@ Configuration is done via `vim.g.diffs`. Set this before the plugin loads:
|
||||||
(inclusive). Higher values produce more vivid
|
(inclusive). Higher values produce more vivid
|
||||||
backgrounds.
|
backgrounds.
|
||||||
|
|
||||||
|
{warn_max_lines} (boolean, default: true)
|
||||||
|
Show a |vim.notify()| warning when syntax
|
||||||
|
highlighting is skipped because a hunk exceeds
|
||||||
|
{max_lines}. See |diffs-max-lines|.
|
||||||
|
|
||||||
{context} (table, default: see below)
|
{context} (table, default: see below)
|
||||||
Syntax parsing context options.
|
Syntax parsing context options.
|
||||||
See |diffs.ContextConfig| for fields.
|
See |diffs.ContextConfig| for fields.
|
||||||
|
|
@ -322,8 +328,10 @@ Configuration is done via `vim.g.diffs`. Set this before the plugin loads:
|
||||||
Apply treesitter syntax highlighting to code.
|
Apply treesitter syntax highlighting to code.
|
||||||
|
|
||||||
{max_lines} (integer, default: 500)
|
{max_lines} (integer, default: 500)
|
||||||
Skip treesitter highlighting for hunks larger than
|
Skip treesitter highlighting for hunks with more
|
||||||
this many lines. Prevents lag on massive diffs.
|
highlighted lines (`+`/`-`) than this threshold.
|
||||||
|
Context lines are not counted. Prevents lag on
|
||||||
|
massive diffs.
|
||||||
|
|
||||||
*diffs.VimConfig*
|
*diffs.VimConfig*
|
||||||
Vim config fields: ~
|
Vim config fields: ~
|
||||||
|
|
@ -338,9 +346,11 @@ Configuration is done via `vim.g.diffs`. Set this before the plugin loads:
|
||||||
parser installed (e.g., COBOL, Fortran).
|
parser installed (e.g., COBOL, Fortran).
|
||||||
|
|
||||||
{max_lines} (integer, default: 200)
|
{max_lines} (integer, default: 200)
|
||||||
Skip vim syntax highlighting for hunks larger than
|
Skip vim syntax highlighting for hunks with more
|
||||||
this many lines. Lower than the treesitter default
|
highlighted lines (`+`/`-`) than this threshold.
|
||||||
due to the per-character cost of |synID()|.
|
Context lines are not counted. Lower than the
|
||||||
|
treesitter default due to the per-character cost
|
||||||
|
of |synID()|.
|
||||||
|
|
||||||
*diffs.IntraConfig*
|
*diffs.IntraConfig*
|
||||||
Intra config fields: ~
|
Intra config fields: ~
|
||||||
|
|
@ -359,8 +369,9 @@ Configuration is done via `vim.g.diffs`. Set this before the plugin loads:
|
||||||
(falls back to default if not available).
|
(falls back to default if not available).
|
||||||
|
|
||||||
{max_lines} (integer, default: 500)
|
{max_lines} (integer, default: 500)
|
||||||
Skip character-level highlighting for hunks larger
|
Skip character-level highlighting for hunks with
|
||||||
than this many lines.
|
more highlighted lines (`+`/`-`) than this
|
||||||
|
threshold. Context lines are not counted.
|
||||||
|
|
||||||
Note: Header context (e.g., `@@ -10,3 +10,4 @@ func()`) is always
|
Note: Header context (e.g., `@@ -10,3 +10,4 @@ func()`) is always
|
||||||
highlighted with treesitter when a parser is available.
|
highlighted with treesitter when a parser is available.
|
||||||
|
|
@ -370,6 +381,33 @@ Configuration is done via `vim.g.diffs`. Set this before the plugin loads:
|
||||||
or register treesitter parsers for custom filetypes, use
|
or register treesitter parsers for custom filetypes, use
|
||||||
|vim.filetype.add()| and |vim.treesitter.language.register()|.
|
|vim.filetype.add()| and |vim.treesitter.language.register()|.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
MAX LINES *diffs-max-lines*
|
||||||
|
|
||||||
|
When a hunk contains more highlighted lines (`+`/`-`) than the configured
|
||||||
|
threshold, diffs.nvim skips syntax highlighting for that hunk to avoid lag.
|
||||||
|
Context lines (lines with a space prefix) are not counted toward the limit.
|
||||||
|
|
||||||
|
A warning is shown when this happens: >
|
||||||
|
[diffs.nvim]: Syntax highlighting skipped for 1 hunk(s) — too large.
|
||||||
|
<
|
||||||
|
To increase the threshold: >lua
|
||||||
|
vim.g.diffs = {
|
||||||
|
highlights = {
|
||||||
|
treesitter = { max_lines = 1000 }, -- default: 500
|
||||||
|
vim = { max_lines = 500 }, -- default: 200
|
||||||
|
},
|
||||||
|
}
|
||||||
|
<
|
||||||
|
To suppress the warning without changing the threshold: >lua
|
||||||
|
vim.g.diffs = {
|
||||||
|
highlights = { warn_max_lines = false },
|
||||||
|
}
|
||||||
|
<
|
||||||
|
The `intra.max_lines` threshold (default: 500) is separate and controls
|
||||||
|
character-level diff highlighting within changed lines. It does not affect
|
||||||
|
the syntax highlighting warning.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
COMMANDS *diffs-commands*
|
COMMANDS *diffs-commands*
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -310,16 +310,27 @@ function M.highlight_hunk(bufnr, ns, hunk, opts)
|
||||||
local use_vim = not use_ts and hunk.ft and opts.highlights.vim.enabled
|
local use_vim = not use_ts and hunk.ft and opts.highlights.vim.enabled
|
||||||
|
|
||||||
local max_lines = use_ts and opts.highlights.treesitter.max_lines or opts.highlights.vim.max_lines
|
local max_lines = use_ts and opts.highlights.treesitter.max_lines or opts.highlights.vim.max_lines
|
||||||
if (use_ts or use_vim) and #hunk.lines > max_lines then
|
if use_ts or use_vim then
|
||||||
dbg(
|
local hl_count = 0
|
||||||
'skipping hunk %s:%d (%d lines > %d max)',
|
for _, line in ipairs(hunk.lines) do
|
||||||
hunk.filename,
|
local c = line:sub(1, 1)
|
||||||
hunk.start_line,
|
if c == '+' or c == '-' then
|
||||||
#hunk.lines,
|
hl_count = hl_count + 1
|
||||||
max_lines
|
end
|
||||||
)
|
end
|
||||||
use_ts = false
|
hunk._hl_line_count = hl_count
|
||||||
use_vim = false
|
if hl_count > max_lines then
|
||||||
|
dbg(
|
||||||
|
'skipping hunk %s:%d (%d highlighted lines > %d max)',
|
||||||
|
hunk.filename,
|
||||||
|
hunk.start_line,
|
||||||
|
hl_count,
|
||||||
|
max_lines
|
||||||
|
)
|
||||||
|
hunk._skipped_max_lines = true
|
||||||
|
use_ts = false
|
||||||
|
use_vim = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if use_vim and opts.defer_vim_syntax then
|
if use_vim and opts.defer_vim_syntax then
|
||||||
|
|
@ -456,7 +467,7 @@ function M.highlight_hunk(bufnr, ns, hunk, opts)
|
||||||
and intra_cfg
|
and intra_cfg
|
||||||
and intra_cfg.enabled
|
and intra_cfg.enabled
|
||||||
and pw == 1
|
and pw == 1
|
||||||
and #hunk.lines <= intra_cfg.max_lines
|
and (hunk._hl_line_count or #hunk.lines) <= intra_cfg.max_lines
|
||||||
then
|
then
|
||||||
dbg('computing intra for hunk %s:%d (%d lines)', hunk.filename, hunk.start_line, #hunk.lines)
|
dbg('computing intra for hunk %s:%d (%d lines)', hunk.filename, hunk.start_line, #hunk.lines)
|
||||||
intra = diff.compute_intra_hunks(hunk.lines, intra_cfg.algorithm)
|
intra = diff.compute_intra_hunks(hunk.lines, intra_cfg.algorithm)
|
||||||
|
|
@ -467,8 +478,12 @@ function M.highlight_hunk(bufnr, ns, hunk, opts)
|
||||||
end
|
end
|
||||||
elseif intra_cfg and not intra_cfg.enabled then
|
elseif intra_cfg and not intra_cfg.enabled then
|
||||||
dbg('intra disabled by config')
|
dbg('intra disabled by config')
|
||||||
elseif intra_cfg and #hunk.lines > intra_cfg.max_lines then
|
elseif intra_cfg and (hunk._hl_line_count or #hunk.lines) > intra_cfg.max_lines then
|
||||||
dbg('intra skipped: %d lines > %d max', #hunk.lines, intra_cfg.max_lines)
|
dbg(
|
||||||
|
'intra skipped: %d highlighted lines > %d max',
|
||||||
|
hunk._hl_line_count or #hunk.lines,
|
||||||
|
intra_cfg.max_lines
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@type table<integer, diffs.CharSpan[]>
|
---@type table<integer, diffs.CharSpan[]>
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
---@field gutter boolean
|
---@field gutter boolean
|
||||||
---@field blend_alpha? number
|
---@field blend_alpha? number
|
||||||
---@field overrides? table<string, table>
|
---@field overrides? table<string, table>
|
||||||
|
---@field warn_max_lines boolean
|
||||||
---@field context diffs.ContextConfig
|
---@field context diffs.ContextConfig
|
||||||
---@field treesitter diffs.TreesitterConfig
|
---@field treesitter diffs.TreesitterConfig
|
||||||
---@field vim diffs.VimConfig
|
---@field vim diffs.VimConfig
|
||||||
|
|
@ -132,6 +133,7 @@ local default_config = {
|
||||||
highlights = {
|
highlights = {
|
||||||
background = true,
|
background = true,
|
||||||
gutter = true,
|
gutter = true,
|
||||||
|
warn_max_lines = true,
|
||||||
context = {
|
context = {
|
||||||
enabled = true,
|
enabled = true,
|
||||||
lines = 25,
|
lines = 25,
|
||||||
|
|
@ -203,6 +205,7 @@ local diff_windows = {}
|
||||||
---@field tick integer
|
---@field tick integer
|
||||||
---@field highlighted table<integer, true>
|
---@field highlighted table<integer, true>
|
||||||
---@field pending_clear boolean
|
---@field pending_clear boolean
|
||||||
|
---@field warned_max_lines boolean
|
||||||
---@field line_count integer
|
---@field line_count integer
|
||||||
---@field byte_count integer
|
---@field byte_count integer
|
||||||
|
|
||||||
|
|
@ -423,6 +426,7 @@ local function ensure_cache(bufnr)
|
||||||
tick = tick,
|
tick = tick,
|
||||||
highlighted = carried or {},
|
highlighted = carried or {},
|
||||||
pending_clear = not carried,
|
pending_clear = not carried,
|
||||||
|
warned_max_lines = false,
|
||||||
line_count = lc,
|
line_count = lc,
|
||||||
byte_count = bc,
|
byte_count = bc,
|
||||||
}
|
}
|
||||||
|
|
@ -703,6 +707,7 @@ local function init()
|
||||||
vim.validate('highlights.gutter', opts.highlights.gutter, 'boolean', true)
|
vim.validate('highlights.gutter', opts.highlights.gutter, 'boolean', true)
|
||||||
vim.validate('highlights.blend_alpha', opts.highlights.blend_alpha, 'number', true)
|
vim.validate('highlights.blend_alpha', opts.highlights.blend_alpha, 'number', true)
|
||||||
vim.validate('highlights.overrides', opts.highlights.overrides, 'table', 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.context', opts.highlights.context, 'table', true)
|
||||||
vim.validate('highlights.treesitter', opts.highlights.treesitter, 'table', true)
|
vim.validate('highlights.treesitter', opts.highlights.treesitter, 'table', true)
|
||||||
vim.validate('highlights.vim', opts.highlights.vim, 'table', true)
|
vim.validate('highlights.vim', opts.highlights.vim, 'table', true)
|
||||||
|
|
@ -910,6 +915,7 @@ local function init()
|
||||||
end
|
end
|
||||||
local t0 = config.debug and vim.uv.hrtime() or nil
|
local t0 = config.debug and vim.uv.hrtime() or nil
|
||||||
local deferred_syntax = {}
|
local deferred_syntax = {}
|
||||||
|
local skipped_count = 0
|
||||||
local count = 0
|
local count = 0
|
||||||
for i = first, last do
|
for i = first, last do
|
||||||
if not entry.highlighted[i] then
|
if not entry.highlighted[i] then
|
||||||
|
|
@ -923,6 +929,9 @@ local function init()
|
||||||
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
|
||||||
|
if hunk._skipped_max_lines then
|
||||||
|
skipped_count = skipped_count + 1
|
||||||
|
end
|
||||||
local has_syntax = hunk.lang and config.highlights.treesitter.enabled
|
local has_syntax = hunk.lang and config.highlights.treesitter.enabled
|
||||||
local needs_vim = not hunk.lang and hunk.ft and config.highlights.vim.enabled
|
local needs_vim = not hunk.lang and hunk.ft and config.highlights.vim.enabled
|
||||||
if has_syntax or needs_vim then
|
if has_syntax or needs_vim then
|
||||||
|
|
@ -930,6 +939,19 @@ local function init()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if skipped_count > 0 and not entry.warned_max_lines and config.highlights.warn_max_lines then
|
||||||
|
entry.warned_max_lines = true
|
||||||
|
local n = skipped_count
|
||||||
|
vim.schedule(function()
|
||||||
|
vim.notify(
|
||||||
|
(
|
||||||
|
'[diffs.nvim]: Syntax highlighting skipped for %d hunk(s) — too large.'
|
||||||
|
.. ' See :h diffs-max-lines to resolve or suppress this warning.'
|
||||||
|
):format(n),
|
||||||
|
vim.log.levels.WARN
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
end
|
||||||
if #deferred_syntax > 0 then
|
if #deferred_syntax > 0 then
|
||||||
local tick = entry.tick
|
local tick = entry.tick
|
||||||
dbg('deferred syntax scheduled: %d hunks tick=%d', #deferred_syntax, tick)
|
dbg('deferred syntax scheduled: %d hunks tick=%d', #deferred_syntax, tick)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
---@field repo_root string?
|
---@field repo_root string?
|
||||||
---@field context_before string[]?
|
---@field context_before string[]?
|
||||||
---@field context_after string[]?
|
---@field context_after string[]?
|
||||||
|
---@field _hl_line_count integer?
|
||||||
|
---@field _skipped_max_lines boolean?
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,8 +135,8 @@ describe('highlight', function()
|
||||||
local lines = { '@@ -1,100 +1,101 @@' }
|
local lines = { '@@ -1,100 +1,101 @@' }
|
||||||
local hunk_lines = {}
|
local hunk_lines = {}
|
||||||
for i = 1, 600 do
|
for i = 1, 600 do
|
||||||
table.insert(lines, ' line ' .. i)
|
table.insert(lines, '+line ' .. i)
|
||||||
table.insert(hunk_lines, ' line ' .. i)
|
table.insert(hunk_lines, '+line ' .. i)
|
||||||
end
|
end
|
||||||
|
|
||||||
local bufnr = create_buffer(lines)
|
local bufnr = create_buffer(lines)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue