Skip to content

Commit 8776470

Browse files
benknoblegitster
authored andcommitted
completion: repair config completion for Zsh
Commit 1e0ee40 (completion: add and use __git_compute_first_level_config_vars_for_section, 2024-02-10) uses an indirect variable syntax that is only valid for Bash, but the Zsh completion code relies on the Bash completion code to function. Zsh supports a different indirect variable expansion using ${(P)var}, but in `emulate ksh` mode does not support Bash's ${!var}. This manifests as completing strange config options like "__git_first_level_config_vars_for_section_remote" as a choice for the command line git config set remote. Using Zsh's C-x ? _complete_debug widget with the cursor at the end of that command line captures a trace, in which we see (some details elided): +__git_complete_config_variable_name:7> __git_compute_first_level_config_vars_for_section remote +__git_compute_first_level_config_vars_for_section:7> local section=remote +__git_compute_first_level_config_vars_for_section:7> __git_compute_config_vars +__git_compute_config_vars:7> test -n $'add.ignoreErrors\nadvice.addEmbeddedRepo\nadvice.addEmptyPathspec\nadvice.addIgnoredFile[…]' +__git_compute_first_level_config_vars_for_section:7> local this_section=__git_first_level_config_vars_for_section_remote +__git_compute_first_level_config_vars_for_section:7> test -n __git_first_level_config_vars_for_section_remote +__git_complete_config_variable_name:7> local this_section=__git_first_level_config_vars_for_section_remote +__git_complete_config_variable_name:7> __gitcomp_nl_append __git_first_level_config_vars_for_section_remote remote. '' ' ' +__gitcomp_nl_append:7> __gitcomp_nl __git_first_level_config_vars_for_section_remote remote. '' ' ' +__gitcomp_nl:7> emulate -L zsh +__gitcomp_nl:7> compset -P '*[=:]' +__gitcomp_nl:7> compadd -Q -S ' ' -p remote. -- __git_first_level_config_vars_for_section_remote We perform the test for __git_compute_config_vars correctly, but the ${!this_section} references are not expanded as expected. Instead, portably expand indirect references through the new __git_indirect. Contrary to some versions you might find online [1], this version avoids echo non-portabilities [2] [3] and correctly quotes the indirect expansion after eval (so that the result is not split or globbed before being handed to printf). [1]: https://unix.stackexchange.com/a/41409/301073 [2]: https://askubuntu.com/questions/715765/mysterious-behavior-of-echo-command#comment1056038_715769 [3]: https://mywiki.wooledge.org/CatEchoLs The following demo program demonstrates how this works: b=1 indirect() { eval printf '%s' "\"\$$1\"" } f() { # Comment this out to see that it works for globals, too. Or, use # a value with spaces like '2 3 4' to see how it handles those. local b=2 local a=b test -n "$(indirect $a)" && echo nice } f When placed in a file "demo", then both bash -x demo and zsh -xc 'emulate ksh -c ". ./demo"' |& tail provide traces showing that "$(indirect $a)" produces 2 (or 1, with the global, or "2 3 4" as a single string, etc.). Signed-off-by: D. Ben Knoble <[email protected]> Acked-by: Philippe Blain <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c2b3f2b commit 8776470

File tree

1 file changed

+11
-6
lines changed

1 file changed

+11
-6
lines changed

contrib/completion/git-completion.bash

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2723,12 +2723,17 @@ __git_compute_config_vars_all ()
27232723
__git_config_vars_all="$(git --no-pager help --config)"
27242724
}
27252725

2726+
__git_indirect()
2727+
{
2728+
eval printf '%s' "\"\$$1\""
2729+
}
2730+
27262731
__git_compute_first_level_config_vars_for_section ()
27272732
{
27282733
local section="$1"
27292734
__git_compute_config_vars
27302735
local this_section="__git_first_level_config_vars_for_section_${section}"
2731-
test -n "${!this_section}" ||
2736+
test -n "$(__git_indirect "${this_section}")" ||
27322737
printf -v "__git_first_level_config_vars_for_section_${section}" %s \
27332738
"$(echo "$__git_config_vars" | awk -F. "/^${section}\.[a-z]/ { print \$2 }")"
27342739
}
@@ -2738,7 +2743,7 @@ __git_compute_second_level_config_vars_for_section ()
27382743
local section="$1"
27392744
__git_compute_config_vars_all
27402745
local this_section="__git_second_level_config_vars_for_section_${section}"
2741-
test -n "${!this_section}" ||
2746+
test -n "$(__git_indirect "${this_section}")" ||
27422747
printf -v "__git_second_level_config_vars_for_section_${section}" %s \
27432748
"$(echo "$__git_config_vars_all" | awk -F. "/^${section}\.</ { print \$3 }")"
27442749
}
@@ -2893,7 +2898,7 @@ __git_complete_config_variable_name ()
28932898
local section="${pfx%.*.}"
28942899
__git_compute_second_level_config_vars_for_section "${section}"
28952900
local this_section="__git_second_level_config_vars_for_section_${section}"
2896-
__gitcomp "${!this_section}" "$pfx" "$cur_" "$sfx"
2901+
__gitcomp "$(__git_indirect "${this_section}")" "$pfx" "$cur_" "$sfx"
28972902
return
28982903
;;
28992904
branch.*)
@@ -2903,7 +2908,7 @@ __git_complete_config_variable_name ()
29032908
__gitcomp_direct "$(__git_heads "$pfx" "$cur_" ".")"
29042909
__git_compute_first_level_config_vars_for_section "${section}"
29052910
local this_section="__git_first_level_config_vars_for_section_${section}"
2906-
__gitcomp_nl_append "${!this_section}" "$pfx" "$cur_" "${sfx:- }"
2911+
__gitcomp_nl_append "$(__git_indirect "${this_section}")" "$pfx" "$cur_" "${sfx:- }"
29072912
return
29082913
;;
29092914
pager.*)
@@ -2920,7 +2925,7 @@ __git_complete_config_variable_name ()
29202925
__gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "."
29212926
__git_compute_first_level_config_vars_for_section "${section}"
29222927
local this_section="__git_first_level_config_vars_for_section_${section}"
2923-
__gitcomp_nl_append "${!this_section}" "$pfx" "$cur_" "${sfx:- }"
2928+
__gitcomp_nl_append "$(__git_indirect "${this_section}")" "$pfx" "$cur_" "${sfx:- }"
29242929
return
29252930
;;
29262931
submodule.*)
@@ -2930,7 +2935,7 @@ __git_complete_config_variable_name ()
29302935
__gitcomp_nl "$(__git config -f "$(__git rev-parse --show-toplevel)/.gitmodules" --get-regexp 'submodule.*.path' | awk -F. '{print $2}')" "$pfx" "$cur_" "."
29312936
__git_compute_first_level_config_vars_for_section "${section}"
29322937
local this_section="__git_first_level_config_vars_for_section_${section}"
2933-
__gitcomp_nl_append "${!this_section}" "$pfx" "$cur_" "${sfx:- }"
2938+
__gitcomp_nl_append "$(__git_indirect "${this_section}")" "$pfx" "$cur_" "${sfx:- }"
29342939
return
29352940
;;
29362941
*.*)

0 commit comments

Comments
 (0)