From 4866eb3f9c55b5d0aa2992c35d64e073f4e81efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Pankowski?= Date: Tue, 30 Sep 2025 23:42:47 +0200 Subject: [PATCH] vis: new fast jump using fzf and selecting by letter --- vis/.config/vis/fast-jump.lua | 178 +++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 79 deletions(-) diff --git a/vis/.config/vis/fast-jump.lua b/vis/.config/vis/fast-jump.lua index 7834b41..cf2d097 100644 --- a/vis/.config/vis/fast-jump.lua +++ b/vis/.config/vis/fast-jump.lua @@ -1,81 +1,75 @@ +require('vis') + local lpeg = vis.lpeg -P = lpeg.P -R = lpeg.R -S = lpeg.S -Cp = lpeg.Cp -Ct = lpeg.Ct -space = S(' \t\n\r') -alnum = R('az', 'AZ', '09') +local P = lpeg.P +local Cp = lpeg.Cp +local Ct = lpeg.Ct local function search(p) - return Ct(((1 - p)^0 * Cp() * p * Cp())^0) + return Ct(((1 - p)^0 * Cp() * p)^0) end -vis:map(vis.modes.NORMAL, '\\', function(keys) - if #keys > 1 then - vis.win:draw() - end +local up = { + 'a', 's', 'd', 'f' , + 'q', 'w', 'e', 'r', 't', 'g', + 'z', 'x', 'c', 'v', 'b', + '1', '2', '3', '4', '5', + 'A', 'S', 'D', 'F' , + 'Q', 'W', 'E', 'R', 'T', 'G', + 'Z', 'X', 'C', 'V', 'B', + '!', '@', '#', '$', '%', + '`', '~', +} + +local down = { + 'j', 'k', 'l', ';', + 'y', 'u', 'i', 'o', 'p', + 'n', 'm', ',', '.', '/', + '6', '7', '8', '9', '0', + 'J', 'K', 'L', ':', + 'Y', 'U', 'I', 'O', 'P', + 'N', 'M', '<', '>', '?', + '^', '&', '*', '(', ')', + "'", '"', '\\', '|', +} + +local jumps = {} + +local function jump(keys) local _, esc = keys:find('') if esc then return esc end - local _, enter = keys:find('') - if enter then - keys = keys:gsub('', '') - end - keys = keys:gsub('', 'J') - keys = keys:gsub('', 'K') - vis:info(keys) - local n = 0 - keys = keys:gsub('[KJ]', function(s) - if s == 'K' then - n = n - 1 - elseif s == 'J' then - n = n + 1 - end - return '' - end) - keys = keys:gsub('.', '') - if #keys < 1 then + local ret = #keys + keys = keys:gsub('', '\n') + if #keys < 2 then return -1 end - local up = n < 0 + if #keys > 2 then + vis:info('not found') + return ret + end local v = vis.win.viewport.bytes local data = vis.win.file:content(v) - local p = P(false) - local prefix = nil - for i = 1, #keys do - local x = keys:sub(i, i) - if x == 'A' then - prefix = alnum - elseif x == 'F' then - prefix = P(1) - space - else - local y = S(x:lower() .. x:upper()) - if i == 1 then - p = y - elseif prefix then - p = p * (prefix - y)^0 * y - elseif x == ' ' then - p = p * space^1 - else - p = p * y - end - prefix = false - end - end - p = search(p) + + local p = search(P(keys)) local lst = p:match(data) - if not lst then + if not lst or #lst == 0 then vis:info('not found') - return + return ret end - local pos = vis.win.selection.pos + if #lst == 1 then + vis.win.selection.pos = v.start + lst[1] - 1 + return ret + end + local pos = vis.win.selection.pos - v.start local prev = 0 - local next = 0 - for i = 2, #lst, 2 do - local a = lst[i-1] + v.start - 1 + local next = #lst + 1 + local t = {} + jumps = {} + for i = 1, #lst do + local a = lst[i] if a < pos then prev = i end @@ -84,27 +78,53 @@ vis:map(vis.modes.NORMAL, '\\', function(keys) break end end - local j = 0 - if up then - j = prev + 1 + 2 * n - else - j = next - 1 + 2 * n + local j = 1 + for i = prev, 1, -1 do + if not up[j] then + break + end + t[i] = up[j] + jumps[t[i]] = v.start + lst[i] - 1 + j = j + 1 end - if j > 0 and j < #lst then - pos = lst[j] + v.start - 1 + j = 1 + for i = next, #lst do + if not down[j] then + break + end + t[i] = down[j] + jumps[t[i]] = v.start + lst[i] - 1 + j = j + 1 end - if enter then - vis.win.selection.pos = pos - return enter - end - for i = 2, #lst, 2 do - local a = lst[i-1] + v.start - 1 - local b = lst[i] + v.start - 2 - if a == pos then - vis.win:style(vis.win.STYLE_COLOR_COLUMN, a, b) + local input = '' + local k = 1 + for i = 1, #lst do + input = input .. data:sub(k, lst[i] - 1) + if t[i] then + input = input .. '\x1b[1;37;44m' .. keys .. '\x1b[42m' .. t[i] .. '\x1b[0m' + k = lst[i] + 3 + if data:sub(k - 1, k - 1) == '\n' then + k = k - 1 + end else - vis.win:style(vis.win.STYLE_SELECTION, a, b) + input = input .. '\x1b[1;37;44m' .. keys .. '\x1b[0m' + k = lst[i] + 2 end end - return -1 -end, 'colorize token') + input = input .. data:sub(k) + + local code, out, err = vis:pipe(input, 'fzf --ansi --layout=reverse-list --no-info --no-separator --color gutter:-1 --marker="" --padding 0,0,0,3 --print-query --bind change:accept') + if code ~= 0 then + vis:info(err or ('fzf exit code ' .. code)) + else + local p = jumps[out:sub(1, 1)] + if p then + vis.win.selection.pos = p + else + vis:info('not found') + end + end + return ret +end + +vis:map(vis.modes.NORMAL, '\\', jump)