I'm trying to make fzf
s autocompletion invoked on cat **<TAB>
return only files (directories does not make sense for cat
). According to docs it's the matter of defining _fzf_complete_cat()
, so my first try was
_fzf_complete_cat() {
_fzf_complete -- "$@" < <(
fd --type f --hidden --follow --no-ignore --exclude .git
)
}
however, there's a major flaw: this completion does not take into account the path's part before **
, e.g. if I am in ~/subdir
and type cat ~/another/**<TAB>
it will not recurse from there, but rather from ~/subdir
.
I understand the trick is around these lines from fzf/shell/completion.zsh, namely, the way _fzf_[path|dir]_completion()
handles it. So I tried smth like that (essentially, repeating the logic of the completion.zsh
):
_custom_fzf_compgen_path() {
fd --hidden --follow --no-ignore --exclude ".git" . "$1"
}
_custom_fzf_path_completion() {
__fzf_generic_path_completion "$1" "$2" _fzf_compgen_path \
"-m" "" " "
}
_fzf_complete_cat() {
_custom_fzf_path_completion "$prefix" "$1"
}
and it almost works, messing up in the very end with zle reset-prompt
from here.
TL;DR: I need **<TAB>
for cat
command work similarly to _fzf_[path|dir]_completion()
but return only files.
Appreciate any ideas! Thanks!
I ended up going down the initial path of tweaking _fzf_complete_cat()
. It uses a wonderful function __fzf_generic_path_completion()
which takes care of splitting the path yped before **<TAB>
(e.g. cat ~/some_other_dir/**<TAB>
) and finding the base of it. Problem lied around extra zle reset-prompt
in here, so I had to create my own __fzf_generic_path_completion()
without it.
Full working solution
__custom_fzf_generic_path_completion() {
local base lbuf cmd compgen fzf_opts suffix tail dir leftover matches
base=$1
lbuf=$2
cmd=$(__fzf_extract_command "$lbuf")
compgen=$3
fzf_opts=$4
suffix=$5
tail=$6
setopt localoptions nonomatch
eval "base=$base"
[[ $base = *"/"* ]] && dir="$base"
while [ 1 ]; do
if [[ -z "$dir" || -d ${dir} ]]; then
leftover=${base/#"$dir"}
leftover=${leftover/#\/}
[ -z "$dir" ] && dir='.'
[ "$dir" != "/" ] && dir="${dir/%\//}"
matches=$(eval "$compgen $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS" __fzf_comprun "$cmd" ${(Q)${(Z+n+)fzf_opts}} -q "$leftover" | while read item; do
echo -n "${(q)item}$suffix "
done)
matches=${matches% }
if [ -n "$matches" ]; then
LBUFFER="$lbuf$matches$tail"
fi
# REMOVED HERE zle reset-prompt
break
fi
dir=$(dirname "$dir")
dir=${dir%/}/
done
}
_custom_fzf_compgen_path() {
# Add here your favorite command to search for files. $1 is the starting
# point.
fd --type f --hidden --follow --no-ignore --exclude ".git" . "$1"
}
_custom_fzf_path_completion() {
__custom_fzf_generic_path_completion "$1" "$2" _custom_fzf_compgen_path \
"-m" "" " "
}
_fzf_complete_cat() {
# $prefix is the variable set by fzf here https://github.com/junegunn/fzf/blob/master/shell/completion.zsh#L302
_custom_fzf_path_completion "$prefix" "$1"
}