[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