186 lines
3.6 KiB
Lua
186 lines
3.6 KiB
Lua
require('vis')
|
|
|
|
local lpeg = vis.lpeg
|
|
|
|
local P = lpeg.P
|
|
local Cp = lpeg.Cp
|
|
local Ct = lpeg.Ct
|
|
|
|
local function search(p)
|
|
return Ct(((1 - p)^0 * Cp() * p)^0)
|
|
end
|
|
|
|
local up_keys = {
|
|
'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_keys = {
|
|
'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 function merge(a, b)
|
|
local c = {}
|
|
for i = 1, #a do
|
|
c[i] = a[i]
|
|
end
|
|
for i = 1, #b do
|
|
c[#a + i] = b[i]
|
|
end
|
|
return c
|
|
end
|
|
|
|
local function layout()
|
|
local l, r, t, n = 0, 0, 0, 0
|
|
local opt = vis.win.options
|
|
if opt.numbers or opt.relativenumbers then
|
|
n = #tostring(vis.win.viewport.lines.finish)
|
|
end
|
|
if vis.ui.layout == vis.ui.layouts.HORIZONTAL then
|
|
for win in vis:windows() do
|
|
if win == vis.win then
|
|
break
|
|
end
|
|
t = t + win.height
|
|
end
|
|
elseif vis.ui.layout == vis.ui.layouts.VERTICAL then
|
|
local left = true
|
|
for win in vis:windows() do
|
|
if win == vis.win then
|
|
left = false
|
|
if opt.wrapcolumn ~= 0 then
|
|
r = r + win.width - n - opt.wrapcolumn
|
|
end
|
|
elseif left then
|
|
l = l + win.width + 1
|
|
else
|
|
r = r + win.width
|
|
end
|
|
end
|
|
end
|
|
return '--wrap --padding=' .. t .. ',' .. r .. ',0,' .. (l + n) .. ' --tabstop=' .. opt.tabwidth
|
|
end
|
|
|
|
local mu = #up_keys
|
|
local md = #down_keys
|
|
local up = merge(up_keys, down_keys)
|
|
local down = merge(down_keys, up_keys)
|
|
|
|
local jumps = {}
|
|
|
|
local function jump(keys)
|
|
local _, esc = keys:find('<Escape>')
|
|
if esc then
|
|
return esc
|
|
end
|
|
local ret = #keys
|
|
keys = keys:gsub('<Enter>', '\n')
|
|
if #keys < 2 then
|
|
return -1
|
|
end
|
|
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 = search(P(keys))
|
|
local lst = p:match(data)
|
|
if not lst or #lst == 0 then
|
|
vis:info('not found')
|
|
return ret
|
|
end
|
|
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 = #lst + 1
|
|
local t = {}
|
|
jumps = {}
|
|
for i = 1, #lst do
|
|
local a = lst[i]
|
|
if a < pos then
|
|
prev = i
|
|
end
|
|
if a > pos then
|
|
next = i
|
|
break
|
|
end
|
|
end
|
|
local nu = prev
|
|
local nd = #lst - next
|
|
local j = 1
|
|
for i = prev, 1, -1 do
|
|
if j == mu + 1 then
|
|
j = j + nd
|
|
end
|
|
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 j == md + 1 then
|
|
j = j + nu
|
|
end
|
|
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
|
|
input = input .. '\x1b[1;37;44m' .. keys .. '\x1b[0m'
|
|
k = lst[i] + 2
|
|
end
|
|
end
|
|
input = input .. data:sub(k)
|
|
|
|
local code, out, err = vis:pipe(input, 'fzf --ansi --layout=reverse-list --no-info --no-separator --color gutter:-1,bg+:-1 --marker="" ' .. layout() .. ' --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)
|