[PATCH v2] completion: zsh: support completion after "git -C <path>"

"Lutz Lengemann via GitGitGadget" <[email protected]>
Newsgroups org.kernel.vger.git
Message-ID <[email protected]>
From: Lutz Lengemann <[email protected]>

The zsh completion wrapper does not handle the global -C option, so

	git -C <path> <command> <TAB>

offers nothing.  -C is not part of the _arguments specification, and the
wrapper hard-codes __git_cmd_idx=1, i.e. it assumes that the command is
the first argument, so the bash helpers look at the wrong word.  The
latter is not specific to -C; the assumption breaks after any global
option, e.g. "git -p checkout <TAB>" does not complete branch names.

Add -C to the specification, and find the command by skipping over the
global options and, where they take one, their arguments, as __git_main
in git-completion.bash does.  The index is one less than zsh's, as the
helpers count the words from zero.  Collect the paths given to -C into
__git_C_args, or else the helpers run git in the current directory and
fail to resolve the aliases and refs of the repository the command runs
in.

The argument of a -C is still completed without regard for the -C
options before it, i.e. "git -C dir -C <TAB>" offers the directories in
".", not the ones in "dir".

Signed-off-by: Lutz Lengemann <[email protected]>
---
    completion: zsh: support completion after "git -C "
    
     * The command is now located by walking the global options in front of
       it, mirroring the loop at the beginning of __git_main in
       git-completion.bash, instead of skipping only leading -C options.
       This also fixes argument completion after other global options, e.g.
       git -p checkout <TAB>.
     * The log message uses the present tense for the pre-image and notes
       that the argument of a -C is completed without regard for the -C
       options before it.
    
    cc: Ben Knoble [email protected] cc: Junio C Hamano [email protected]

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2155%2Fmobilutz%2Fzsh-complete-global-C-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2155/mobilutz/zsh-complete-global-C-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/2155

Range-diff vs v1:

 1:  9739cde6fc ! 1:  9984228f1f completion: zsh: support completion after "git -C <path>"
     @@ Metadata
       ## Commit message ##
          completion: zsh: support completion after "git -C <path>"
      
     -    The zsh completion wrapper (__git_zsh_main) did not handle the global -C
     -    option, so "git -C <path> <command> <TAB>" offered nothing and could not
     -    complete a command's arguments.
     +    The zsh completion wrapper does not handle the global -C option, so
      
     -    Three things are needed to make it work, all scoped to -C:
     +            git -C <path> <command> <TAB>
      
     -      - Add -C to the _arguments specification, so completion no longer stops
     -        at it.
     +    offers nothing.  -C is not part of the _arguments specification, and the
     +    wrapper hard-codes __git_cmd_idx=1, i.e. it assumes that the command is
     +    the first argument, so the bash helpers look at the wrong word.  The
     +    latter is not specific to -C; the assumption breaks after any global
     +    option, e.g. "git -p checkout <TAB>" does not complete branch names.
      
     -      - Advance __git_cmd_idx past any leading "-C <path>" options. The index
     -        is hard-coded to 1, i.e. the command is assumed to be the first
     -        argument; with -C present the command sits two words later for each
     -        -C, so the bash helpers otherwise look at the wrong word and produce
     -        nothing.
     +    Add -C to the specification, and find the command by skipping over the
     +    global options and, where they take one, their arguments, as __git_main
     +    in git-completion.bash does.  The index is one less than zsh's, as the
     +    helpers count the words from zero.  Collect the paths given to -C into
     +    __git_C_args, or else the helpers run git in the current directory and
     +    fail to resolve the aliases and refs of the repository the command runs
     +    in.
      
     -      - Collect the -C paths into __git_C_args, as __git_main does. The bash
     -        helpers run git to resolve aliases and list refs; without the -C
     -        paths they run in the current directory, so completion fails whenever
     -        the cwd is not the target repository or the command is an alias.
     -
     -    With these, "git -C <path> <command> <TAB>" completes the command, its
     -    options and its arguments, including outside the repository, through
     -    aliases, and with repeated -C options.
     +    The argument of a -C is still completed without regard for the -C
     +    options before it, i.e. "git -C dir -C <TAB>" offers the directories in
     +    ".", not the ones in "dir".
      
          Signed-off-by: Lutz Lengemann <[email protected]>
      
     @@ contrib/completion/git-completion.zsh: __git_zsh_main ()
       		'(- :)--version[prints the git suite version]' \
       		'--exec-path=-[path to where your core git programs are installed]:: :_directories' \
      @@ contrib/completion/git-completion.zsh: __git_zsh_main ()
     + 		done
       		;;
       	(arg)
     - 		local command="${words[1]}" __git_dir __git_cmd_idx=1
     +-		local command="${words[1]}" __git_dir __git_cmd_idx=1
     ++		local command="${words[1]}" __git_dir __git_cmd_idx
      +		local -a __git_C_args
      +		local -i i=2
      +
     -+		while [[ ${orig_words[i]} == -C ]]; do
     -+			__git_C_args+=(-C ${orig_words[i+1]})
     -+			(( __git_cmd_idx += 2 ))
     -+			(( i += 2 ))
     ++		while (( i <= $#orig_words )); do
     ++			case ${orig_words[i]} in
     ++			-C)
     ++				__git_C_args+=(-C ${orig_words[i+1]})
     ++				(( i++ ))
     ++				;;
     ++			-c|--git-dir|--work-tree|--namespace)
     ++				(( i++ ))
     ++				;;
     ++			-*)
     ++				;;
     ++			*)
     ++				break
     ++				;;
     ++			esac
     ++			(( i++ ))
      +		done
     ++
     ++		__git_cmd_idx=$(( i - 1 ))
       
       		if (( $+opt_args[--bare] )); then
       			__git_dir='.'


 contrib/completion/git-completion.zsh | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
index c32186a977..d5c526665b 100644
--- a/contrib/completion/git-completion.zsh
+++ b/contrib/completion/git-completion.zsh
@@ -227,6 +227,7 @@ __git_zsh_main ()
 		'(-p --paginate --no-pager)'{-p,--paginate}'[pipe all output into ''less'']' \
 		'(-p --paginate)--no-pager[do not pipe git output into a pager]' \
 		'--git-dir=-[set the path to the repository]: :_directories' \
+		'*-C[run as if git was started in <path>]: :_directories' \
 		'--bare[treat the repository as a bare repository]' \
 		'(- :)--version[prints the git suite version]' \
 		'--exec-path=-[path to where your core git programs are installed]:: :_directories' \
@@ -251,7 +252,29 @@ __git_zsh_main ()
 		done
 		;;
 	(arg)
-		local command="${words[1]}" __git_dir __git_cmd_idx=1
+		local command="${words[1]}" __git_dir __git_cmd_idx
+		local -a __git_C_args
+		local -i i=2
+
+		while (( i <= $#orig_words )); do
+			case ${orig_words[i]} in
+			-C)
+				__git_C_args+=(-C ${orig_words[i+1]})
+				(( i++ ))
+				;;
+			-c|--git-dir|--work-tree|--namespace)
+				(( i++ ))
+				;;
+			-*)
+				;;
+			*)
+				break
+				;;
+			esac
+			(( i++ ))
+		done
+
+		__git_cmd_idx=$(( i - 1 ))
 
 		if (( $+opt_args[--bare] )); then
 			__git_dir='.'

base-commit: 0fae78c9d55efe705877ea537fe42c59164ccd94
-- 
gitgitgadget
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.