vis: add script fzf.sh and use it with just two keys

fzf.sh is a wrapper around fzf with mode for fd, rg, git and jj which
allow to switch between them with keys
This commit is contained in:
2025-09-16 20:48:27 +02:00
parent d03dda4979
commit 84d26c68a5
2 changed files with 251 additions and 63 deletions

215
vis/.config/vis/fzf.sh Executable file
View File

@@ -0,0 +1,215 @@
#!/bin/sh
prompt=${FZF_PROMPT%> }
cmd=${prompt%+*}
hidden=${prompt#$cmd}
ripgrep='rg --column --line-number --color=always --smart-case'
if [ "$1" = list ]; then
case "$FZF_HEADER_LABEL" in
:?*)
path=${FZF_HEADER_LABEL#?}
;;
*)
path=
;;
esac
case "$prompt" in
files)
exec fd --type f '' $path
;;
files+hidden)
exec fd --type f -H '' $path
;;
search)
exec $ripgrep "$FZF_QUERY" $path
;;
search+hidden)
exec $ripgrep -. "$FZF_QUERY" $path
;;
git-files*)
exec git ls-files $path
;;
git-search*)
exec git grep --column --line-number --color=always "$FZF_QUERY" $path
;;
jj-files*)
exec jj file list --ignore-working-copy $path
;;
jj-search*)
exec $ripgrep "$FZF_QUERY" $(jj file list --ignore-working-copy $path)
;;
esac
exit
fi
if [ "$1" = preview ]; then
if [ -n "$3" ]; then
start=$(( $3 - $FZF_PREVIEW_LINES / 2 ))
if [ $start -lt 1 ]; then
start=1
fi
end=$(( $start + $FZF_PREVIEW_LINES ))
exec bat --style=numbers --color=always --highlight-line $3 --line-range $start:$end $2
else
exec bat --style=numbers --color=always $2
fi
fi
reload="reload(sh $0 list || true)"
no_search="rebind(change)+disable-search"
search="unbind(change)+enable-search"
if [ "$1" = key ]; then
case "$FZF_KEY" in
alt-d)
path=${FZF_HEADER_LABEL#?}
case "$FZF_HEADER_LABEL" in
.?*)
echo "change-header(path: $path)+change-header-label(:$path)+$reload"
;;
*)
echo "change-header()+change-header-label(.$path)+$reload"
;;
esac
;;
alt-f)
case "$cmd" in
*files)
prompt="files$hidden"
;;
*search)
prompt="${cmd%-*}-files$hidden"
;;
esac
echo "change-prompt($prompt> )+$search+$reload"
;;
alt-g)
case "$cmd" in
*files)
prompt="git-files$hidden"
echo "change-prompt($prompt> )+$search+$reload"
;;
*search)
prompt="git-search$hidden"
echo "change-prompt($prompt> )+$no_search+$reload"
;;
esac
;;
alt-h)
if [ -z "$hidden" ]; then
prompt="$cmd+hidden"
else
prompt="$cmd"
fi
echo "change-prompt($prompt> )+$reload"
;;
alt-j)
case "$cmd" in
*files)
prompt="jj-files$hidden"
echo "change-prompt($prompt> )+$search+$reload"
;;
*search)
prompt="jj-search$hidden"
echo "change-prompt($prompt> )+$no_search+$reload"
;;
esac
;;
alt-s)
case "$cmd" in
*files)
prompt="${cmd%-*}-search$hidden"
;;
*search)
prompt="search$hidden"
;;
esac
echo "change-prompt($prompt> )+$no_search+$reload"
;;
esac
exit
fi
if [ -n "$2" ]; then
label=".$2"
else
label=".."
fi
case ${1%+hidden} in
auto-files)
git=$(git rev-parse --show-toplevel 2> /dev/null)
jj=$(jj root --ignore-working-copy 2> /dev/null)
if [ -n "$jj" ] && [ "${git#$jj}" = "$git" -o "$git" = "$jj" ]; then
cmd="jj-files$hidden"
elif [ -n "$git" ] && [ "${jj#$git}" = "$jj" ]; then
cmd="git-files$hidden"
else
cmd="files"
fi
action="$search"
prompt="$cmd> "
;;
auto-search)
git=$(git rev-parse --show-toplevel 2> /dev/null)
jj=$(jj root --ignore-working-copy 2> /dev/null)
if [ -n "$jj" ] && [ "${git#$jj}" = "$git" -o "$git" = "$jj" ]; then
cmd="jj-search$hidden"
elif [ -n "$git" ] && [ "${jj#$git}" = "$jj" ]; then
cmd="git-search$hidden"
else
cmd="search"
fi
action="$no_search"
prompt="$cmd> "
;;
files|git-files|jj-files)
cmd="$1"
action="$search"
prompt="$1> "
;;
search|git-search|jj-search)
cmd="$1"
action="$no_search"
prompt="$1> "
;;
*)
cmd="files"
action="$search"
prompt="files> "
;;
esac
key="transform(sh $0 key)"
HELP='Keys:
alt-? help
alt-d toggle alternative directory
alt-f switch to files (twice for plain files)
alt-g switch to git
alt-j switch to jj
alt-h toggle hidden
alt-p toggle preview (also to turn off help)
alt-s switch to search (twice for plain search)
alt-u toggle preview window position (right or up)
'
exec fzf --query "$3" \
--prompt "$prompt" \
--header-label "$label" \
--ansi \
--delimiter : \
--ghost ' (Use alt-? for help)' \
--bind "change:$reload" \
--bind "start:$reload+$action" \
--bind "alt-d:$key" \
--bind "alt-f:$key" \
--bind "alt-g:$key" \
--bind "alt-j:$key" \
--bind "alt-h:$key" \
--bind "alt-s:$key" \
--bind "alt-p:change-preview(sh $0 preview {1} {2})+toggle-preview" \
--bind "alt-u:change-preview-window(up|right)" \
--bind "alt-?:change-preview(echo '$HELP')+show-preview"

View File

@@ -66,6 +66,32 @@ local function escape_and_quoted(s)
return "'" .. s:gsub("'", "\\'") .. "'"
end
local function cmd_action(cmd, action)
local code, out, err = vis:pipe(cmd, true)
if code == 0 then
action(out)
elseif err ~= nil then
vis:info(err)
elseif code ~= 0 then
vis:info('Program exit code ' .. code)
end
end
local function fzf_sh(arg)
action = function(out)
open_file_pos(out, vis.win.file.modified and 'o' or 'e')
end
local home = os.getenv('HOME')
local path = vis.win.file.path or ''
local dir = path:match('^.*/') or ''
local reg = ''
if reg ~= '"' then
reg = string.gsub(vis.registers[vis.register][1], '%z', '')
end
local cmd = home .. '/.config/vis/fzf.sh ' .. escape_and_quoted(arg) .. ' ' .. escape_and_quoted(dir) .. ' ' .. escape_and_quoted(reg)
cmd_action(cmd, action)
end
local function search(cmd, action)
if action == nil then
action = function(out)
@@ -78,14 +104,7 @@ local function search(cmd, action)
cmd = cmd .. ' --query=' .. escape_and_quoted(reg)
end
end
local code, out, err = vis:pipe(cmd, true)
if code == 0 then
action(out)
elseif err ~= nil then
vis:info(err)
elseif code ~= 0 then
vis:info('Program exit code ' .. code)
end
cmd_action(cmd, action)
end
local file_slots = {}
@@ -178,56 +197,26 @@ vis.events.subscribe(vis.events.INIT, function()
vis:map(vis.modes.NORMAL, ' l=', ':lspc-format<Enter>')
for num = 1, 9 do
vis:map(vis.modes.NORMAL, ' s' .. num, function() set_file_slot(num) end, 'set file slot ' .. num)
vis:map(vis.modes.NORMAL, ' r' .. num, function() set_file_slot(num) end, 'set file slot ' .. num)
vis:map(vis.modes.NORMAL, ' ' .. num, function() open_file_slot(num, 'e') end, 'open file slot ' .. num)
vis:map(vis.modes.NORMAL, ' h' .. num, function() open_file_slot(num, 'o') end, 'open file slot ' .. num)
vis:map(vis.modes.NORMAL, ' v' .. num, function() open_file_slot(num, 'vsplit') end,
'open file slot ' .. num)
end
vis:map(vis.modes.NORMAL, ' fg', function()
search(fzf_reload(ripgrep))
end, 'fzf: rg')
vis:map(vis.modes.NORMAL, ' s', function()
fzf_sh('auto-search')
end, 'fzf: search')
vis:map(vis.modes.NORMAL, ' hg', function()
search(fzf_reload(ripgrep .. ' -.'))
end, 'fzf: rg with hidden files')
vis:map(vis.modes.NORMAL, ' f', function()
fzf_sh('auto-files')
end, 'fzf: files')
vis:map(vis.modes.NORMAL, ' /', function()
search(fzf_reload(ripgrep .. ' --with-filename {q} ' .. escape_and_quoted(vis.win.file.path)))
end, 'fzf: rg current file')
vis:map(vis.modes.NORMAL, ' ff', function()
search('fd --type f | fzf')
end, 'fzf: files')
vis:map(vis.modes.NORMAL, ' fh', function()
search('fd -H --type f | fzf')
end, 'fzf: files with hidden files')
vis:map(vis.modes.NORMAL, ' df', function()
local path = vis.win.file.path
if path then
local dir = path:match('^.*/')
local arg = escape_and_quoted(dir)
search('fd --type f "" ' .. arg .. ' | fzf')
else
search('fd --type f | fzf')
end
end, 'fzf in file directory')
vis:map(vis.modes.NORMAL, ' dh', function()
local path = vis.win.file.path
if path then
local dir = path:match('^.*/')
local arg = escape_and_quoted(dir)
search('fd -H --type f "" ' .. arg .. ' | fzf')
else
search('fd -H --type f | fzf')
end
end, 'fzf in file directory with hidden files')
vis:map(vis.modes.NORMAL, ' sh', function()
vis:map(vis.modes.NORMAL, ' .', function()
local shell = os.getenv('SHELL')
vis:command('!' .. shell)
end, 'run shell')
@@ -244,29 +233,13 @@ vis.events.subscribe(vis.events.INIT, function()
end
end, 'run shell in file directory')
vis:map(vis.modes.NORMAL, ' gf', function()
search('git ls-files | fzf')
end, 'fzf: git files')
vis:map(vis.modes.NORMAL, ' gg', function()
search(fzf_reload('git grep --column --line-number --color=always'))
end, 'fzf: jj grep')
vis:map(vis.modes.NORMAL, ' gl', function()
vis:command('!lazygit')
end, 'lazygit')
vis:map(vis.modes.NORMAL, ' jf', function()
search('jj file list | fzf')
end, 'fzf: jj files')
vis:map(vis.modes.NORMAL, ' jg', function()
search(fzf_reload(ripgrep .. ' {q} $(jj file list | xargs)'))
end, 'fzf: jj grep')
vis:map(vis.modes.NORMAL, ' jl', function()
vis:command('!lazyjj')
end, 'fzf open')
end, 'lazyjj')
vis:map(vis.modes.NORMAL, ' ', function()
vis:command('fzfmru')