Subject: [PATCH 08/11] completion: complete configuration sections and variable names for 'git -c'

From: SZEDER Gábor <[email-masked]>
Date: Tue, 13 Aug 2019 14:26:49 +0200

'git config' expects a configuration variable's name and value in
separate arguments, so we let the __gitcomp() helper append a space
character to each variable name by default, like we do for most other
things (--options, refs, paths, etc.).  'git -c', however, expects
them in a single option joined by a '=' character, i.e.
'section.name=value', so we should append a '=' character to each
fully completed variable name, but no space, so the user can continue
typing the value right away.

Add an option to the __git_complete_config_variable_name() function to
allow callers to specify an alternate suffix to add, and use it to
append that '=' character to configuration variables.  Update the
__gitcomp() helper function to not append a trailing space to any
completion words ending with a '=', not just to those option with a
stuck argument.

Signed-off-by: SZEDER Gábor <[email-masked]>
---
 contrib/completion/git-completion.bash | 59 ++++++++++++++++++++------
 t/t9902-completion.sh                  | 14 ++++++
 2 files changed, 60 insertions(+), 13 deletions(-)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 3e9c5b6b71..367b1c50f4 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -360,7 +360,7 @@ __gitcomp ()
 			c="$c${4-}"
 			if [[ $c == "$cur_"* ]]; then
 				case $c in
-				--*=|*.) ;;
+				*=|*.) ;;
 				*) c="$c " ;;
 				esac
 				COMPREPLY[i++]="${2-}$c"
@@ -2328,18 +2328,33 @@ __git_complete_config_variable_value ()
 }
 
 # Completes configuration sections, subsections, variable names.
+#
+# Usage: __git_complete_config_variable_name [<option>]...
+# --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 sfx
+
+	while test $# != 0; do
+		case "$1" in
+		--sfx=*)	sfx="${1##--sfx=}" ;;
+		*)		return 1 ;;
+		esac
+		shift
+	done
+
 	case "$cur" in
 	branch.*.*)
 		local pfx="${cur%.*}." cur_="${cur##*.}"
-		__gitcomp "remote pushRemote merge mergeOptions rebase" "$pfx" "$cur_"
+		__gitcomp "remote pushRemote merge mergeOptions rebase" "$pfx" "$cur_" "$sfx"
 		return
 		;;
 	branch.*)
 		local pfx="${cur%.*}." cur_="${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
 		;;
 	guitool.*.*)
@@ -2347,28 +2362,28 @@ __git_complete_config_variable_name ()
 		__gitcomp "
 			argPrompt cmd confirm needsFile noConsole noRescan
 			prompt revPrompt revUnmerged title
-			" "$pfx" "$cur_"
+			" "$pfx" "$cur_" "$sfx"
 		return
 		;;
 	difftool.*.*)
 		local pfx="${cur%.*}." cur_="${cur##*.}"
-		__gitcomp "cmd path" "$pfx" "$cur_"
+		__gitcomp "cmd path" "$pfx" "$cur_" "$sfx"
 		return
 		;;
 	man.*.*)
 		local pfx="${cur%.*}." cur_="${cur##*.}"
-		__gitcomp "cmd path" "$pfx" "$cur_"
+		__gitcomp "cmd path" "$pfx" "$cur_" "$sfx"
 		return
 		;;
 	mergetool.*.*)
 		local pfx="${cur%.*}." cur_="${cur##*.}"
-		__gitcomp "cmd path trustExitCode" "$pfx" "$cur_"
+		__gitcomp "cmd path trustExitCode" "$pfx" "$cur_" "$sfx"
 		return
 		;;
 	pager.*)
 		local pfx="${cur%.*}." cur_="${cur#*.}"
 		__git_compute_all_commands
-		__gitcomp_nl "$__git_all_commands" "$pfx" "$cur_"
+		__gitcomp_nl "$__git_all_commands" "$pfx" "$cur_" "$sfx"
 		return
 		;;
 	remote.*.*)
@@ -2376,23 +2391,23 @@ __git_complete_config_variable_name ()
 		__gitcomp "
 			url proxy fetch push mirror skipDefaultUpdate
 			receivepack uploadpack tagOpt pushurl
-			" "$pfx" "$cur_"
+			" "$pfx" "$cur_" "$sfx"
 		return
 		;;
 	remote.*)
 		local pfx="${cur%.*}." cur_="${cur#*.}"
 		__gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "."
-		__gitcomp_nl_append "pushDefault" "$pfx" "$cur_"
+		__gitcomp_nl_append "pushDefault" "$pfx" "$cur_" "$sfx"
 		return
 		;;
 	url.*.*)
 		local pfx="${cur%.*}." cur_="${cur##*.}"
-		__gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur_"
+		__gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur_" "$sfx"
 		return
 		;;
 	*.*)
 		__git_compute_config_vars
-		__gitcomp "$__git_config_vars"
+		__gitcomp "$__git_config_vars" "" "$cur" "$sfx"
 		;;
 	*)
 		__git_compute_config_vars
@@ -2409,6 +2424,20 @@ __git_complete_config_variable_name ()
 	esac
 }
 
+# Completes '='-separated configuration sections/variable names and values
+# for 'git -c section.name=value'.
+__git_complete_config_variable_name_and_value ()
+{
+	case "$cur" in
+	*=*)
+		# in the next patch...
+		;;
+	*)
+		__git_complete_config_variable_name --sfx='='
+		;;
+	esac
+}
+
 _git_config ()
 {
 	case "$prev" in
@@ -2984,7 +3013,11 @@ __git_main ()
 			# Bash filename completion
 			return
 			;;
-		-c|--namespace)
+		-c)
+			__git_complete_config_variable_name_and_value
+			return
+			;;
+		--namespace)
 			# we don't support completing these options' arguments
 			return
 			;;
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 008fba7c89..bf60a11fa8 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -1719,6 +1719,20 @@ test_expect_success 'git config - value' '
 	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 'sourcing the completion script clears cached commands' '
 	__git_compute_all_commands &&
 	verbose test -n "$__git_all_commands" &&
-- 
2.23.0.rc2.350.gf4fdc32db7