Back in 2012 I argued [1] for the introduction of a helper that would allow users to specify aliases like: git_complete gf git_fetch Back then there was pushback because there was no clear guideline for public functions (git_complete vs _git_complete vs _GIT_complete), and some aliases didn't actually work. Fast-forward to 2020 and there's still no guideline for public functions, and those aliases still don't work (even though I sent the fixes). This has not prevented people from using this function that is clearly needed to setup custom aliases [2], and in fact it's the recommended way. But it is cumbersome that the user must type: __git_complete gf _git_fetch Or worse: __git_complete gk __gitk_main 8 years is more than enough time to stop waiting for the perfect to come; let's define a public function (with the same name) that is actually user-friendly: __git_complete gf git_fetch __git_complete gk gitk While also maintaining backwards compatibility. The logic is: 1. If $2 exists, use it directly 2. If not, check if __$2_main exists 3. If not, check if _$2 exists 4. If not, fail [1] https://lore.kernel.org/git/1334524814-13581-1-git-send-email-felipe.contreras@xxxxxxxxx/ [2] https://stackoverflow.com/questions/342969/how-do-i-get-bash-completion-to-work-with-aliases Signed-off-by: Felipe Contreras <felipe.contreras@xxxxxxxxx> --- contrib/completion/git-completion.bash | 31 ++++++++++++++++++++------ t/t9902-completion.sh | 15 ++++++++++++- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 463a3124da..6b0432a72d 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -3493,10 +3493,7 @@ __git_func_wrap () $1 } -# Setup completion for certain functions defined above by setting common -# variables and workarounds. -# This is NOT a public function; use at your own risk. -__git_complete () +___git_complete () { local wrapper="__git_wrap${2}" eval "$wrapper () { __git_func_wrap $2 ; }" @@ -3504,13 +3501,33 @@ __git_complete () || complete -o default -o nospace -F $wrapper $1 } -__git_complete git __git_main -__git_complete gitk __gitk_main +# Setup the completion for git commands +# 1: command or alias +# 2: function to call (e.g. `git`, `gitk`, `git_fetch`) +__git_complete () +{ + local func + + if [[ "$(type -t $2)" == function ]]; then + func=$2 + elif [[ "$(type -t __$2_main)" == function ]]; then + func=__$2_main + elif [[ "$(type -t _$2)" == function ]]; then + func=_$2 + else + echo "ERROR: could not find function '$2'" 1>&2 + return 1 + fi + ___git_complete $1 $func +} + +___git_complete git __git_main +___git_complete gitk __gitk_main # The following are necessary only for Cygwin, and only are needed # when the user has tab-completed the executable name and consequently # included the '.exe' suffix. # if [ "$OSTYPE" = cygwin ]; then - __git_complete git.exe __git_main + ___git_complete git.exe __git_main fi diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 2e59fe4de0..53669a36f1 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -2381,10 +2381,23 @@ test_expect_success 'sourcing the completion script clears cached --options' ' ' test_expect_success '__git_complete' ' + unset -f __git_wrap__git_main && + __git_complete foo __git_main && test "$(type -t __git_wrap__git_main)" == function && + unset -f __git_wrap__git_main && + __git_complete gf _git_fetch && - test "$(type -t __git_wrap_git_fetch)" == function + test "$(type -t __git_wrap_git_fetch)" == function && + + __git_complete foo git && + test "$(type -t __git_wrap__git_main)" == function && + unset -f __git_wrap__git_main && + + __git_complete gd git_diff && + test "$(type -t __git_wrap_git_diff)" == function && + + test_must_fail __git_complete ga missing ' test_done -- 2.30.0.rc2