vis: new fast jump using fzf and selecting by letter
This commit is contained in:
@@ -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('<Escape>')
|
||||
if esc then
|
||||
return esc
|
||||
end
|
||||
local _, enter = keys:find('<Enter>')
|
||||
if enter then
|
||||
keys = keys:gsub('<Enter>', '')
|
||||
end
|
||||
keys = keys:gsub('<Tab>', 'J')
|
||||
keys = keys:gsub('<S[-]Tab>', '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('.<Backspace>', '')
|
||||
if #keys < 1 then
|
||||
local ret = #keys
|
||||
keys = keys:gsub('<Enter>', '\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
|
||||
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
|
||||
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
|
||||
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
|
||||
j = next - 1 + 2 * n
|
||||
input = input .. '\x1b[1;37;44m' .. keys .. '\x1b[0m'
|
||||
k = lst[i] + 2
|
||||
end
|
||||
if j > 0 and j < #lst then
|
||||
pos = lst[j] + v.start - 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)
|
||||
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
|
||||
vis.win:style(vis.win.STYLE_SELECTION, a, b)
|
||||
local p = jumps[out:sub(1, 1)]
|
||||
if p then
|
||||
vis.win.selection.pos = p
|
||||
else
|
||||
vis:info('not found')
|
||||
end
|
||||
end
|
||||
return -1
|
||||
end, 'colorize token')
|
||||
return ret
|
||||
end
|
||||
|
||||
vis:map(vis.modes.NORMAL, '\\', jump)
|
||||
|
||||
Reference in New Issue
Block a user