114 lines
3.3 KiB
Lua
114 lines
3.3 KiB
Lua
local M = {
|
|
editor = "hx",
|
|
args = {},
|
|
file_arg_format = "{file}:{row}:{col}",
|
|
}
|
|
|
|
local cwd = ya.sync(function()
|
|
return cx.active.current.cwd
|
|
end)
|
|
|
|
local sync_self = ya.sync(function()
|
|
local self = {}
|
|
for key, value in pairs(M) do
|
|
if type(value) ~= "function" then
|
|
self[key] = value
|
|
end
|
|
end
|
|
return self
|
|
end)
|
|
|
|
function M:setup(opts)
|
|
self.editor = opts.editor or self.editor
|
|
self.args = opts.args or self.args
|
|
self.file_arg_format = opts.file_arg_format or self.file_arg_format
|
|
end
|
|
|
|
function M:entry()
|
|
ya.emit("escape", { visual = true })
|
|
|
|
local _permit = ui.hide()
|
|
local cwd = cwd()
|
|
|
|
local output, err = M.run_with(cwd)
|
|
if not output then
|
|
return ya.notify({ title = "Yafg", content = tostring(err), timeout = 5, level = "error" })
|
|
end
|
|
|
|
local results = M.split_results(cwd, output)
|
|
if #results == 0 then
|
|
return
|
|
elseif #results == 1 then
|
|
local first_url = results[1][1]
|
|
local cha = fs.cha(first_url)
|
|
ya.emit(cha and cha.is_dir and "cd" or "reveal", { Url(first_url) })
|
|
end
|
|
|
|
local ss = sync_self()
|
|
local args = {}
|
|
for i, arg in ipairs(ss.args) do
|
|
args[i] = ya.quote(arg)
|
|
end
|
|
local file_args = {}
|
|
for i, result in ipairs(results) do
|
|
local arg = string.gsub(ss.file_arg_format, "{file}", ya.quote(tostring(result[1])))
|
|
arg = string.gsub(arg, "{row}", tostring(result[2]))
|
|
arg = string.gsub(arg, "{col}", tostring(result[3]))
|
|
file_args[i] = arg
|
|
end
|
|
|
|
local cmd = ss.editor .. " " .. table.concat(args, " ") .. " " .. table.concat(file_args, " ")
|
|
ya.dbg("Yafg", "editor cmd", cmd)
|
|
os.execute(cmd)
|
|
end
|
|
|
|
function M.run_with(cwd)
|
|
local cmd_args = [=[
|
|
RG_PREFIX='rg --column --line-number --no-heading --color=always --smart-case'
|
|
PREVIEW='bat --color=always --highlight-line={2} {1}'
|
|
fzf --ansi --disabled --multi \
|
|
--bind "start:reload:${RG_PREFIX} {q}" \
|
|
--bind "change:reload:sleep 0.1; ${RG_PREFIX} {q} || true" \
|
|
--bind "ctrl-t:transform:[[ ! \${FZF_PROMPT} =~ ripgrep ]] &&
|
|
echo 'rebind(change)+change-prompt(1. ripgrep> )+disable-search+reload:${RG_PREFIX} \{q} || true' ||
|
|
echo 'unbind(change)+change-prompt(2. fzf> )+enable-search+reload:${RG_PREFIX} \"\" || true'" \
|
|
--color "hl:-1:underline,hl+:-1:underline:reverse" \
|
|
--prompt '1. ripgrep> ' \
|
|
--delimiter : \
|
|
--header 'CTRL-T: Switch between ripgrep/fzf' \
|
|
--preview "${PREVIEW}" \
|
|
--preview-window 'up,60%,~3,+{2}+3/2' \
|
|
--nth '3..'
|
|
]=]
|
|
local child, err =
|
|
Command("bash"):arg({ "-c", cmd_args }):cwd(tostring(cwd)):stdin(Command.INHERIT):stdout(Command.PIPED):spawn()
|
|
|
|
if not child then
|
|
return nil, Err("Failed to start `fzf`, error: %s", err)
|
|
end
|
|
|
|
local output, err = child:wait_with_output()
|
|
if not output then
|
|
return nil, Err("Cannot read `fzf` output, error: %s", err)
|
|
elseif not output.status.success and output.status.code ~= 130 then
|
|
return nil, Err("`fzf` exited with error code %s", output.status.code)
|
|
end
|
|
return output.stdout, nil
|
|
end
|
|
|
|
function M.split_results(cwd, output)
|
|
local t = {}
|
|
for line in output:gmatch("[^\r\n]+") do
|
|
local file, row, col = (string.gmatch(line, "(..-):(%d+):(%d+):"))()
|
|
local u = Url(file)
|
|
if u.is_absolute then
|
|
t[#t + 1] = { u, row, col }
|
|
else
|
|
t[#t + 1] = { cwd:join(u), row, col }
|
|
end
|
|
end
|
|
return t
|
|
end
|
|
|
|
return M
|