Merge branch 'sg/complete-configuration-variables'

Command line completion updates for "git -c var.name=val"

* sg/complete-configuration-variables:
  completion: complete config variables and values for 'git clone --config='
  completion: complete config variables names and values for 'git clone -c'
  completion: complete values of configuration variables after 'git -c var='
  completion: complete configuration sections and variable names for 'git -c'
  completion: split _git_config()
  completion: simplify inner 'case' pattern in __gitcomp()
  completion: use 'sort -u' to deduplicate config variable names
  completion: deduplicate configuration sections
  completion: add tests for 'git config' completion
  completion: complete more values of more 'color.*' configuration variables
  completion: fix a typo in a comment
This commit is contained in:
Junio C Hamano 2019-09-18 11:50:08 -07:00
commit 95486229e3
2 changed files with 243 additions and 64 deletions

View File

@ -340,7 +340,7 @@ __gitcomp ()
c="$c${4-}" c="$c${4-}"
if [[ $c == "$cur_"* ]]; then if [[ $c == "$cur_"* ]]; then
case $c in case $c in
--*=*|*.) ;; --*=|*.) ;;
*) c="$c " ;; *) c="$c " ;;
esac esac
COMPREPLY[i++]="${2-}$c" COMPREPLY[i++]="${2-}$c"
@ -360,7 +360,7 @@ __gitcomp ()
c="$c${4-}" c="$c${4-}"
if [[ $c == "$cur_"* ]]; then if [[ $c == "$cur_"* ]]; then
case $c in case $c in
--*=*|*.) ;; *=|*.) ;;
*) c="$c " ;; *) c="$c " ;;
esac esac
COMPREPLY[i++]="${2-}$c" COMPREPLY[i++]="${2-}$c"
@ -524,7 +524,7 @@ __git_index_files ()
# Even when a directory name itself does not contain # Even when a directory name itself does not contain
# any special characters, it will still be quoted if # any special characters, it will still be quoted if
# any of its (stripped) trailing path components do. # any of its (stripped) trailing path components do.
# Because of this we may have seen the same direcory # Because of this we may have seen the same directory
# both quoted and unquoted. # both quoted and unquoted.
if (p in paths) if (p in paths)
# We have seen the same directory unquoted, # We have seen the same directory unquoted,
@ -1399,7 +1399,18 @@ _git_clean ()
_git_clone () _git_clone ()
{ {
case "$prev" in
-c|--config)
__git_complete_config_variable_name_and_value
return
;;
esac
case "$cur" in case "$cur" in
--config=*)
__git_complete_config_variable_name_and_value \
--cur="${cur##--config=}"
return
;;
--*) --*)
__gitcomp_builtin clone __gitcomp_builtin clone
return return
@ -2225,181 +2236,282 @@ __git_config_vars=
__git_compute_config_vars () __git_compute_config_vars ()
{ {
test -n "$__git_config_vars" || test -n "$__git_config_vars" ||
__git_config_vars="$(git help --config-for-completion | sort | uniq)" __git_config_vars="$(git help --config-for-completion | sort -u)"
} }
_git_config () # Completes possible values of various configuration variables.
#
# Usage: __git_complete_config_variable_value [<option>]...
# --varname=<word>: The name of the configuration variable whose value is
# to be completed. Defaults to the previous word on the
# command line.
# --cur=<word>: The current value to be completed. Defaults to the current
# word to be completed.
__git_complete_config_variable_value ()
{ {
local varname local varname="$prev" cur_="$cur"
while test $# != 0; do
case "$1" in
--varname=*) varname="${1##--varname=}" ;;
--cur=*) cur_="${1##--cur=}" ;;
*) return 1 ;;
esac
shift
done
if [ "${BASH_VERSINFO[0]:-0}" -ge 4 ]; then if [ "${BASH_VERSINFO[0]:-0}" -ge 4 ]; then
varname="${prev,,}" varname="${varname,,}"
else else
varname="$(echo "$prev" |tr A-Z a-z)" varname="$(echo "$varname" |tr A-Z a-z)"
fi fi
case "$varname" in case "$varname" in
branch.*.remote|branch.*.pushremote) branch.*.remote|branch.*.pushremote)
__gitcomp_nl "$(__git_remotes)" __gitcomp_nl "$(__git_remotes)" "" "$cur_"
return return
;; ;;
branch.*.merge) branch.*.merge)
__git_complete_refs __git_complete_refs --cur="$cur_"
return return
;; ;;
branch.*.rebase) branch.*.rebase)
__gitcomp "false true merges preserve interactive" __gitcomp "false true merges preserve interactive" "" "$cur_"
return return
;; ;;
remote.pushdefault) remote.pushdefault)
__gitcomp_nl "$(__git_remotes)" __gitcomp_nl "$(__git_remotes)" "" "$cur_"
return return
;; ;;
remote.*.fetch) remote.*.fetch)
local remote="${prev#remote.}" local remote="${varname#remote.}"
remote="${remote%.fetch}" remote="${remote%.fetch}"
if [ -z "$cur" ]; then if [ -z "$cur_" ]; then
__gitcomp_nl "refs/heads/" "" "" "" __gitcomp_nl "refs/heads/" "" "" ""
return return
fi fi
__gitcomp_nl "$(__git_refs_remotes "$remote")" __gitcomp_nl "$(__git_refs_remotes "$remote")" "" "$cur_"
return return
;; ;;
remote.*.push) remote.*.push)
local remote="${prev#remote.}" local remote="${varname#remote.}"
remote="${remote%.push}" remote="${remote%.push}"
__gitcomp_nl "$(__git for-each-ref \ __gitcomp_nl "$(__git for-each-ref \
--format='%(refname):%(refname)' refs/heads)" --format='%(refname):%(refname)' refs/heads)" "" "$cur_"
return return
;; ;;
pull.twohead|pull.octopus) pull.twohead|pull.octopus)
__git_compute_merge_strategies __git_compute_merge_strategies
__gitcomp "$__git_merge_strategies" __gitcomp "$__git_merge_strategies" "" "$cur_"
return
;;
color.branch|color.diff|color.interactive|\
color.showbranch|color.status|color.ui)
__gitcomp "always never auto"
return return
;; ;;
color.pager) color.pager)
__gitcomp "false true" __gitcomp "false true" "" "$cur_"
return return
;; ;;
color.*.*) color.*.*)
__gitcomp " __gitcomp "
normal black red green yellow blue magenta cyan white normal black red green yellow blue magenta cyan white
bold dim ul blink reverse bold dim ul blink reverse
" " "" "$cur_"
return
;;
color.*)
__gitcomp "false true always never auto" "" "$cur_"
return return
;; ;;
diff.submodule) diff.submodule)
__gitcomp "$__git_diff_submodule_formats" __gitcomp "$__git_diff_submodule_formats" "" "$cur_"
return return
;; ;;
help.format) help.format)
__gitcomp "man info web html" __gitcomp "man info web html" "" "$cur_"
return return
;; ;;
log.date) log.date)
__gitcomp "$__git_log_date_formats" __gitcomp "$__git_log_date_formats" "" "$cur_"
return return
;; ;;
sendemail.aliasfiletype) sendemail.aliasfiletype)
__gitcomp "mutt mailrc pine elm gnus" __gitcomp "mutt mailrc pine elm gnus" "" "$cur_"
return return
;; ;;
sendemail.confirm) sendemail.confirm)
__gitcomp "$__git_send_email_confirm_options" __gitcomp "$__git_send_email_confirm_options" "" "$cur_"
return return
;; ;;
sendemail.suppresscc) sendemail.suppresscc)
__gitcomp "$__git_send_email_suppresscc_options" __gitcomp "$__git_send_email_suppresscc_options" "" "$cur_"
return return
;; ;;
sendemail.transferencoding) sendemail.transferencoding)
__gitcomp "7bit 8bit quoted-printable base64" __gitcomp "7bit 8bit quoted-printable base64" "" "$cur_"
return
;;
--get|--get-all|--unset|--unset-all)
__gitcomp_nl "$(__git_config_get_set_variables)"
return return
;; ;;
*.*) *.*)
return return
;; ;;
esac esac
case "$cur" in }
--*)
__gitcomp_builtin config # Completes configuration sections, subsections, variable names.
return #
;; # Usage: __git_complete_config_variable_name [<option>]...
# --cur=<word>: The current configuration section/variable name to be
# completed. Defaults to the current word to be completed.
# --sfx=<suffix>: A suffix to be appended to each fully completed
# configuration variable name (but not to sections or
# subsections) instead of the default space.
__git_complete_config_variable_name ()
{
local cur_="$cur" sfx
while test $# != 0; do
case "$1" in
--cur=*) cur_="${1##--cur=}" ;;
--sfx=*) sfx="${1##--sfx=}" ;;
*) return 1 ;;
esac
shift
done
case "$cur_" in
branch.*.*) branch.*.*)
local pfx="${cur%.*}." cur_="${cur##*.}" local pfx="${cur_%.*}."
__gitcomp "remote pushRemote merge mergeOptions rebase" "$pfx" "$cur_" cur_="${cur_##*.}"
__gitcomp "remote pushRemote merge mergeOptions rebase" "$pfx" "$cur_" "$sfx"
return return
;; ;;
branch.*) branch.*)
local pfx="${cur%.*}." cur_="${cur#*.}" local pfx="${cur%.*}."
cur_="${cur#*.}"
__gitcomp_direct "$(__git_heads "$pfx" "$cur_" ".")" __gitcomp_direct "$(__git_heads "$pfx" "$cur_" ".")"
__gitcomp_nl_append $'autoSetupMerge\nautoSetupRebase\n' "$pfx" "$cur_" __gitcomp_nl_append $'autoSetupMerge\nautoSetupRebase\n' "$pfx" "$cur_" "$sfx"
return return
;; ;;
guitool.*.*) guitool.*.*)
local pfx="${cur%.*}." cur_="${cur##*.}" local pfx="${cur_%.*}."
cur_="${cur_##*.}"
__gitcomp " __gitcomp "
argPrompt cmd confirm needsFile noConsole noRescan argPrompt cmd confirm needsFile noConsole noRescan
prompt revPrompt revUnmerged title prompt revPrompt revUnmerged title
" "$pfx" "$cur_" " "$pfx" "$cur_" "$sfx"
return return
;; ;;
difftool.*.*) difftool.*.*)
local pfx="${cur%.*}." cur_="${cur##*.}" local pfx="${cur_%.*}."
__gitcomp "cmd path" "$pfx" "$cur_" cur_="${cur_##*.}"
__gitcomp "cmd path" "$pfx" "$cur_" "$sfx"
return return
;; ;;
man.*.*) man.*.*)
local pfx="${cur%.*}." cur_="${cur##*.}" local pfx="${cur_%.*}."
__gitcomp "cmd path" "$pfx" "$cur_" cur_="${cur_##*.}"
__gitcomp "cmd path" "$pfx" "$cur_" "$sfx"
return return
;; ;;
mergetool.*.*) mergetool.*.*)
local pfx="${cur%.*}." cur_="${cur##*.}" local pfx="${cur_%.*}."
__gitcomp "cmd path trustExitCode" "$pfx" "$cur_" cur_="${cur_##*.}"
__gitcomp "cmd path trustExitCode" "$pfx" "$cur_" "$sfx"
return return
;; ;;
pager.*) pager.*)
local pfx="${cur%.*}." cur_="${cur#*.}" local pfx="${cur_%.*}."
cur_="${cur_#*.}"
__git_compute_all_commands __git_compute_all_commands
__gitcomp_nl "$__git_all_commands" "$pfx" "$cur_" __gitcomp_nl "$__git_all_commands" "$pfx" "$cur_" "$sfx"
return return
;; ;;
remote.*.*) remote.*.*)
local pfx="${cur%.*}." cur_="${cur##*.}" local pfx="${cur_%.*}."
cur_="${cur_##*.}"
__gitcomp " __gitcomp "
url proxy fetch push mirror skipDefaultUpdate url proxy fetch push mirror skipDefaultUpdate
receivepack uploadpack tagOpt pushurl receivepack uploadpack tagOpt pushurl
" "$pfx" "$cur_" " "$pfx" "$cur_" "$sfx"
return return
;; ;;
remote.*) remote.*)
local pfx="${cur%.*}." cur_="${cur#*.}" local pfx="${cur_%.*}."
cur_="${cur_#*.}"
__gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "." __gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "."
__gitcomp_nl_append "pushDefault" "$pfx" "$cur_" __gitcomp_nl_append "pushDefault" "$pfx" "$cur_" "$sfx"
return return
;; ;;
url.*.*) url.*.*)
local pfx="${cur%.*}." cur_="${cur##*.}" local pfx="${cur_%.*}."
__gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur_" cur_="${cur_##*.}"
__gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur_" "$sfx"
return return
;; ;;
*.*) *.*)
__git_compute_config_vars __git_compute_config_vars
__gitcomp "$__git_config_vars" __gitcomp "$__git_config_vars" "" "$cur_" "$sfx"
;; ;;
*) *)
__git_compute_config_vars __git_compute_config_vars
__gitcomp "$(echo "$__git_config_vars" | sed 's/\.[^ ]*/./g')" __gitcomp "$(echo "$__git_config_vars" |
awk -F . '{
sections[$1] = 1
}
END {
for (s in sections)
print s "."
}
')" "" "$cur_"
;;
esac
}
# Completes '='-separated configuration sections/variable names and values
# for 'git -c section.name=value'.
#
# Usage: __git_complete_config_variable_name_and_value [<option>]...
# --cur=<word>: The current configuration section/variable name/value to be
# completed. Defaults to the current word to be completed.
__git_complete_config_variable_name_and_value ()
{
local cur_="$cur"
while test $# != 0; do
case "$1" in
--cur=*) cur_="${1##--cur=}" ;;
*) return 1 ;;
esac
shift
done
case "$cur_" in
*=*)
__git_complete_config_variable_value \
--varname="${cur_%%=*}" --cur="${cur_#*=}"
;;
*)
__git_complete_config_variable_name --cur="$cur_" --sfx='='
;;
esac
}
_git_config ()
{
case "$prev" in
--get|--get-all|--unset|--unset-all)
__gitcomp_nl "$(__git_config_get_set_variables)"
return
;;
*.*)
__git_complete_config_variable_value
return
;;
esac
case "$cur" in
--*)
__gitcomp_builtin config
;;
*)
__git_complete_config_variable_name
;;
esac esac
} }
@ -2956,7 +3068,11 @@ __git_main ()
# Bash filename completion # Bash filename completion
return return
;; ;;
-c|--namespace) -c)
__git_complete_config_variable_name_and_value
return
;;
--namespace)
# we don't support completing these options' arguments # we don't support completing these options' arguments
return return
;; ;;

View File

@ -1698,6 +1698,69 @@ do
' '
done done
test_expect_success 'git config - section' '
test_completion "git config br" <<-\EOF
branch.Z
browser.Z
EOF
'
test_expect_success 'git config - variable name' '
test_completion "git config log.d" <<-\EOF
log.date Z
log.decorate Z
EOF
'
test_expect_success 'git config - value' '
test_completion "git config color.pager " <<-\EOF
false Z
true Z
EOF
'
test_expect_success 'git -c - section' '
test_completion "git -c br" <<-\EOF
branch.Z
browser.Z
EOF
'
test_expect_success 'git -c - variable name' '
test_completion "git -c log.d" <<-\EOF
log.date=Z
log.decorate=Z
EOF
'
test_expect_success 'git -c - value' '
test_completion "git -c color.pager=" <<-\EOF
false Z
true Z
EOF
'
test_expect_success 'git clone --config= - section' '
test_completion "git clone --config=br" <<-\EOF
branch.Z
browser.Z
EOF
'
test_expect_success 'git clone --config= - variable name' '
test_completion "git clone --config=log.d" <<-\EOF
log.date=Z
log.decorate=Z
EOF
'
test_expect_success 'git clone --config= - value' '
test_completion "git clone --config=color.pager=" <<-\EOF
false Z
true Z
EOF
'
test_expect_success 'sourcing the completion script clears cached commands' ' test_expect_success 'sourcing the completion script clears cached commands' '
__git_compute_all_commands && __git_compute_all_commands &&
verbose test -n "$__git_all_commands" && verbose test -n "$__git_all_commands" &&