From 7f94b78ddabdb49cde32b088ca66b422e7cda628 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 30 Dec 2020 17:29:47 -0600 Subject: [PATCH 1/4] completion: bash: add __git_have_func helper This makes the code more readable, and also will help when new code wants to do similar checks. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 463a3124da..869c73ee2c 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -3358,15 +3358,19 @@ __git_support_parseopt_helper () { esac } +__git_have_func () { + declare -f $1 >/dev/null 2>/dev/null +} + __git_complete_command () { local command="$1" local completion_func="_git_${command//-/_}" - if ! declare -f $completion_func >/dev/null 2>/dev/null && - declare -f _completion_loader >/dev/null 2>/dev/null + if ! __git_have_func $completion_func && + __git_have_func _completion_loader then _completion_loader "git-$command" fi - if declare -f $completion_func >/dev/null 2>/dev/null + if __git_have_func $completion_func then $completion_func return 0 From 810df0ea8ed00f31d372f3fd90c205d953aea1e6 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 30 Dec 2020 17:29:48 -0600 Subject: [PATCH 2/4] completion: bash: improve function detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. We should quote the argument 2. We don't need two redirections 3. A safeguard for arguments (-a) would be good Suggested-by: René Scharfe Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 869c73ee2c..1150d4bf44 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -3359,7 +3359,7 @@ __git_support_parseopt_helper () { } __git_have_func () { - declare -f $1 >/dev/null 2>/dev/null + declare -f -- "$1" >/dev/null 2>&1 } __git_complete_command () { From 0e02bdc17a4d4beca06d5606a1d3020c79676d7f Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 30 Dec 2020 17:29:49 -0600 Subject: [PATCH 3/4] test: completion: add tests for __git_complete Even though the function was marked as not public, it's already used in the wild. We should at least test basic functionality. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- t/t9902-completion.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index a1c4f1f6d4..c0b4380eae 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -2380,4 +2380,12 @@ test_expect_success 'sourcing the completion script clears cached --options' ' verbose test -z "$__gitcomp_builtin_notes_edit" ' +test_expect_success '__git_complete' ' + unset -f __git_wrap__git_main && + __git_complete foo __git_main && + __git_have_func __git_wrap__git_main && + __git_complete gf _git_fetch && + __git_have_func __git_wrap_git_fetch +' + test_done From 5a067ba9d04eebc92ad77f101b785219238f4f1e Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 30 Dec 2020 17:29:50 -0600 Subject: [PATCH 4/4] completion: add proper public __git_complete When __git_complete was introduced, it was meant to be temporarily, while a proper guideline for public shell functions was established (tentatively _GIT_complete), but since that never happened, people in the wild started to use __git_complete, even though it was marked as not public. Eight years is more than enough wait, let's mark this function as public, and make it a bit more user-friendly. So that instead of doing: __git_complete gk __gitk_main The user can do: __git_complete gk gitk And instead of: __git_complete gf _git_fetch Do: __git_complete gf git_fetch Backwards compatibility is maintained. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 40 +++++++++++++++++++++----- t/t9902-completion.sh | 14 ++++++++- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 1150d4bf44..4b1f4264a6 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -29,6 +29,15 @@ # tell the completion to use commit completion. This also works with aliases # of form "!sh -c '...'". For example, "!sh -c ': git commit ; ... '". # +# If you have a command that is not part of git, but you would still +# like completion, you can use __git_complete: +# +# __git_complete gl git_log +# +# Or if it's a main command (i.e. git or gitk): +# +# __git_complete gk gitk +# # Compatible with bash 3.2.57. # # You can set the following environment variables to influence the behavior of @@ -3497,10 +3506,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 ; }" @@ -3508,13 +3514,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 __git_have_func $2; then + func=$2 + elif __git_have_func __$2_main; then + func=__$2_main + elif __git_have_func _$2; 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 c0b4380eae..c4a7758409 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -2382,10 +2382,22 @@ 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 && __git_have_func __git_wrap__git_main && + unset -f __git_wrap__git_main && + __git_complete gf _git_fetch && - __git_have_func __git_wrap_git_fetch + __git_have_func __git_wrap_git_fetch && + + __git_complete foo git && + __git_have_func __git_wrap__git_main && + unset -f __git_wrap__git_main && + + __git_complete gd git_diff && + __git_have_func __git_wrap_git_diff && + + test_must_fail __git_complete ga missing ' test_done