Skip to content

Instantly share code, notes, and snippets.

@b0o
Last active February 14, 2021 04:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save b0o/22ae2b230d39cf5bc749383921611405 to your computer and use it in GitHub Desktop.
Save b0o/22ae2b230d39cf5bc749383921611405 to your computer and use it in GitHub Desktop.
# fzf path finding filesystem navigation thing by maddy (github.com/b0o)
#
# key bindings:
# - return: accept final
# - alt-return: accept final (absolute)
# - esc: escape
# - ctrl-g: escape (absolute)
# - alt-o: accept query
# - alt-P append query
# - ctrl-o: replace query
# - alt-i: descend into directory or accept file
# - alt-u: ascend into parent directory
# - alt-U ascend to next existing ancestor
# - ctrl-n: next
# - alt-n: next
# - tab: next
# - down: next
# - ctrl-p: prev
# - alt-p: prev
# - shift-tab: prev
# - up: prev
function _smart_fzf () {
local left="$LBUFFER"
local right="$RBUFFER"
local path_orig="$*"
if [[ -z "$path_orig" && -n "$BUFFER" ]]; then
zmodload -e zsh/pcre || zmodload zsh/pcre
# Split before word adjacent to the left of the cursor
pcre_compile -- '^(?U)((.*\s+)*)((\S|\\\s)+)$'
if [[ -n "$LBUFFER" ]] && pcre_match -a mat -- "$LBUFFER"; then
path_orig="${mat[3]//(#m)\\/}"
left="${LBUFFER:0:$((${#LBUFFER} - ${#path_orig}))}"
fi
# Split after word adjacent to the right of the cursor
pcre_compile -- '^((\\\s|\S)+)((\s+.*)*)$'
if [[ -n "$RBUFFER" ]] && pcre_match -a mat -- "$RBUFFER"; then
right="${mat[3]}"
path_orig="${path_orig}${mat[1]//(#m)\\/}"
fi
fi
path_orig="${path_orig:-.}"
path_orig=${~path_orig} # expand tilde
path_orig="${(e)path_orig}" # expand variables
local path_orig_absolute
local relative="$PWD"
if [[ "$path_orig" =~ ^/ ]]; then
path_orig_absolute="$path_orig"
relative="/"
else
path_orig_absolute="$(realpath -m "$path_orig")"
fi
local fzf_preview=(
'f="$(realpath -m "'"$path_orig_absolute"'/{}")";'
'bat --color always "$f" 2>/dev/null || exa --tree --level=1 --color=always "$f" 2>/dev/null || stat "$f" 2>/dev/null'
)
local res
res="$(
{
{
find "$path_orig_absolute" -mindepth 1 -maxdepth 1 -type b -or -type c -printf "${fg_bold[yellow]}%f${reset_color}\\n";
find "$path_orig_absolute" -mindepth 1 -maxdepth 1 -type f -not -executable -printf "${fg_no_bold[default]}%f${reset_color}\\n";
find "$path_orig_absolute" -mindepth 1 -maxdepth 1 -type f -executable -printf "${fg_no_bold[green]}%f${reset_color}\\n";
find "$path_orig_absolute" -mindepth 1 -maxdepth 1 -type l -printf "${fg_no_bold[cyan]}%f${reset_color}\\n";
find "$path_orig_absolute" -mindepth 1 -maxdepth 1 -type p -printf "${fg_no_bold[yellow]}%f${reset_color}\\n";
find "$path_orig_absolute" -mindepth 1 -maxdepth 1 -type s -printf "${fg_bold[magenta]}%f${reset_color}\\n";
find "$path_orig_absolute" -mindepth 1 -maxdepth 1 -not '(' -type b -or -type c -or -type f -or -type l -or -type p -or -type s -or -type d ')' -printf "${fg_no_bold[red]}%f${reset_color}\\n";
} | sort -k 1.8 # The '-k 1.8' argument tells sort to skip the first 8 characters of each line, which happens to be the length of the ANSI color code escape sequences
find "$path_orig_absolute" -mindepth 1 -maxdepth 1 -type d -printf "${fg_bold[blue]}%f${reset_color}\\n";
printf "${fg_bold[white]}%s${reset_color}\n" "." ".."
} 2>/dev/null \
| fzf \
--reverse --no-sort --ansi --height='50%' --header="$path_orig_absolute" \
--print-query --cycle \
--expect='alt-return,ctrl-g,alt-P,alt-o,alt-i,alt-u,alt-U' \
--bind='ctrl-o:replace-query,tab:down,btab:up,alt-n:down,alt-p:up' \
--preview="bash -c '${fzf_preview[*]}'")"
local -i code=$?
local path_new
local query key match
case $code in
0|1|130)
query="$(head -1 <<<"$res")"
;|
0|1)
key="$(head -2 <<<"$res" | tail -1)"
case "${key:-}" in
"alt-u")
path_new=".."
;;
"alt-o"|"alt-P")
path_new="${query:-}"
;;
"alt-U"|"ctrl-g")
path_new="."
;;
esac
;|
# Match
0)
path_new="${path_new:-$(tail -1 <<<"$res")}"
;;
# No match
1)
;;
# Interrupted with CTRL-C or ESC
130)
path_new=""
;;
# Error
2|*)
return 1
;;
esac
if [[ "$key" != "alt-o" ]]; then
path_new="$(realpath -m --relative-to="$relative" "${path_orig:+$path_orig/}${path_new}")"
if [[ "$key" == "alt-U" ]]; then
local -i c_u_once=0
while [[ $c_u_once -eq 0 || ! -e "$path_new" ]]; do
c_u_once=1
path_new="$(realpath -m --relative-to="$relative" "${path_new}/..")"
done
fi
if [[ "$relative" == "/" ]]; then
path_new="/${path_new}"
fi
fi
if [[ "$key" == "alt-return" || "$key" == "ctrl-g" ]]; then
path_new="$(realpath -m "$path_new")"
fi
LBUFFER="${left}${path_new}"
RBUFFER="$right"
zle reset-prompt
if [[ "$key" =~ ^alt-[uUoP]$ || ( "$key" == "alt-i" && ( ! -e "$path_new" || -d "$path_new" ) ) ]]; then
_smart_fzf
fi
}
zle -N smart-fzf _smart_fzf
bindkey "^[." smart-fzf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment