diff --git a/.bashrc b/.bashrc index d51b233..0129df1 100644 --- a/.bashrc +++ b/.bashrc @@ -9,10 +9,10 @@ function echo_info() { echo -e "\033[0;35m${*}\033[0m"; } # for examples # If not running interactively, don't do anything -case $- in -*i*) ;; -*) return ;; -esac +# case $- in +# *i*) ;; +# *) return ;; +# esac _defaults_() { # don't put duplicate lines or lines starting with space in the history. @@ -269,15 +269,6 @@ _cat_() { fi } -_fzf_() { - if command_exists fzf; then - # Set up fzf key bindings and fuzzy completion - eval "$(fzf --bash)" - source ./fzf-bash-completion.sh - bind -x '"\t": fzf_bash_completion' - fi -} - _fetches_() { # ─< fastfetch >──────────────────────────────────────────────────────────────────────────── if command_exists fastfetch; then @@ -289,9 +280,7 @@ _fetches_() { git clone https://git.k4li.de/mirrors/fastfetch.git $HOME/.local/share/fastfetch >/dev/null 2>&1 exec $SHELL fi - clear & - f - alias clear="clear & f" + alias clear="clear & ff" fi } @@ -386,9 +375,11 @@ get_packager() { refresh="nala update" remove="nala remove" purge="nala purge" + search="nala search" alias update="$_sudo $refresh && $_sudo $upgrade" alias install="$_sudo $refresh && $_sudo $install" alias remove="$_sudo $remove && $_sudo $purge && $_sudo $clean" + alias search="$search" elif command_exists apt-get; then PKG="apt-get" install="apt-get install --yes" @@ -397,9 +388,11 @@ get_packager() { clean="apt-get autoremove" remove="apt-get remove" purge="apt-get purge" + search="apt-cache search" alias update="$_sudo $refresh && $_sudo $upgrade" alias install="$_sudo $refresh && $_sudo $install" alias remove="$_sudo $remove && $_sudo $purge && $_sudo $clean" + alias search="$search" fi ;; arch | manjaro | endevouros) @@ -408,16 +401,19 @@ get_packager() { alias install="yay -S --noconfirm" alias update="yay -Syu" alias remove="yay -R" + alias search="yay -Ss" elif command_exists paru; then PKG="paru" alias install="paru -S --noconfirm" alias update="paru -Syu" alias remove="paru -R" + alias search="paru -Ss" elif command_exists pacman; then PKG="pacman" alias install="$_sudo pacman -S --noconfirm" alias update="$_sudo pacman -Syu" alias remove="$_sudo pacman -R" + alias search="$_sudo pacman -Ss" fi ;; fedora | centos) @@ -425,6 +421,7 @@ get_packager() { alias install="dnf install --yes" alias update="dnf update" alias remove="dnf remove" + alias search="dnf search" ;; alpine) PKG="apk" @@ -445,7 +442,6 @@ get_alias() { _color_prompt_ _cli_qol_ _cat_ - # _fzf_ _trash _nmap_ _tmux_ diff --git a/fzf-bash-completion.sh b/fzf-bash-completion.sh index 7e03e8c..e7a10fd 100644 --- a/fzf-bash-completion.sh +++ b/fzf-bash-completion.sh @@ -1,152 +1,153 @@ _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="$(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_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_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 + # 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 + ( + 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 + 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 + 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)" + 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 + 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 '^(\\.|[^"])*"')" + 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 + 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 + elif ((${#shell_start} && (!${#string_end} || ${#shell_start} < ${#string_end}))); then + # found a subshell - word+="${shell_start:0:-2}" - line="${line:${#shell_start}}" + 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}}" + 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" + 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 + 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' + _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 @@ -162,448 +163,460 @@ s/^(.*[\x00\n])?(\[\[|case|do|done|elif|else|esac|fi|for|function|if|in|select|t # remove ENVVAR=VALUE s/^(\s*[\n\x00]|\w+=[^\n\x00]*[\n\x00])*// EOF -)" \ - | tr \\0 \\n + )" | + 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 + 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 + # 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") + # 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") + 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 ...' + 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 + # 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" + 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 + 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) + 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]='' + 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 - COMP_CWORD="${#COMP_WORDS[@]}" - (( COMP_CWORD-- )) + 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 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} )) + 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" + 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_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 + 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 + 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} ))" + 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 + 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 - printf %s\\n "${items[@]}" + 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 - cat + 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 + 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 + # 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 "$( + eval "$( local _fzf_sentinel1=b5a0da60-3378-4afd-ba00-bc1c269bef68 local _fzf_sentinel2=257539ae-7100-4cd8-b822-a1ef35335e88 ( - set -o pipefail + set -o pipefail - # hack: hijack compopt - compopt() { _fzf_bash_completion_compopt "$@"; } + # 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 &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% }" + count=0 + _fzf_bash_completion_complete "$@" + while (($? == 124)); do + ((count++)) + if ((count > 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" + 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 + # 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" + printf '%s\n' ": $_fzf_sentinel1$_fzf_sentinel2" ) | $_fzf_bash_completion_sed -un "/$_fzf_sentinel1$_fzf_sentinel2/q; p" - )" 2>/dev/null + )" 2>/dev/null - if [ "$code" = 0 ]; then - COMPREPLY="${COMPREPLY[*]}" - [ "$compl_nospace" != 1 ] && COMPREPLY="$COMPREPLY " - [[ "$compl_filenames" == *1* ]] && COMPREPLY="${COMPREPLY/%\/ //}" - fi + 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 + 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 - 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[@]}" + if [[ "$compl_filenames" == 1 ]]; then + local dir_marker=_fzf_bash_completion_dir_marker + else + local dir_marker=cat + fi - 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}" + 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 ( - if [ -n "${compgen_actions[*]}" ]; then - compgen "${compgen_actions[@]}" -- "$2" - fi + 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 - 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 + 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 - ) \ - | "$dir_marker" + 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 + 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}")" + 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 + 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" + 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 + # 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 + 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 + [ -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 + 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 + 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 + if [[ "$2" =~ bashdefault|default|dirnames|filenames|noquote|nosort|nospace|plusdirs ]]; then + eval "compl_$2=$val" + fi + shift 2 + done }