From 653461675a42a52d0ca2295cb033e460f302eefb Mon Sep 17 00:00:00 2001 From: wxiwnd Date: Thu, 4 Dec 2025 21:33:22 +0800 Subject: [PATCH 1/2] feat: support _comp_complete_minimal completion Signed-off-by: wxiwnd --- scripts/bash_pinyin_completion | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/scripts/bash_pinyin_completion b/scripts/bash_pinyin_completion index b5990b6..d8f2314 100644 --- a/scripts/bash_pinyin_completion +++ b/scripts/bash_pinyin_completion @@ -12,6 +12,27 @@ fi # Backup the original function eval "function __bak_comp_compgen__call_builtin() { $(declare -f _comp_compgen__call_builtin | tail -n +2) }" +# When Bash falls back to the minimal default completion handler (typically +# triggered for commands invoked via path prefixes such as ./foo or ../bar), +# bash-completion stops before calling compgen and our pinyin hook never runs. +# Wrap that fallback so path-based commands still go through _filedir and, in +# turn, our enhanced matcher. +if declare -F _comp_complete_minimal &>/dev/null && \ + ! declare -F __bak_comp_complete_minimal &>/dev/null; then + eval "function __bak_comp_complete_minimal() { $(declare -f _comp_complete_minimal | tail -n +2) }" + + _comp_complete_minimal() { + if [[ ${COMP_WORDS[0]+_} ]] && [[ ${COMP_WORDS[0]} == */* ]]; then + local cur prev words cword comp_args + _comp_initialize -- "$@" || return + _filedir + return + fi + + __bak_comp_complete_minimal "$@" + } +fi + # Expand environment references ("$VAR", "${VAR}") inside completion prefixes __expand_env_refs() { local input="$1" From 1240db5007ad4d2ceb573fc8282632166acc11cf Mon Sep 17 00:00:00 2001 From: wxiwnd Date: Sat, 6 Dec 2025 15:59:54 +0800 Subject: [PATCH 2/2] feat: support _comp_xfunc _comp_local* completion(scp, sftp) Signed-off-by: wxiwnd --- scripts/bash_pinyin_completion | 64 +++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/scripts/bash_pinyin_completion b/scripts/bash_pinyin_completion index d8f2314..27d5c02 100644 --- a/scripts/bash_pinyin_completion +++ b/scripts/bash_pinyin_completion @@ -33,6 +33,53 @@ if declare -F _comp_complete_minimal &>/dev/null && \ } fi +# Decide whether a generator invoked via _comp_xfunc appears to provide +# local filesystem candidates. +_pinyin_is_local_file_generator() { + local generator="$1" + [[ -z "$generator" ]] && return 1 + + case "$generator" in + compgen_local_files|compgen_local_dirs|compgen_local_filedirs|compgen_filedir|compgen_filedirs) + return 0 ;; + compgen_local_*|*_local_files|*_local_dirs) + return 0 ;; + esac + + [[ "$generator" == *local*file* ]] && return 0 + [[ "$generator" == *file*local* ]] && return 0 + + return 1 +} + +# Hook _comp_xfunc so any command-level generator that looks like it enumerates +# local files automatically benefits from the pinyin matcher. +if declare -F _comp_xfunc &>/dev/null && \ + ! declare -F __bak_comp_xfunc &>/dev/null; then + eval "function __bak_comp_xfunc() { $(declare -f _comp_xfunc | tail -n +2) }" + + _comp_xfunc() { + local -a __pinyin_args=("$@") + __bak_comp_xfunc "${__pinyin_args[@]}" + local status=$? + + local generator="${__pinyin_args[1]-}" + if _pinyin_is_local_file_generator "$generator"; then + local -a dir_flag=() + local arg + for arg in "${__pinyin_args[@]:2}"; do + if [[ "$arg" == "-d" ]]; then + dir_flag=('-d') + break + fi + done + _add_completion "${dir_flag[@]}" + fi + + return $status + } +fi + # Expand environment references ("$VAR", "${VAR}") inside completion prefixes __expand_env_refs() { local input="$1" @@ -196,7 +243,13 @@ _add_completion() { # cur: bash-completion's working value for the current word. local cur - eval "cur=${_cur}" + if [[ -n ${_cur-} ]]; then + eval "cur=${_cur}" + elif [[ -n ${COMP_WORDS+x} && -n ${COMP_CWORD+x} ]]; then + cur="${COMP_WORDS[COMP_CWORD]-}" + else + return + fi # origin_cur: the user's raw buffer text before any expansion # including quotes or ~user prefixes. in other word, "snapshot". local orig_cur="$cur" @@ -215,12 +268,13 @@ _add_completion() { fi # Check if we have the necessary variables - if [[ -z "${_cur-}" ]] || [[ -z "${_var-}" ]]; then - return + local var_name + if [[ -n ${_var-} ]]; then + var_name="$_var" + else + var_name="COMPREPLY" fi - local var_name="$_var" - # Skip empty [[ -z "$cur" ]] && return