feat: two-char jump labels for overflow matches
When there are more matches than the single-char label pool (>|L|, i.e. > 26 with the default), issue two-char labels so matches past the single-char ceiling are still reachable. Tactics: - Cap: 2 * |L| = 52 labels total in two-char mode. The full |L|^2 = 676 space produces visually unusable density on packed buffers; 52 is plenty once the cursor-proximity sort lands them near the cursor. - Label order: first char varies slow (26 labels starting with 'f', next 26 starting with 'j') so only 'f' and 'j' become prefixes. The remaining 24 letters stay usable for pattern extension in two-char mode. - Per-line readability spacing: a 2-char label requires one column of original text between itself and the previous 2-char label on the same line. Prevents visual bleed when matches are adjacent (e.g. '0' search on timestamp-heavy text). Single-char mode unchanged. - No global mode flag: a 'prefixes' set, populated while assigning labels, tells the input loop when to buffer a second keystroke. The set resets each iteration with 'active'.
This commit is contained in:
1 file changed
+29
-9
+29
-9
@@ -67,11 +67,14 @@ function M.start()
|
|||||||
local info = fn.getwininfo(win)[1]
|
local info = fn.getwininfo(win)[1]
|
||||||
local top = info.topline
|
local top = info.topline
|
||||||
local lines = api.nvim_buf_get_lines(buf, top - 1, info.botline, true)
|
local lines = api.nvim_buf_get_lines(buf, top - 1, info.botline, true)
|
||||||
local chars, active = '', {}
|
local chars, active, prefixes = '', {}, {}
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
api.nvim_echo({ { '/' .. chars, '' } }, false, {})
|
api.nvim_echo({ { '/' .. chars, '' } }, false, {})
|
||||||
local ch = fn.getcharstr(-1)
|
local ch = fn.getcharstr(-1)
|
||||||
|
if prefixes[ch] then
|
||||||
|
ch = ch .. fn.getcharstr(-1)
|
||||||
|
end
|
||||||
local jump_to = active[ch]
|
local jump_to = active[ch]
|
||||||
|
|
||||||
if ch == K.ESC then
|
if ch == K.ESC then
|
||||||
@@ -97,7 +100,7 @@ function M.start()
|
|||||||
chars = chars .. ch
|
chars = chars .. ch
|
||||||
end
|
end
|
||||||
|
|
||||||
active = {}
|
active, prefixes = {}, {}
|
||||||
api.nvim_buf_clear_namespace(buf, NS, 0, -1)
|
api.nvim_buf_clear_namespace(buf, NS, 0, -1)
|
||||||
|
|
||||||
if #chars > 0 then
|
if #chars > 0 then
|
||||||
@@ -111,6 +114,9 @@ function M.start()
|
|||||||
end
|
end
|
||||||
return math.abs(a.start_col - cc) < math.abs(b.start_col - cc)
|
return math.abs(a.start_col - cc) < math.abs(b.start_col - cc)
|
||||||
end)
|
end)
|
||||||
|
local L = M.config.labels
|
||||||
|
local two = #matches > #L
|
||||||
|
local line_end = {}
|
||||||
local li = 1
|
local li = 1
|
||||||
for _, m in ipairs(matches) do
|
for _, m in ipairs(matches) do
|
||||||
vim.hl.range(
|
vim.hl.range(
|
||||||
@@ -121,20 +127,34 @@ function M.start()
|
|||||||
{ m.line, m.end_col },
|
{ m.line, m.end_col },
|
||||||
{ priority = 200 }
|
{ priority = 200 }
|
||||||
)
|
)
|
||||||
while
|
local label
|
||||||
li <= #M.config.labels and not avail[M.config.labels:sub(li, li)]
|
if two then
|
||||||
do
|
if li <= 2 * #L then
|
||||||
li = li + 1
|
local a = math.floor((li - 1) / #L) + 1
|
||||||
|
local b = (li - 1) % #L + 1
|
||||||
|
label = L:sub(a, a) .. L:sub(b, b)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
while li <= #L and not avail[L:sub(li, li)] do
|
||||||
|
li = li + 1
|
||||||
|
end
|
||||||
|
if li <= #L then
|
||||||
|
label = L:sub(li, li)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if li <= #M.config.labels then
|
local prev = line_end[m.line]
|
||||||
local label = M.config.labels:sub(li, li)
|
if label and (not prev or m.start_col >= prev) then
|
||||||
li = li + 1
|
if two then
|
||||||
|
prefixes[label:sub(1, 1)] = true
|
||||||
|
end
|
||||||
active[label] = { m.line + 1, m.start_col }
|
active[label] = { m.line + 1, m.start_col }
|
||||||
api.nvim_buf_set_extmark(buf, NS, m.line, m.start_col, {
|
api.nvim_buf_set_extmark(buf, NS, m.line, m.start_col, {
|
||||||
virt_text = { { label, M.config.label } },
|
virt_text = { { label, M.config.label } },
|
||||||
virt_text_pos = 'overlay',
|
virt_text_pos = 'overlay',
|
||||||
priority = 201,
|
priority = 201,
|
||||||
})
|
})
|
||||||
|
line_end[m.line] = m.start_col + #label + (two and 1 or 0)
|
||||||
|
li = li + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in new issue
Block a user