ohmyzsh/plugins/fz/fz.sh
2017-04-10 22:21:44 -07:00

297 lines
8.8 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[[ -n "$FZ_CMD" ]] || FZ_CMD=z
[[ -n "$FZ_SUBDIR_CMD" ]] || FZ_SUBDIR_CMD=zz
[[ -n "$FZ_HISTORY_CD_CMD" ]] || FZ_HISTORY_CD_CMD=_z
[[ -n "$FZ_SUBDIR_HISTORY_CD_CMD" ]] || FZ_SUBDIR_HISTORY_CD_CMD="_z -c"
[[ -n "$FZ_HISTORY_LIST_GENERATOR" ]] \
|| FZ_HISTORY_LIST_GENERATOR=__fz_generate_matched_history_list
[[ -n "$FZ_SUBDIR_HISTORY_LIST_GENERATOR" ]] \
|| FZ_SUBDIR_HISTORY_LIST_GENERATOR=__fz_generate_matched_subdir_history_list
[[ -n "$FZ_SUBDIR_TRAVERSAL" ]] || FZ_SUBDIR_TRAVERSAL=1
[[ -n "$FZ_CASE_INSENSITIVE" ]] || FZ_CASE_INSENSITIVE=1
[[ -n "$FZ_ABBREVIATE_HOME" ]] || FZ_ABBREVIATE_HOME=1
alias ${FZ_CMD}='_fz'
alias ${FZ_SUBDIR_CMD}='_fzz'
__fz_generate_matched_subdir_list() {
local dir seg starts_with_dir
if [[ "$1" == */ ]]; then
dir="$1"
find -L "$(cd "$dir" 2>/dev/null && pwd)" -mindepth 1 -maxdepth 1 -type d \
2>/dev/null | while read -r line; do
base="${line##*/}"
if [[ "$base" == .* ]]; then
continue
fi
echo "$line"
done
else
dir=$(dirname -- "$1")
seg=$(basename -- "$1")
if [[ "$FZ_CASE_INSENSITIVE" == "1" ]]; then
seg=$(echo "$seg" | tr '[:upper:]' '[:lower:]')
fi
starts_with_dir=$( \
find -L "$(cd "$dir" 2>/dev/null && pwd)" -mindepth 1 -maxdepth 1 \
-type d 2>/dev/null | while read -r line; do \
base="${line##*/}"
if [[ "$seg" != .* && "$base" == .* ]]; then
continue
fi
if [[ "$FZ_CASE_INSENSITIVE" != "1" ]]; then
if [[ "$base" == "$seg"* ]]; then
echo "$line"
fi
else
if [[ -n "$BASH_VERSION" ]]; then
if [[ "${base,,}" == "${seg,,}"* ]]; then
echo "$line"
fi
elif [[ -n "$ZSH_VERSION" ]]; then
if [[ "${base:l}" == "${seg:l}"* ]]; then
echo "$line"
fi
fi
fi
done
)
if [ -n "$starts_with_dir" ]; then
echo "$starts_with_dir"
else
find -L "$(cd "$dir" 2>/dev/null && pwd)" -mindepth 1 -maxdepth 1 \
-type d 2>/dev/null | while read -r line; do \
base="${line##*/}"
if [[ "$seg" != .* && "$base" == .* ]]; then
continue
fi
if [[ "$FZ_CASE_INSENSITIVE" != "1" ]]; then
if [[ "$base" == *"$seg"* ]]; then
echo "$line"
fi
else
if [[ -n "$BASH_VERSION" ]]; then
if [[ "${base,,}" == *"${seg,,}"* ]]; then
echo "$line"
fi
elif [[ -n "$ZSH_VERSION" ]]; then
if [[ "${base:l}" == *"${seg:l}"* ]]; then
echo "$line"
fi
fi
fi
done
fi
fi
}
__fz_generate_matched_history_list() {
_z -l $@ 2>&1 | while read -r line; do
if [[ "$line" == common:* ]]; then continue; fi
# Reverse the order and cut off the scores
echo "$line"
done | sed '1!G;h;$!d' | cut -b 12-
}
__fz_generate_matched_subdir_history_list() {
__fz_generate_matched_history_list -c "$@"
}
__fz_generate_matches() {
local cmd histories subdirs
if [[ -n "$BASH_VERSION" ]]; then
cmd=$([[ "${COMP_WORDS[0]}" =~ [[:space:]]*([^[:space:]]|[^[:space:]].*[^[:space:]])[[:space:]]* ]]; \
echo -n "${BASH_REMATCH[1]}")
elif [[ -n "$ZSH_VERSION" ]]; then
cmd=(${(z)LBUFFER})
cmd=${cmd[1]}
fi
if [[ "$cmd" == "$FZ_CMD" ]]; then
if [[ "$FZ_ABBREVIATE_HOME" == "1" ]]; then
if [ "$FZ_SUBDIR_TRAVERSAL" == "1" ]; then
cat <("$FZ_HISTORY_LIST_GENERATOR" "$@") \
<(__fz_generate_matched_subdir_list "$@") \
| sed '/^$/d' | sed -e "s,^$HOME,~," | awk '!seen[$0]++'
else
cat <("$FZ_HISTORY_LIST_GENERATOR" "$@") \
| sed '/^$/d' | sed -e "s,^$HOME,~," | awk '!seen[$0]++'
fi
else
if [ "$FZ_SUBDIR_TRAVERSAL" == "1" ]; then
cat <("$FZ_HISTORY_LIST_GENERATOR" "$@") \
<(__fz_generate_matched_subdir_list "$@") \
| sed '/^$/d' | awk '!seen[$0]++'
else
cat <("$FZ_HISTORY_LIST_GENERATOR" "$@") \
| sed '/^$/d' | awk '!seen[$0]++'
fi
fi
elif [[ "$cmd" == "$FZ_SUBDIR_CMD" ]]; then
histories=$("$FZ_SUBDIR_HISTORY_LIST_GENERATOR" "$@")
if [[ "$FZ_ABBREVIATE_HOME" == "1" ]]; then
if [ "$FZ_SUBDIR_TRAVERSAL" == "1" ]; then
cat <("$FZ_SUBDIR_HISTORY_LIST_GENERATOR" "$@") \
<(__fz_generate_matched_subdir_list "$@") \
| sed '/^$/d' | sed -e "s,^$HOME,~," | awk '!seen[$0]++'
else
cat <("$FZ_SUBDIR_HISTORY_LIST_GENERATOR" "$@") \
| sed '/^$/d' | sed -e "s,^$HOME,~," | awk '!seen[$0]++'
fi
else
if [ "$FZ_SUBDIR_TRAVERSAL" == "1" ]; then
cat <("$FZ_SUBDIR_HISTORY_LIST_GENERATOR" "$@") \
<(__fz_generate_matched_subdir_list "$@") \
| sed '/^$/d' | awk '!seen[$0]++'
else
cat <("$FZ_SUBDIR_HISTORY_LIST_GENERATOR" "$@") \
| sed '/^$/d' | awk '!seen[$0]++'
fi
fi
fi
}
__fz_bash_completion() {
COMPREPLY=()
local selected slug
eval "slug=${COMP_WORDS[@]:(-1)}"
if [[ "$(__fz_generate_matches "$slug" | head | wc -l)" -gt 1 ]]; then
selected=$(__fz_generate_matches "$slug" \
| FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse \
--bind 'shift-tab:up,tab:down' $FZF_DEFAULT_OPTS" fzf)
elif [[ "$(__fz_generate_matches "$slug" | head | wc -l)" -eq 1 ]]; then
selected=$(__fz_generate_matches "$slug")
else
return
fi
if [[ -n "$selected" ]]; then
if [[ "$FZ_ABBREVIATE_HOME" == "1" ]]; then
selected=${selected/#\~/$HOME}
fi
selected=$(printf %q "$selected")
if [[ "$selected" != */ ]]; then
selected="${selected}/"
fi
if [[ "$FZ_ABBREVIATE_HOME" == "1" ]]; then
selected=${selected/#$HOME/\~}
fi
COMPREPLY=( "$selected" )
fi
printf '\e[5n'
}
__fz_zsh_completion() {
setopt localoptions noshwordsplit noksh_arrays noposixbuiltins nonomatch
local args cmd selected slug
args=(${(z)LBUFFER})
cmd=${args[1]}
if [[ "$cmd" != "$FZ_CMD" && "$cmd" != "$FZ_SUBDIR_CMD" ]] \
|| [[ "$cmd" == "$FZ_CMD" && "$LBUFFER" =~ "^\s*$FZ_CMD$" ]] \
|| [[ "$cmd" == "$FZ_SUBDIR_CMD" && "$LBUFFER" =~ "^\s*$FZ_SUBDIR_CMD$" ]]; then
zle ${__fz_zsh_default_completion:-expand-or-complete}
return
fi
if [[ "${#args}" -gt 1 ]]; then
eval "slug=${args[-1]}"
fi
if [[ "$(__fz_generate_matches "$slug" | head | wc -l)" -gt 1 ]]; then
selected=$(__fz_generate_matches "$slug" \
| FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse \
--bind 'shift-tab:up,tab:down' $FZF_DEFAULT_OPTS" fzf)
elif [[ "$(__fz_generate_matches "$slug" | head | wc -l)" -eq 1 ]]; then
selected=$(__fz_generate_matches "$slug")
else
return
fi
if [[ -n "$selected" ]]; then
if [[ "$FZ_ABBREVIATE_HOME" == "1" ]]; then
selected=${selected/#\~/$HOME}
fi
selected="${(q)selected}"
if [[ "$selected" != */ ]]; then
selected="${selected}/"
fi
if [[ "$FZ_ABBREVIATE_HOME" == "1" ]]; then
selected=${selected/#$HOME/\~}
fi
LBUFFER="$cmd $selected"
fi
zle redisplay
typeset -f zle-line-init >/dev/null && zle zle-line-init
}
__fz_init_bash_completion() {
# Enable redrawing line by printf '\e[5n'
bind '"\e[0n": redraw-current-line'
complete -o nospace -F __fz_bash_completion "$FZ_CMD"
complete -o nospace -F __fz_bash_completion "$FZ_SUBDIR_CMD"
}
__fz_init_zsh_completion() {
[ -n "$__fz_zsh_default_completion" ] || {
binding=$(bindkey '^I')
# $binding[(s: :w)2]
# The command substitution and following word splitting to determine the
# default zle widget for ^I formerly only works if the IFS parameter contains
# a space via $binding[(w)2]. Now it specifically splits at spaces, regardless
# of IFS.
# Its not compatitable with bash so use awk instead.
[[ $binding =~ 'undefined-key' ]] \
|| __fz_zsh_default_completion=$(echo "$binding" | awk '{print $2}')
unset binding
}
zle -N __fz_zsh_completion
bindkey '^I' __fz_zsh_completion
}
_fz() {
local rc
if [[ "$($FZ_HISTORY_LIST_GENERATOR "$@" | head | wc -l)" -gt 0 ]]; then
"$FZ_HISTORY_CD_CMD" "$@"
elif [[ "$FZ_SUBDIR_TRAVERSAL" -ne 0 ]]; then
err=$(cd "${@: -1}" 2>&1)
rc=$?
if ! cd "${@: -1}" 2>/dev/null; then
echo ${err#* } >&2
return $rc
fi
fi
}
_fzz() {
local rc
if [[ "$($FZ_SUBDIR_HISTORY_LIST_GENERATOR "$@" | head | wc -l)" -gt 0 ]]; then
if [[ -n "$BASH_VERSION" ]]; then
$FZ_SUBDIR_HISTORY_CD_CMD "$@"
elif [[ -n "$ZSH_VERSION" ]]; then
${=FZ_SUBDIR_HISTORY_CD_CMD} "$@"
fi
elif [[ "$FZ_SUBDIR_TRAVERSAL" -ne 0 ]]; then
err=$(cd "${@: -1}" 2>&1)
rc=$?
if ! cd "${@: -1}" 2>/dev/null; then
echo ${err#* } >&2
return $rc
fi
fi
}
if [[ -n "$BASH_VERSION" ]]; then
__fz_init_bash_completion
elif [[ -n "$ZSH_VERSION" ]]; then
__fz_init_zsh_completion
fi