fix: proper multi-label-per-line overlap check + raise cap to |L|^2
Two changes folded into one commit since they were developed together: 1. Raise two-char label cap from 2*|L| to |L|^2. The cap was a conservative guess against visual density; the gap+overlap-skip logic makes density self-limiting regardless of pool size. Cost: all 26 letters land in prefixes[] in two-char mode, so single- char pattern extension doesn't work there. Acceptable since you're in two-char mode precisely because you want to jump, not extend further. 2. Fix: overlap check now compares a candidate label against ALL labels already placed on the same line, not just the most recent one. Previously line_end[line] tracked a single right edge, which assumed left-to-right commit order. With cursor-proximity sort, a right-of-cursor label can commit first and poison the tracker, wrongly rejecting a left-of-it match whose label wouldn't actually overlap. Now line_intervals[line] holds a list of [start, end) intervals and the candidate is tested against the whole list with a gap-aware interval-overlap check.
This commit is contained in:
1 file changed
+28
-14
+28
-14
@@ -116,7 +116,7 @@ function M.start()
|
||||
end)
|
||||
local L = M.config.labels
|
||||
local two = #matches > #L
|
||||
local line_end = {}
|
||||
local line_intervals = {}
|
||||
local li = 1
|
||||
for _, m in ipairs(matches) do
|
||||
vim.hl.range(
|
||||
@@ -129,7 +129,7 @@ function M.start()
|
||||
)
|
||||
local label
|
||||
if two then
|
||||
if li <= 2 * #L then
|
||||
if li <= #L * #L then
|
||||
local a = math.floor((li - 1) / #L) + 1
|
||||
local b = (li - 1) % #L + 1
|
||||
label = L:sub(a, a) .. L:sub(b, b)
|
||||
@@ -142,19 +142,33 @@ function M.start()
|
||||
label = L:sub(li, li)
|
||||
end
|
||||
end
|
||||
local prev = line_end[m.line]
|
||||
if label and (not prev or m.start_col >= prev) then
|
||||
if two then
|
||||
prefixes[label:sub(1, 1)] = true
|
||||
if label then
|
||||
local gap = two and 1 or 0
|
||||
local ivs = line_intervals[m.line] or {}
|
||||
local fits = true
|
||||
for _, iv in ipairs(ivs) do
|
||||
if
|
||||
m.start_col < iv[2] + gap
|
||||
and iv[1] < m.start_col + #label + gap
|
||||
then
|
||||
fits = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if fits then
|
||||
if two then
|
||||
prefixes[label:sub(1, 1)] = true
|
||||
end
|
||||
active[label] = { m.line + 1, m.start_col }
|
||||
api.nvim_buf_set_extmark(buf, NS, m.line, m.start_col, {
|
||||
virt_text = { { label, M.config.label } },
|
||||
virt_text_pos = 'overlay',
|
||||
priority = 201,
|
||||
})
|
||||
ivs[#ivs + 1] = { m.start_col, m.start_col + #label }
|
||||
line_intervals[m.line] = ivs
|
||||
li = li + 1
|
||||
end
|
||||
active[label] = { m.line + 1, m.start_col }
|
||||
api.nvim_buf_set_extmark(buf, NS, m.line, m.start_col, {
|
||||
virt_text = { { label, M.config.label } },
|
||||
virt_text_pos = 'overlay',
|
||||
priority = 201,
|
||||
})
|
||||
line_end[m.line] = m.start_col + #label + (two and 1 or 0)
|
||||
li = li + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in new issue
Block a user