From 6a89b6c8e710758bb35b26afdb5e9f4f0ddab590 Mon Sep 17 00:00:00 2001 From: pika Date: Sun, 18 Aug 2024 02:42:53 +0200 Subject: [PATCH] addet fzf --- .bashrc | 24 +- .fzf.bash | 599 --------------------------------------- fzf-bash-completion.sh | 622 ----------------------------------------- 3 files changed, 22 insertions(+), 1223 deletions(-) delete mode 100644 .fzf.bash delete mode 100644 fzf-bash-completion.sh diff --git a/.bashrc b/.bashrc index f603e6e..2ae6568 100644 --- a/.bashrc +++ b/.bashrc @@ -217,16 +217,35 @@ _cli_qol_() { curl -s https://ohmyposh.dev/install.sh | sudo bash -s -- -d /usr/bin/ fi +} + +_fzf_(){ # ─< Setup fzf >────────────────────────────────────────────────────────────────────────── if [[ ! "$PATH" == */usr/share/doc/fzf/examples* ]]; then export PATH="${PATH:+${PATH}:}/usr/share/doc/fzf/examples" fi - # ─< Auto-completion >──────────────────────────────────────────────────────────────────── [[ $- == *i* ]] && source "/usr/share/doc/fzf/examples/completion.bash" 2> /dev/null # ─< Key bindings >─────────────────────────────────────────────────────────────────────── -source "/usr/share/doc/fzf/examples/key-bindings.bash" +source /usr/share/doc/fzf/examples/completion.bash +source /usr/share/doc/fzf/examples/key-bindings.bash +# ─< Use fzf for completion >───────────────────────────────────────────────────────────── +# Use fzf for enhanced completion +_fzf_comprun() { + local command=$1 + shift + case "$command" in + cd) fzf --preview 'tree -C {} | head -200' "$@" ;; + export|unset) fzf --preview "eval 'echo \$'{}" "$@" ;; + ssh) fzf --preview 'dig {}' "$@" ;; + *) fzf --preview 'bat -n --color=always {}' "$@" ;; + esac +} + +# Use fzf-completion with TAB +bind -x '"\t": fzf-completion' +bind -x '"\C-i": fzf-completion' } # ─< t stands for trash(-cli) >─────────────────────────────────────────────────────────────── @@ -463,6 +482,7 @@ get_alias() { _defaults_ _color_prompt_ _cli_qol_ + _fzf_ _cat_ _trash _nmap_ diff --git a/.fzf.bash b/.fzf.bash deleted file mode 100644 index 38e7202..0000000 --- a/.fzf.bash +++ /dev/null @@ -1,599 +0,0 @@ -# ____ ____ -# / __/___ / __/ -# / /_/_ / / /_ -# / __/ / /_/ __/ -# /_/ /___/_/ completion.bash -# -# - $FZF_TMUX (default: 0) -# - $FZF_TMUX_OPTS (default: empty) -# - $FZF_COMPLETION_TRIGGER (default: '**') -# - $FZF_COMPLETION_OPTS (default: empty) -# - $FZF_COMPLETION_PATH_OPTS (default: empty) -# - $FZF_COMPLETION_DIR_OPTS (default: empty) - -if [[ $- =~ i ]]; then - - -# To use custom commands instead of find, override _fzf_compgen_{path,dir} -# -# _fzf_compgen_path() { -# echo "$1" -# command find -L "$1" \ -# -name .git -prune -o -name .hg -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \ -# -a -not -path "$1" -print 2> /dev/null | command sed 's@^\./@@' -# } -# -# _fzf_compgen_dir() { -# command find -L "$1" \ -# -name .git -prune -o -name .hg -prune -o -name .svn -prune -o -type d \ -# -a -not -path "$1" -print 2> /dev/null | command sed 's@^\./@@' -# } - -########################################################### - -# To redraw line after fzf closes (printf '\e[5n') -bind '"\e[0n": redraw-current-line' 2> /dev/null - -__fzf_defaults() { - # $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS - # $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS - echo "--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore $1" - command cat "${FZF_DEFAULT_OPTS_FILE-}" 2> /dev/null - echo "${FZF_DEFAULT_OPTS-} $2" -} - -__fzf_comprun() { - if [[ "$(type -t _fzf_comprun 2>&1)" = function ]]; then - _fzf_comprun "$@" - elif [[ -n "${TMUX_PANE-}" ]] && { [[ "${FZF_TMUX:-0}" != 0 ]] || [[ -n "${FZF_TMUX_OPTS-}" ]]; }; then - shift - fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- "$@" - else - shift - fzf "$@" - fi -} - -__fzf_orig_completion() { - local l comp f cmd - while read -r l; do - if [[ "$l" =~ ^(.*\ -F)\ *([^ ]*).*\ ([^ ]*)$ ]]; then - comp="${BASH_REMATCH[1]}" - f="${BASH_REMATCH[2]}" - cmd="${BASH_REMATCH[3]}" - [[ "$f" = _fzf_* ]] && continue - printf -v "_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}" "%s" "${comp} %s ${cmd} #${f}" - if [[ "$l" = *" -o nospace "* ]] && [[ ! "${__fzf_nospace_commands-}" = *" $cmd "* ]]; then - __fzf_nospace_commands="${__fzf_nospace_commands-} $cmd " - fi - fi - done -} - -# @param $1 cmd - Command name for which the original completion is searched -# @var[out] REPLY - Original function name is returned -__fzf_orig_completion_get_orig_func() { - local cmd orig_var orig - cmd=$1 - orig_var="_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}" - orig="${!orig_var-}" - REPLY="${orig##*#}" - [[ $REPLY ]] && type "$REPLY" &> /dev/null -} - -# @param $1 cmd - Command name for which the original completion is searched -# @param $2 func - Fzf's completion function to replace the original function -# @var[out] REPLY - Completion setting is returned as a string to "eval" -__fzf_orig_completion_instantiate() { - local cmd func orig_var orig - cmd=$1 - func=$2 - orig_var="_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}" - orig="${!orig_var-}" - orig="${orig%#*}" - [[ $orig == *' %s '* ]] || return 1 - printf -v REPLY "$orig" "$func" -} - -_fzf_opts_completion() { - local cur prev opts - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - opts=" - +c --no-color - +i --no-ignore-case - +s --no-sort - +x --no-extended - --ansi - --bash - --bind - --border - --border-label - --border-label-pos - --color - --cycle - --disabled - --ellipsis - --expect - --filepath-word - --fish - --header - --header-first - --header-lines - --height - --highlight-line - --history - --history-size - --hscroll-off - --info - --jump-labels - --keep-right - --layout - --listen - --listen-unsafe - --literal - --man - --margin - --marker - --min-height - --no-bold - --no-clear - --no-hscroll - --no-mouse - --no-scrollbar - --no-separator - --no-unicode - --padding - --pointer - --preview - --preview-label - --preview-label-pos - --preview-window - --print-query - --print0 - --prompt - --read0 - --reverse - --scheme - --scroll-off - --separator - --sync - --tabstop - --tac - --tiebreak - --tmux - --track - --version - --with-nth - --with-shell - --wrap - --zsh - -0 --exit-0 - -1 --select-1 - -d --delimiter - -e --exact - -f --filter - -h --help - -i --ignore-case - -m --multi - -n --nth - -q --query - --" - - case "${prev}" in - --scheme) - COMPREPLY=( $(compgen -W "default path history" -- "$cur") ) - return 0 - ;; - --tiebreak) - COMPREPLY=( $(compgen -W "length chunk begin end index" -- "$cur") ) - return 0 - ;; - --color) - COMPREPLY=( $(compgen -W "dark light 16 bw no" -- "$cur") ) - return 0 - ;; - --layout) - COMPREPLY=( $(compgen -W "default reverse reverse-list" -- "$cur") ) - return 0 - ;; - --info) - COMPREPLY=( $(compgen -W "default right hidden inline inline-right" -- "$cur") ) - return 0 - ;; - --preview-window) - COMPREPLY=( $(compgen -W " - default - hidden - nohidden - wrap - nowrap - cycle - nocycle - up top - down bottom - left - right - rounded border border-rounded - sharp border-sharp - border-bold - border-block - border-thinblock - border-double - noborder border-none - border-horizontal - border-vertical - border-up border-top - border-down border-bottom - border-left - border-right - follow - nofollow" -- "$cur") ) - return 0 - ;; - --border) - COMPREPLY=( $(compgen -W "rounded sharp bold block thinblock double horizontal vertical top bottom left right none" -- "$cur") ) - return 0 - ;; - --border-label-pos|--preview-label-pos) - COMPREPLY=( $(compgen -W "center bottom top" -- "$cur") ) - return 0 - ;; - esac - - if [[ "$cur" =~ ^-|\+ ]]; then - COMPREPLY=( $(compgen -W "${opts}" -- "$cur") ) - return 0 - fi - - return 0 -} - -_fzf_handle_dynamic_completion() { - local cmd ret REPLY orig_cmd orig_complete - cmd="$1" - shift - orig_cmd="$1" - if __fzf_orig_completion_get_orig_func "$cmd"; then - "$REPLY" "$@" - elif [[ -n "${_fzf_completion_loader-}" ]]; then - orig_complete=$(complete -p "$orig_cmd" 2> /dev/null) - $_fzf_completion_loader "$@" - ret=$? - # _completion_loader may not have updated completion for the command - if [[ "$(complete -p "$orig_cmd" 2> /dev/null)" != "$orig_complete" ]]; then - __fzf_orig_completion < <(complete -p "$orig_cmd" 2> /dev/null) - - # Update orig_complete by _fzf_orig_completion entry - [[ $orig_complete =~ ' -F '(_fzf_[^ ]+)' ' ]] && - __fzf_orig_completion_instantiate "$cmd" "${BASH_REMATCH[1]}" && - orig_complete=$REPLY - - if [[ "${__fzf_nospace_commands-}" = *" $orig_cmd "* ]]; then - eval "${orig_complete/ -F / -o nospace -F }" - else - eval "$orig_complete" - fi - fi - [[ $ret -eq 0 ]] && return 124 - return $ret - fi -} - -__fzf_generic_path_completion() { - local cur base dir leftover matches trigger cmd - cmd="${COMP_WORDS[0]}" - if [[ $cmd == \\* ]]; then - cmd="${cmd:1}" - fi - COMPREPLY=() - trigger=${FZF_COMPLETION_TRIGGER-'**'} - [[ $COMP_CWORD -ge 0 ]] && cur="${COMP_WORDS[COMP_CWORD]}" - if [[ "$cur" == *"$trigger" ]] && [[ $cur != *'$('* ]] && [[ $cur != *':='* ]] && [[ $cur != *'`'* ]]; then - base=${cur:0:${#cur}-${#trigger}} - eval "base=$base" 2> /dev/null || return - - dir= - [[ $base = *"/"* ]] && dir="$base" - while true; do - if [[ -z "$dir" ]] || [[ -d "$dir" ]]; then - leftover=${base/#"$dir"} - leftover=${leftover/#\/} - [[ -z "$dir" ]] && dir='.' - [[ "$dir" != "/" ]] && dir="${dir/%\//}" - matches=$( - export FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --scheme=path" "${FZF_COMPLETION_OPTS-} $2") - unset FZF_DEFAULT_COMMAND FZF_DEFAULT_OPTS_FILE - if declare -F "$1" > /dev/null; then - eval "$1 $(printf %q "$dir")" | __fzf_comprun "$4" -q "$leftover" - else - if [[ $1 =~ dir ]]; then - walker=dir,follow - rest=${FZF_COMPLETION_DIR_OPTS-} - else - walker=file,dir,follow,hidden - rest=${FZF_COMPLETION_PATH_OPTS-} - fi - __fzf_comprun "$4" -q "$leftover" --walker "$walker" --walker-root="$dir" $rest - fi | while read -r item; do - printf "%q " "${item%$3}$3" - 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=$(command dirname "$dir") - [[ "$dir" =~ /$ ]] || dir="$dir"/ - done - else - shift - shift - shift - _fzf_handle_dynamic_completion "$cmd" "$@" - fi -} - -_fzf_complete() { - # Split arguments around -- - local args rest str_arg i sep - args=("$@") - sep= - for i in "${!args[@]}"; do - if [[ "${args[$i]}" = -- ]]; then - sep=$i - break - fi - done - if [[ -n "$sep" ]]; then - str_arg= - rest=("${args[@]:$((sep + 1)):${#args[@]}}") - args=("${args[@]:0:$sep}") - else - str_arg=$1 - args=() - shift - rest=("$@") - fi - - local cur selected trigger cmd post - post="$(caller 0 | command awk '{print $2}')_post" - type -t "$post" > /dev/null 2>&1 || post='command cat' - - trigger=${FZF_COMPLETION_TRIGGER-'**'} - cmd="${COMP_WORDS[0]}" - cur="${COMP_WORDS[COMP_CWORD]}" - if [[ "$cur" == *"$trigger" ]] && [[ $cur != *'$('* ]] && [[ $cur != *':='* ]] && [[ $cur != *'`'* ]]; then - cur=${cur:0:${#cur}-${#trigger}} - - selected=$( - FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse" "${FZF_COMPLETION_OPTS-} $str_arg") \ - FZF_DEFAULT_OPTS_FILE='' \ - __fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | $post | command tr '\n' ' ') - selected=${selected% } # Strip trailing space not to repeat "-o nospace" - if [[ -n "$selected" ]]; then - COMPREPLY=("$selected") - else - COMPREPLY=("$cur") - fi - printf '\e[5n' - return 0 - else - _fzf_handle_dynamic_completion "$cmd" "${rest[@]}" - 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() { - _fzf_proc_completion "$@" -} - -_fzf_proc_completion() { - _fzf_complete -m --header-lines=1 --no-preview --wrap -- "$@" < <( - command ps -eo user,pid,ppid,start,time,command 2> /dev/null || - command ps -eo user,pid,ppid,time,args 2> /dev/null || # For BusyBox - command ps --everyone --full --windows # For cygwin - ) -} - -_fzf_proc_completion_post() { - command awk '{print $2}' -} - -# To use custom hostname lists, override __fzf_list_hosts. -# The function is expected to print hostnames, one per line as well as in the -# desired sorting and with any duplicates removed, to standard output. -# -# e.g. -# # Use bash-completions’s _known_hosts_real() for getting the list of hosts -# __fzf_list_hosts() { -# # Set the local attribute for any non-local variable that is set by _known_hosts_real() -# local COMPREPLY=() -# _known_hosts_real '' -# printf '%s\n' "${COMPREPLY[@]}" | command sort -u --version-sort -# } -if ! declare -F __fzf_list_hosts > /dev/null; then - __fzf_list_hosts() { - command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | command awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?%]') \ - <(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts 2> /dev/null | command tr ',' '\n' | command tr -d '[' | command awk '{ print $1 " " $1 }') \ - <(command grep -v '^\s*\(#\|$\)' /etc/hosts 2> /dev/null | command grep -Fv '0.0.0.0' | command sed 's/#.*//') | - command awk '{for (i = 2; i <= NF; i++) print $i}' | command sort -u - } -fi - -_fzf_host_completion() { - _fzf_complete +m -- "$@" < <(__fzf_list_hosts) -} - -# Values for $1 $2 $3 are described here -# https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html -# > the first argument ($1) is the name of the command whose arguments are being completed, -# > the second argument ($2) is the word being completed, -# > and the third argument ($3) is the word preceding the word being completed on the current command line. -_fzf_complete_ssh() { - case $3 in - -i|-F|-E) - _fzf_path_completion "$@" - ;; - *) - local user= - [[ "$2" =~ '@' ]] && user="${2%%@*}@" - _fzf_complete +m -- "$@" < <(__fzf_list_hosts | command awk -v user="$user" '{print user $0}') - ;; - esac -} - -_fzf_var_completion() { - _fzf_complete -m -- "$@" < <( - declare -xp | command sed -En 's|^declare [^ ]+ ([^=]+).*|\1|p' - ) -} - -_fzf_alias_completion() { - _fzf_complete -m -- "$@" < <( - alias | command sed -En 's|^alias ([^=]+).*|\1|p' - ) -} - -# fzf options -complete -o default -F _fzf_opts_completion fzf -# fzf-tmux is a thin fzf wrapper that has only a few more options than fzf -# itself. As a quick improvement we take fzf's completion. Adding the few extra -# fzf-tmux specific options (like `-w WIDTH`) are left as a future patch. -complete -o default -F _fzf_opts_completion fzf-tmux - -# Default path completion -__fzf_default_completion() { - __fzf_generic_path_completion _fzf_compgen_path "-m" "" "$@" - - # Dynamic completion loader has updated the completion for the command - if [[ $? -eq 124 ]]; then - # We trigger _fzf_setup_completion so that fuzzy completion for the command - # still works. However, loader can update the completion for multiple - # commands at once, and fuzzy completion will no longer work for those - # other commands. e.g. pytest -> py.test, pytest-2, pytest-3, etc - _fzf_setup_completion path "$1" - return 124 - fi -} - -if complete | command grep -q __fzf_default_completion; then - : # Default completion already set up. Do nothing. -elif ! complete | command grep -- '-D$' | command grep -qv _comp_complete_load && - complete -D -F __fzf_default_completion -o default -o bashdefault 2> /dev/null; then - a_cmds="" -else - # We can't set up default completion, - # 1. if it's already set up by another script - # 2. or if the current version of bash doesn't support -D option - # - # NOTE: $FZF_COMPLETION_PATH_COMMANDS and $FZF_COMPLETION_VAR_COMMANDS are - # undocumented and subject to change in the future. - a_cmds="${FZF_COMPLETION_PATH_COMMANDS-" - awk bat cat code diff diff3 - emacs emacsclient ex file ftp g++ gcc gvim head hg hx 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"}" -fi - -d_cmds="${FZF_COMPLETION_DIR_COMMANDS-cd pushd rmdir}" - -v_cmds="${FZF_COMPLETION_VAR_COMMANDS-export unset printenv}" - -# Preserve existing completion -__fzf_orig_completion < <(complete -p $d_cmds $a_cmds $v_cmds unalias kill ssh 2> /dev/null) - -if type _comp_load > /dev/null 2>&1; then - # _comp_load was added in bash-completion 2.12 to replace _completion_loader. - # We use it without -D option so that it does not use _comp_complete_minimal as the fallback. - _fzf_completion_loader=_comp_load -elif type __load_completion > /dev/null 2>&1; then - # In bash-completion 2.11, _completion_loader internally calls __load_completion - # and if it returns a non-zero status, it sets the default 'minimal' completion. - _fzf_completion_loader=__load_completion -elif type _completion_loader > /dev/null 2>&1; then - _fzf_completion_loader=_completion_loader -fi - -__fzf_defc() { - local cmd func opts REPLY - cmd="$1" - func="$2" - opts="$3" - if __fzf_orig_completion_instantiate "$cmd" "$func"; then - eval "$REPLY" - 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 bashdefault -o nospace -o dirnames" -done - -# Variables -for cmd in $v_cmds; do - __fzf_defc "$cmd" _fzf_var_completion "-o default -o nospace -v" -done - -# Aliases -__fzf_defc unalias _fzf_alias_completion "-a" - -# Processes -__fzf_defc kill _fzf_proc_completion "-o default -o bashdefault" - -# ssh -__fzf_defc ssh _fzf_complete_ssh "-o default -o bashdefault" - -unset cmd d_cmds a_cmds v_cmds - -_fzf_setup_completion() { - local kind fn cmd - kind=$1 - fn=_fzf_${1}_completion - if [[ $# -lt 2 ]] || ! type -t "$fn" > /dev/null; then - echo "usage: ${FUNCNAME[0]} path|dir|var|alias|host|proc COMMANDS..." - return 1 - fi - shift - __fzf_orig_completion < <(complete -p "$@" 2> /dev/null) - for cmd in "$@"; do - case "$kind" in - dir) __fzf_defc "$cmd" "$fn" "-o nospace -o dirnames" ;; - var) __fzf_defc "$cmd" "$fn" "-o default -o nospace -v" ;; - alias) __fzf_defc "$cmd" "$fn" "-a" ;; - *) __fzf_defc "$cmd" "$fn" "-o default -o bashdefault" ;; - esac - done -} - -fi diff --git a/fzf-bash-completion.sh b/fzf-bash-completion.sh deleted file mode 100644 index e7a10fd..0000000 --- a/fzf-bash-completion.sh +++ /dev/null @@ -1,622 +0,0 @@ -_FZF_COMPLETION_SEP=$'\x01' - -# shell parsing stuff -_fzf_bash_completion_awk="$(builtin command -v gawk &>/dev/null && echo gawk || echo awk)" -_fzf_bash_completion_sed="$(builtin command -v gsed &>/dev/null && echo gsed || echo sed)" -_fzf_bash_completion_grep="$(builtin command -v ggrep &>/dev/null && echo ggrep || echo builtin command grep)" - -_fzf_bash_completion_awk_escape() { - "$_fzf_bash_completion_sed" 's/\\/\\\\\\\\/g; s/[[*^$.]/\\\\&/g' <<<"$1" -} - -_fzf_bash_completion_shell_split() { - $_fzf_bash_completion_grep -E -o \ - -e '\|+|&+|<+|>+' \ - -e '[;(){}&\|]' \ - -e '(\\.|\$[-[:alnum:]_*@#?$!]|(\$\{[^}]*(\}|$))|[^$\|"[:space:];(){}&<>'"'${wordbreaks}])+" \ - -e "\\\$'(\\\\.|[^'])*('|$)" \ - -e "'[^']*('|$)" \ - -e '"(\\.|\$($|[^(])|[^"$])*("|$)' \ - -e '".*' \ - -e '[[:space:]]+' \ - -e . -} - -_fzf_bash_completion_unbuffered_awk() { - # need to get awk to be unbuffered either by using -W interactive or system("") - "$_fzf_bash_completion_awk" -W interactive "${@:3}" "$1 { $2; print \$0; system(\"\") }" 2>/dev/null -} - -_fzf_bash_completion_flatten_subshells() { - ( - local count=0 buffer= - while IFS= read -r line; do - case "$line" in - \( | \{) ((count--)) ;; - \) | \}) ((count++)) ;; - esac - - if ((count < 0)); then - return - elif ((count > 0)); then - buffer="$line$buffer" - else - printf '%s\n' "$line$buffer" - buffer= - fi - done < <(tac) - printf '%s\n' "$buffer" - ) | tac -} - -_fzf_bash_completion_find_matching_bracket() { - local count=0 - while IFS=: read -r num bracket; do - if [ "$bracket" = "$1" ]; then - ((count++)) - if ((count > 0)); then - printf '%s\n' "$num" - return 0 - fi - else - ((count--)) - fi - done < <($_fzf_bash_completion_grep -F -e '(' -e ')' -n) - return 1 -} - -_fzf_bash_completion_parse_dq() { - local words="$(cat)" - local last="$(<<<"$words" tail -n1)" - - if [[ "$last" == \"* ]]; then - local line="${last:1}" shell_start string_end joined num - local word= - while true; do - # we are in a double quoted string - - shell_start="$(<<<"$line" $_fzf_bash_completion_grep -E -o '^(\\.|\$[^(]|[^$])*\$\(')" - string_end="$(<<<"$line" $_fzf_bash_completion_grep -E -o '^(\\.|[^"])*"')" - - if ((${#string_end} && (!${#shell_start} || ${#string_end} < ${#shell_start}))); then - # found end of string - line="${line:${#string_end}}" - if ((${#line})); then - printf '%s\n' "${words:0:-${#line}}" - _fzf_bash_completion_parse_line <<<"$line" - else - printf '%s\n' "$words" - fi - return - - elif ((${#shell_start} && (!${#string_end} || ${#shell_start} < ${#string_end}))); then - # found a subshell - - word+="${shell_start:0:-2}" - line="${line:${#shell_start}}" - - split="$(<<<"$line" _fzf_bash_completion_shell_split)" - if ! split="$(_fzf_bash_completion_parse_dq <<<"$split")"; then - # bubble up - printf '%s\n' "$split" - return 1 - fi - if ! num="$(_fzf_bash_completion_find_matching_bracket ')' <<<"$split")"; then - # subshell not closed, this is it - printf '%s\n' "$split" - return 1 - fi - # subshell closed - joined="$(<<<"$split" head -n "$num" | tr -d \\n)" - word+=$'\n$('"$joined"$'\n' - line="${line:${#joined}}" - - else - # the whole line is an incomplete string - break - fi - done - fi - printf '%s\n' "$words" -} - -_fzf_bash_completion_unquote_strings() { - local line - while IFS= read -r line; do - if [[ "$line" =~ ^\'[^\']*\'?$ ]]; then - # single quoted with no single quotes inside - line="${line%%\'}" - printf '%s\n' "${line:1}" - elif [[ "$line" =~ ^\"(\\.|[^\"$])*\"?$ ]]; then - # double quoted with all special characters quoted - "$_fzf_bash_completion_sed" -r 's/\\(.)/\1/g' <<<"${line:1-1}" - elif [[ "$line" == *\\* && "$line" =~ ^(\\.|[a-zA-Z0-9_])*$ ]]; then - # all special characters are quoted - "$_fzf_bash_completion_sed" -r 's/\\(.)/\1/g' <<<"$line" - else - # this string is either boring or too complicated to parse - # print as is - printf '%s\n' "$line" - fi - done -} - -_fzf_bash_completion_parse_line() { - _fzf_bash_completion_shell_split | - _fzf_bash_completion_parse_dq | - _fzf_bash_completion_flatten_subshells | - tr \\n \\0 | - "$_fzf_bash_completion_sed" -r "$( - cat <<'EOF' -# collapse newlines -s/\x00\x00/\x00/g; -# leave trailing space -s/\x00(\s*)$/\n\1/; -# A & B -> (A, &, B) -s/([^&\n\x00])&([^&\n\x00])/\1\n\&\n\2/g; -# > B -> (>, B) -s/([\n\x00\z])([<>]+)([^\n\x00])/\1\2\n\3/g; -s/([<>][\n\x00])$/\1\n/; -# clear up until the a keyword starting a new command -# except the last line isn't a keyword, it may be the start of a command -s/^(.*[\x00\n])?(\[\[|case|do|done|elif|else|esac|fi|for|function|if|in|select|then|time|until|while|&|;|&&|\|[|&]?)\x00//; -# remove ENVVAR=VALUE -s/^(\s*[\n\x00]|\w+=[^\n\x00]*[\n\x00])*// -EOF - )" | - tr \\0 \\n -} - -_fzf_bash_completion_compspec() { - if [[ "$2" =~ .*\$(\{?)([A-Za-z0-9_]*)$ ]]; then - printf '%s\n' 'complete -F _fzf_bash_completion_complete_variables' - elif [[ "$COMP_CWORD" == 0 && -z "$2" ]]; then - # If the command word is the empty string (completion attempted at the beginning of an empty line), any compspec defined with the -E option to complete is used. - complete -p -E || { ! shopt -q no_empty_cmd_completion && printf '%s\n' 'complete -F _fzf_bash_completion_complete_commands -E'; } - elif [[ "$COMP_CWORD" == 0 ]]; then - complete -p -I || printf '%s\n' 'complete -F _fzf_bash_completion_complete_commands -I' - else - # If the command word is a full pathname, a compspec for the full pathname is searched for first. If no compspec is found for the full pathname, an attempt is made to find a compspec for the portion following the final slash. If those searches do not result in a compspec, any compspec defined with the -D option to complete is used as the default - complete -p -- "$1" || complete -p -- "${1##*/}" || complete -p -D || printf '%s\n' 'complete -o filenames -F _fzf_bash_completion_fallback_completer' - fi -} - -_fzf_bash_completion_fallback_completer() { - # fallback completion in case no compspecs loaded - if [[ "$1" == \~* && "$1" != */* ]]; then - # complete ~user directories - readarray -t COMPREPLY < <(compgen -P '~' -u -- "${1#\~}") - else - # complete files - readarray -t COMPREPLY < <(compgen -f -- "$1") - fi -} - -_fzf_bash_completion_complete_commands() { - # commands - compopt -o filenames - readarray -t COMPREPLY < <(compgen -abc -- "$2") -} - -_fzf_bash_completion_complete_variables() { - if [[ "$2" =~ .*\$(\{?)([A-Za-z0-9_]*)$ ]]; then - # environment variables - local brace="${BASH_REMATCH[1]}" - local filter="${BASH_REMATCH[2]}" - if [ -n "$filter" ]; then - local prefix="${2::-${#filter}}" - else - local prefix="$2" - fi - readarray -t COMPREPLY < <(compgen -v -P "$prefix" -S "${brace:+\}}" -- "$filter") - fi -} - -_fzf_bash_completion_loading_msg() { - echo 'Loading matches ...' -} - -fzf_bash_completion() { - # bail early if no_empty_cmd_completion - if ! [[ "$READLINE_LINE" =~ [^[:space:]] ]] && shopt -q no_empty_cmd_completion; then - return 1 - fi - - printf '\r' - command tput sc 2>/dev/null || echo -ne "\0337" - printf '%s' "$(_fzf_bash_completion_loading_msg)" - command tput rc 2>/dev/null || echo -ne "\0338" - - local raw_comp_words=() - local COMP_WORDS=() COMP_CWORD COMP_POINT COMP_LINE - local COMP_TYPE=37 # % == indicates menu completion - local line="${READLINE_LINE:0:READLINE_POINT}" - local wordbreaks="$COMP_WORDBREAKS" - wordbreaks="${wordbreaks//[]^]/\\&}" - wordbreaks="${wordbreaks//[[:space:]]/}" - if [[ "$line" =~ [^[:space:]] ]]; then - readarray -t raw_comp_words < <(_fzf_bash_completion_parse_line <<<"$line") - fi - - if [[ ${#raw_comp_words[@]} -gt 1 ]]; then - _fzf_bash_completion_expand_alias "${raw_comp_words[@]}" - fi - readarray -t COMP_WORDS < <(printf '%s\n' "${raw_comp_words[@]}" | _fzf_bash_completion_unquote_strings) - - printf -v COMP_LINE '%s' "${COMP_WORDS[@]}" - COMP_POINT="${#COMP_LINE}" - # remove the ones that just spaces - local i - # iterate in reverse - for ((i = ${#COMP_WORDS[@]} - 2; i >= 0; i--)); do - if ! [[ "${COMP_WORDS[i]}" =~ [^[:space:]] ]]; then - COMP_WORDS=("${COMP_WORDS[@]:0:i}" "${COMP_WORDS[@]:i+1}") - fi - done - # add an extra blank word if last word is just space - if [[ "${#COMP_WORDS[@]}" = 0 ]]; then - COMP_WORDS+=('') - elif ! [[ "${COMP_WORDS[${#COMP_WORDS[@]} - 1]}" =~ [^[:space:]] ]]; then - COMP_WORDS[${#COMP_WORDS[@]} - 1]='' - fi - COMP_CWORD="${#COMP_WORDS[@]}" - ((COMP_CWORD--)) - - local cmd="${COMP_WORDS[0]}" - local prev - if [ "$COMP_CWORD" = 0 ]; then - prev= - else - prev="${COMP_WORDS[COMP_CWORD - 1]}" - fi - local cur="${COMP_WORDS[COMP_CWORD]}" - if [[ "$cur" =~ ^[$wordbreaks]$ ]]; then - cur= - fi - local raw_cur="${cur:+${raw_comp_words[-1]}}" - - local COMPREPLY= - fzf_bash_completer "$cmd" "$cur" "$prev" - if [ -n "$COMPREPLY" ]; then - if [ -n "$raw_cur" ]; then - line="${line::-${#raw_cur}}" - fi - READLINE_LINE="${line}${COMPREPLY}${READLINE_LINE:$READLINE_POINT}" - ((READLINE_POINT += ${#COMPREPLY} - ${#raw_cur})) - fi - - printf '\r' - command tput el 2>/dev/null || echo -ne "\033[K" -} - -_fzf_bash_completion_selector() { - FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS" \ - $(__fzfcmd 2>/dev/null || echo fzf) -1 -0 --prompt "${FZF_TAB_COMPLETION_PROMPT:-> }$line" --nth 2 -d "$_FZF_COMPLETION_SEP" --ansi | - tr -d "$_FZF_COMPLETION_SEP" -} - -_fzf_bash_completion_expand_alias() { - if alias "$1" &>/dev/null; then - value=(${BASH_ALIASES[$1]}) - if [ -n "${value[*]}" -a "${value[0]}" != "$1" ]; then - raw_comp_words=("${value[@]}" "${raw_comp_words[@]:1}") - fi - fi -} - -_fzf_bash_completion_auto_common_prefix() { - if [ "$FZF_COMPLETION_AUTO_COMMON_PREFIX" = true ]; then - local prefix item items prefix_len prefix_is_full input_len i - IFS= read -r prefix && items=("$prefix") || return - prefix_len="${#prefix}" - prefix_is_full=1 # prefix == item - - input_len="$((${#1}))" - - while [ "$prefix_len" != "$input_len" ] && IFS= read -r item && items+=("$item"); do - for ((i = $input_len; i < $prefix_len; i++)); do - if [[ "${item:i:1}" != "${prefix:i:1}" ]]; then - prefix_len="$i" - unset prefix_is_full - break - fi - done - - if [ -z "$prefix_is_full" ] && [ -z "${item:i:1}" ]; then - prefix_is_full=1 - fi - done - - if [ "$prefix_len" != "$input_len" ]; then - if [ "$FZF_COMPLETION_AUTO_COMMON_PREFIX_PART" == true ] || [ "$prefix_is_full" == 1 ]; then - [ "${items[1]}" ] && printf 'compl_nospace=1\n' >&"${__evaled}" # no space if not only one - printf %s\\n "${prefix:0:prefix_len}" - return - fi - fi - - printf %s\\n "${items[@]}" - fi - - cat -} - -fzf_bash_completer() { - local value code - local compl_bashdefault compl_default compl_dirnames compl_filenames compl_noquote compl_nosort compl_nospace compl_plusdirs - - # preload completions in top shell - { complete -p -- "$1" || __load_completion "$1"; } &>/dev/null - local compspec - if ! compspec="$(_fzf_bash_completion_compspec "$@" 2>/dev/null)"; then - return - fi - - eval "$( - local _fzf_sentinel1=b5a0da60-3378-4afd-ba00-bc1c269bef68 - local _fzf_sentinel2=257539ae-7100-4cd8-b822-a1ef35335e88 - ( - set -o pipefail - - # hack: hijack compopt - compopt() { _fzf_bash_completion_compopt "$@"; } - - exec {__evaled}>&1 - coproc ( - ( - # input from tty in case one of the completions wants fzf using $FZF_DEFAULT_COMMAND - exec 32)); then - echo "$1: possible retry loop" >/dev/tty - break - fi - _fzf_bash_completion_complete "$@" - done - printf '%s\n' "$_FZF_COMPLETION_SEP$_fzf_sentinel1$_fzf_sentinel2" - ) | $_fzf_bash_completion_sed -un "/$_fzf_sentinel1$_fzf_sentinel2/q; p" | - _fzf_bash_completion_auto_common_prefix "$raw_cur" | - _fzf_bash_completion_unbuffered_awk '$0!="" && !x[$0]++' '$0 = "\x1b[37m" substr($0, 1, len) "\x1b[0m" sep substr($0, len+1)' -vlen="${#raw_cur}" -vsep="$_FZF_COMPLETION_SEP" - ) - local coproc_pid="$COPROC_PID" - value="$(_fzf_bash_completion_selector "$1" "$raw_cur" "$3" <&"${COPROC[0]}")" - code="$?" - value="$(<<<"$value" tr \\n \ )" - value="${value% }" - - printf 'COMPREPLY=%q\n' "$value" - printf 'code=%q\n' "$code" - - # kill descendant processes of coproc - descend_process() { - printf '%s\n' "$1" - for pid in $(ps -ef | "$_fzf_bash_completion_awk" -v ppid="$1" '$3 == ppid { print $2 }'); do - descend_process "$pid" - done - } - kill -- $(descend_process "$coproc_pid") 2>/dev/null - - printf '%s\n' ": $_fzf_sentinel1$_fzf_sentinel2" - ) | $_fzf_bash_completion_sed -un "/$_fzf_sentinel1$_fzf_sentinel2/q; p" - )" 2>/dev/null - - if [ "$code" = 0 ]; then - COMPREPLY="${COMPREPLY[*]}" - [ "$compl_nospace" != 1 ] && COMPREPLY="$COMPREPLY " - [[ "$compl_filenames" == *1* ]] && COMPREPLY="${COMPREPLY/%\/ //}" - fi -} - -_fzf_bash_completion_complete() { - local compgen_actions=() compspec= - if ! compspec="$(_fzf_bash_completion_compspec "$@" 2>/dev/null)"; then - return - fi - - local args=("$@") - eval "compspec=( $compspec )" - set -- "${compspec[@]}" - shift # remove the complete command - while (($# > 1)); do - case "$1" in - -F) - local compl_function="$2" - shift - ;; - -C) - local compl_command="$2" - shift - ;; - -G) - local compl_globpat="$2" - shift - ;; - -W) - local compl_wordlist="$2" - shift - ;; - -X) - local compl_xfilter="$2" - shift - ;; - -o) - _fzf_bash_completion_compopt -o "$2" - shift - ;; - -A) - local compgen_opts+=("$1" "$2") - shift - ;; - -P) - local compl_prefix="$(_fzf_bash_completion_awk_escape "$2")" - shift - ;; - -S) - local compl_suffix="$(_fzf_bash_completion_awk_escape "$2")" - shift - ;; - -[a-z]) - compgen_actions+=("$1") - ;; - esac - shift - done - set -- "${args[@]}" - - COMPREPLY=() - if [ -n "$compl_function" ]; then - "$compl_function" "$@" >/dev/null - if [ "$?" = 124 ]; then - local newcompspec - if ! newcompspec="$(_fzf_bash_completion_compspec "$@" 2>/dev/null)"; then - return - elif [ "$newcompspec" != "$compspec" ]; then - return 124 - fi - "$compl_function" "$@" >/dev/null - fi - fi - - if [[ "$compl_filenames" == 1 ]]; then - local dir_marker=_fzf_bash_completion_dir_marker - else - local dir_marker=cat - fi - - printf 'compl_filenames=%q\n' "$compl_filenames" >&"${__evaled}" - printf 'compl_noquote=%q\n' "$compl_noquote" >&"${__evaled}" - printf 'compl_nospace=%q\n' "$compl_nospace" >&"${__evaled}" - - ( - ( - if [ -n "${compgen_actions[*]}" ]; then - compgen "${compgen_actions[@]}" -- "$2" - fi - - if [ -n "$compl_globpat" ]; then - printf %s\\n "$compl_globpat" - fi - - if [ -n "$compl_wordlist" ]; then - eval "printf '%s\\n' $compl_wordlist" - fi - - if [ -n "${COMPREPLY[*]}" ]; then - printf %s\\n "${COMPREPLY[@]}" - fi - - if [ -n "$compl_command" ]; then - ( - unset COMP_WORDS COMP_CWORD - export COMP_LINE="$COMP_LINE" COMP_POINT="$COMP_POINT" COMP_KEY="$COMP_KEY" COMP_TYPE="$COMP_TYPE" - eval "$compl_command" - ) - fi - - printf '\n' - ) | _fzf_bash_completion_apply_xfilter "$compl_xfilter" | - _fzf_bash_completion_unbuffered_awk '$0!=""' 'sub(find, replace)' -vfind='.*' -vreplace="$(printf %s "$compl_prefix" | "$_fzf_bash_completion_sed" 's/[&\]/\\&/g')&$(printf %s "$compl_suffix" | "$_fzf_bash_completion_sed" 's/[&\]/\\&/g')" | - if IFS= read -r line || ((${#COMPREPLY[@]})); then - ( - [[ -z "$line" ]] || printf '%s\n' "$line" - cat - ) | _fzf_bash_completion_quote_filenames "$@" - else - # got no results - local compgen_opts=() - [ "$compl_bashdefault" = 1 ] && compgen_opts+=(-o bashdefault) - [ "$compl_default" = 1 ] && compgen_opts+=(-o default) - [ "$compl_dirnames" = 1 ] && compgen_opts+=(-o dirnames) - # don't double invoke fzf - if [ -n "${compgen_opts[*]}" ]; then - # these are all filenames - printf 'compl_filenames=1\n' >&"${__evaled}" - compgen "${compgen_opts[@]}" -- "$2" | - compl_filenames=1 _fzf_bash_completion_quote_filenames "$@" | - _fzf_bash_completion_dir_marker - fi - fi - - if [ "$compl_plusdirs" = 1 ]; then - compgen -o dirnames -- "$2" | - compl_filenames=1 _fzf_bash_completion_quote_filenames "$@" | - _fzf_bash_completion_dir_marker - fi - ) | - "$dir_marker" -} - -_fzf_bash_completion_apply_xfilter() { - if [ -z "$1" ]; then - cat - return - fi - - local pattern line word="$cur" - word="${word//\//\\/}" - word="${word//&/\\&}" - # replace any unescaped & with the word being completed - pattern="$("$_fzf_bash_completion_sed" 's/\(\(^\|[^\]\)\(\\\\\)*\)&/\1'"$word"'/g' <<<"${1:1}")" - - if [ "${1::1}" = ! ]; then - while IFS= read -r line; do [[ "$line" == $pattern ]] && printf '%s\n' "$line"; done - elif [ -n "$1" ]; then - while IFS= read -r line; do [[ "$line" != $pattern ]] && printf '%s\n' "$line"; done - fi -} - -_fzf_bash_completion_dir_marker() { - local line expanded - while IFS= read -r line; do - expanded="$line" - - # adapted from __expand_tilde_by_ref - if [[ "$expanded" == \~* ]]; then - eval "$(printf expanded=~%q "${expanded:1}")" - fi - - if [[ "$compl_noquote" != 1 && "$expanded" == *\\* ]]; then - expanded="$("$_fzf_bash_completion_sed" -r 's/\\(.)/\1/g' <<<"$expanded")" - fi - - [ -d "$expanded" ] && line="${line%/}/" - printf '%s\n' "$line" - done -} - -_fzf_bash_completion_quote_filenames() { - if [ "$compl_noquote" != 1 -a "$compl_filenames" = 1 ]; then - local IFS line - while IFS= read -r line; do - if [ "${line::1}" = '~' ]; then - printf '~%q\n' "${line:1}" - else - printf '%q\n' "$line" - fi - done - else - cat - fi -} - -_fzf_bash_completion_compopt() { - while [ "$#" -gt 0 ]; do - local val - if [ "$1" = -o ]; then - val=1 - elif [ "$1" = +o ]; then - val=0 - else - break - fi - - if [[ "$2" =~ bashdefault|default|dirnames|filenames|noquote|nosort|nospace|plusdirs ]]; then - eval "compl_$2=$val" - fi - shift 2 - done -}