mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2024-11-25 22:27:41 +00:00
6de1ad9d3d
* Correctly exclude SSH config options with Host SSH config files have 14 options containing 'Host'. Previously The zsh and bash completion scripts would include lines containing these options when doing command-line completion of SSH hosts with `ssh **`. This commit fixes that problem by only including lines with 'host '. * Don't autocomplete SSH hostnames using ? SSH config files support ? as well as * for wildcards in Host lines. This commit excludes lines containing ? for zsh/bash command line completeion using `ssh **`
333 lines
8.9 KiB
Bash
333 lines
8.9 KiB
Bash
# ____ ____
|
|
# / __/___ / __/
|
|
# / /_/_ / / /_
|
|
# / __/ / /_/ __/
|
|
# /_/ /___/_/-completion.bash
|
|
#
|
|
# - $FZF_TMUX (default: 0)
|
|
# - $FZF_TMUX_HEIGHT (default: '40%')
|
|
# - $FZF_COMPLETION_TRIGGER (default: '**')
|
|
# - $FZF_COMPLETION_OPTS (default: empty)
|
|
|
|
# To use custom commands instead of find, override _fzf_compgen_{path,dir}
|
|
if ! declare -f _fzf_compgen_path > /dev/null; then
|
|
_fzf_compgen_path() {
|
|
echo "$1"
|
|
command find -L "$1" \
|
|
-name .git -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \
|
|
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
|
}
|
|
fi
|
|
|
|
if ! declare -f _fzf_compgen_dir > /dev/null; then
|
|
_fzf_compgen_dir() {
|
|
command find -L "$1" \
|
|
-name .git -prune -o -name .svn -prune -o -type d \
|
|
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
|
}
|
|
fi
|
|
|
|
###########################################################
|
|
|
|
# To redraw line after fzf closes (printf '\e[5n')
|
|
bind '"\e[0n": redraw-current-line'
|
|
|
|
__fzfcmd_complete() {
|
|
[ -n "$TMUX_PANE" ] && [ "${FZF_TMUX:-0}" != 0 ] && [ ${LINES:-40} -gt 15 ] &&
|
|
echo "fzf-tmux -d${FZF_TMUX_HEIGHT:-40%}" || echo "fzf"
|
|
}
|
|
|
|
__fzf_orig_completion_filter() {
|
|
sed 's/^\(.*-F\) *\([^ ]*\).* \([^ ]*\)$/export _fzf_orig_completion_\3="\1 %s \3 #\2"; [[ "\1" = *" -o nospace "* ]] \&\& [[ ! "$__fzf_nospace_commands" = *" \3 "* ]] \&\& __fzf_nospace_commands="$__fzf_nospace_commands \3 ";/' |
|
|
awk -F= '{OFS = FS} {gsub(/[^A-Za-z0-9_= ;]/, "_", $1);}1'
|
|
}
|
|
|
|
_fzf_opts_completion() {
|
|
local cur prev opts
|
|
COMPREPLY=()
|
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
|
opts="
|
|
-x --extended
|
|
-e --exact
|
|
--algo
|
|
-i +i
|
|
-n --nth
|
|
--with-nth
|
|
-d --delimiter
|
|
+s --no-sort
|
|
--tac
|
|
--tiebreak
|
|
-m --multi
|
|
--no-mouse
|
|
--bind
|
|
--cycle
|
|
--no-hscroll
|
|
--jump-labels
|
|
--height
|
|
--literal
|
|
--reverse
|
|
--margin
|
|
--inline-info
|
|
--prompt
|
|
--header
|
|
--header-lines
|
|
--ansi
|
|
--tabstop
|
|
--color
|
|
--no-bold
|
|
--history
|
|
--history-size
|
|
--preview
|
|
--preview-window
|
|
-q --query
|
|
-1 --select-1
|
|
-0 --exit-0
|
|
-f --filter
|
|
--print-query
|
|
--expect
|
|
--sync"
|
|
|
|
case "${prev}" in
|
|
--tiebreak)
|
|
COMPREPLY=( $(compgen -W "length begin end index" -- "$cur") )
|
|
return 0
|
|
;;
|
|
--color)
|
|
COMPREPLY=( $(compgen -W "dark light 16 bw" -- "$cur") )
|
|
return 0
|
|
;;
|
|
--history)
|
|
COMPREPLY=()
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
if [[ "$cur" =~ ^-|\+ ]]; then
|
|
COMPREPLY=( $(compgen -W "${opts}" -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
_fzf_handle_dynamic_completion() {
|
|
local cmd orig_var orig ret orig_cmd orig_complete
|
|
cmd="$1"
|
|
shift
|
|
orig_cmd="$1"
|
|
orig_var="_fzf_orig_completion_$cmd"
|
|
orig="${!orig_var##*#}"
|
|
if [ -n "$orig" ] && type "$orig" > /dev/null 2>&1; then
|
|
$orig "$@"
|
|
elif [ -n "$_fzf_completion_loader" ]; then
|
|
orig_complete=$(complete -p "$cmd" 2> /dev/null)
|
|
_completion_loader "$@"
|
|
ret=$?
|
|
# _completion_loader may not have updated completion for the command
|
|
if [ "$(complete -p "$cmd" 2> /dev/null)" != "$orig_complete" ]; then
|
|
eval "$(complete | command grep " -F.* $orig_cmd$" | __fzf_orig_completion_filter)"
|
|
if [[ "$__fzf_nospace_commands" = *" $orig_cmd "* ]]; then
|
|
eval "${orig_complete/ -F / -o nospace -F }"
|
|
else
|
|
eval "$orig_complete"
|
|
fi
|
|
fi
|
|
return $ret
|
|
fi
|
|
}
|
|
|
|
__fzf_generic_path_completion() {
|
|
local cur base dir leftover matches trigger cmd fzf
|
|
fzf="$(__fzfcmd_complete)"
|
|
cmd="${COMP_WORDS[0]//[^A-Za-z0-9_=]/_}"
|
|
COMPREPLY=()
|
|
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
|
if [[ "$cur" == *"$trigger" ]]; then
|
|
base=${cur:0:${#cur}-${#trigger}}
|
|
eval "base=$base"
|
|
|
|
[[ $base = *"/"* ]] && dir="$base"
|
|
while true; do
|
|
if [ -z "$dir" ] || [ -d "$dir" ]; then
|
|
leftover=${base/#"$dir"}
|
|
leftover=${leftover/#\/}
|
|
[ -z "$dir" ] && dir='.'
|
|
[ "$dir" != "/" ] && dir="${dir/%\//}"
|
|
matches=$(eval "$1 $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS" $fzf $2 -q "$leftover" | while read -r item; do
|
|
printf "%q$3 " "$item"
|
|
done)
|
|
matches=${matches% }
|
|
[[ -z "$3" ]] && [[ "$__fzf_nospace_commands" = *" ${COMP_WORDS[0]} "* ]] && matches="$matches "
|
|
if [ -n "$matches" ]; then
|
|
COMPREPLY=( "$matches" )
|
|
else
|
|
COMPREPLY=( "$cur" )
|
|
fi
|
|
printf '\e[5n'
|
|
return 0
|
|
fi
|
|
dir=$(dirname "$dir")
|
|
[[ "$dir" =~ /$ ]] || dir="$dir"/
|
|
done
|
|
else
|
|
shift
|
|
shift
|
|
shift
|
|
_fzf_handle_dynamic_completion "$cmd" "$@"
|
|
fi
|
|
}
|
|
|
|
_fzf_complete() {
|
|
local cur selected trigger cmd fzf post
|
|
post="$(caller 0 | awk '{print $2}')_post"
|
|
type -t "$post" > /dev/null 2>&1 || post=cat
|
|
fzf="$(__fzfcmd_complete)"
|
|
|
|
cmd="${COMP_WORDS[0]//[^A-Za-z0-9_=]/_}"
|
|
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
|
if [[ "$cur" == *"$trigger" ]]; then
|
|
cur=${cur:0:${#cur}-${#trigger}}
|
|
|
|
selected=$(cat | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS" $fzf $1 -q "$cur" | $post | tr '\n' ' ')
|
|
selected=${selected% } # Strip trailing space not to repeat "-o nospace"
|
|
printf '\e[5n'
|
|
|
|
if [ -n "$selected" ]; then
|
|
COMPREPLY=("$selected")
|
|
return 0
|
|
fi
|
|
else
|
|
shift
|
|
_fzf_handle_dynamic_completion "$cmd" "$@"
|
|
fi
|
|
}
|
|
|
|
_fzf_path_completion() {
|
|
__fzf_generic_path_completion _fzf_compgen_path "-m" "" "$@"
|
|
}
|
|
|
|
# Deprecated. No file only completion.
|
|
_fzf_file_completion() {
|
|
_fzf_path_completion "$@"
|
|
}
|
|
|
|
_fzf_dir_completion() {
|
|
__fzf_generic_path_completion _fzf_compgen_dir "" "/" "$@"
|
|
}
|
|
|
|
_fzf_complete_kill() {
|
|
[ -n "${COMP_WORDS[COMP_CWORD]}" ] && return 1
|
|
|
|
local selected fzf
|
|
fzf="$(__fzfcmd_complete)"
|
|
selected=$(command ps -ef | sed 1d | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-50%} --min-height 15 --reverse $FZF_DEFAULT_OPTS --preview 'echo {}' --preview-window down:3:wrap $FZF_COMPLETION_OPTS" $fzf -m | awk '{print $2}' | tr '\n' ' ')
|
|
printf '\e[5n'
|
|
|
|
if [ -n "$selected" ]; then
|
|
COMPREPLY=( "$selected" )
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
_fzf_complete_telnet() {
|
|
_fzf_complete '+m' "$@" < <(
|
|
command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0' |
|
|
awk '{if (length($2) > 0) {print $2}}' | sort -u
|
|
)
|
|
}
|
|
|
|
_fzf_complete_ssh() {
|
|
_fzf_complete '+m' "$@" < <(
|
|
cat <(cat ~/.ssh/config /etc/ssh/ssh_config 2> /dev/null | command grep -i '^host ' | command grep -v '[*?]' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}') \
|
|
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
|
|
<(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
|
|
awk '{if (length($2) > 0) {print $2}}' | sort -u
|
|
)
|
|
}
|
|
|
|
_fzf_complete_unset() {
|
|
_fzf_complete '-m' "$@" < <(
|
|
declare -xp | sed 's/=.*//' | sed 's/.* //'
|
|
)
|
|
}
|
|
|
|
_fzf_complete_export() {
|
|
_fzf_complete '-m' "$@" < <(
|
|
declare -xp | sed 's/=.*//' | sed 's/.* //'
|
|
)
|
|
}
|
|
|
|
_fzf_complete_unalias() {
|
|
_fzf_complete '-m' "$@" < <(
|
|
alias | sed 's/=.*//' | sed 's/.* //'
|
|
)
|
|
}
|
|
|
|
# fzf options
|
|
complete -o default -F _fzf_opts_completion fzf
|
|
|
|
d_cmds="${FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir}"
|
|
a_cmds="
|
|
awk cat diff diff3
|
|
emacs emacsclient ex file ftp g++ gcc gvim head hg java
|
|
javac ld less more mvim nvim patch perl python ruby
|
|
sed sftp sort source tail tee uniq vi view vim wc xdg-open
|
|
basename bunzip2 bzip2 chmod chown curl cp dirname du
|
|
find git grep gunzip gzip hg jar
|
|
ln ls mv open rm rsync scp
|
|
svn tar unzip zip"
|
|
x_cmds="kill ssh telnet unset unalias export"
|
|
|
|
# Preserve existing completion
|
|
eval "$(complete |
|
|
sed -E '/-F/!d; / _fzf/d; '"/ ($(echo $d_cmds $a_cmds $x_cmds | sed 's/ /|/g; s/+/\\+/g'))$/"'!d' |
|
|
__fzf_orig_completion_filter)"
|
|
|
|
if type _completion_loader > /dev/null 2>&1; then
|
|
_fzf_completion_loader=1
|
|
fi
|
|
|
|
_fzf_defc() {
|
|
local cmd func opts orig_var orig def
|
|
cmd="$1"
|
|
func="$2"
|
|
opts="$3"
|
|
orig_var="_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}"
|
|
orig="${!orig_var}"
|
|
if [ -n "$orig" ]; then
|
|
printf -v def "$orig" "$func"
|
|
eval "$def"
|
|
else
|
|
complete -F "$func" $opts "$cmd"
|
|
fi
|
|
}
|
|
|
|
# Anything
|
|
for cmd in $a_cmds; do
|
|
_fzf_defc "$cmd" _fzf_path_completion "-o default -o bashdefault"
|
|
done
|
|
|
|
# Directory
|
|
for cmd in $d_cmds; do
|
|
_fzf_defc "$cmd" _fzf_dir_completion "-o nospace -o dirnames"
|
|
done
|
|
|
|
unset _fzf_defc
|
|
|
|
# Kill completion
|
|
complete -F _fzf_complete_kill -o nospace -o default -o bashdefault kill
|
|
|
|
# Host completion
|
|
complete -F _fzf_complete_ssh -o default -o bashdefault ssh
|
|
complete -F _fzf_complete_telnet -o default -o bashdefault telnet
|
|
|
|
# Environment variables / Aliases
|
|
complete -F _fzf_complete_unset -o default -o bashdefault unset
|
|
complete -F _fzf_complete_export -o default -o bashdefault export
|
|
complete -F _fzf_complete_unalias -o default -o bashdefault unalias
|
|
|
|
unset cmd d_cmds a_cmds x_cmds
|