git-completion.bash: use $__git_cmd_idx in more places

With the introduction of the $__git_cmd_idx variable in e94fb44042 (git-completion.bash: pass $__git_subcommand_idx from __git_main(), 2021-03-24), completion functions were able to know the index at which the git command is listed, allowing them to skip options that are given to the underlying git itself, not the corresponding command (e.g. `-C asdf` in `git -C asdf branch`). While most of the changes here are self-explanatory, some bear further explanation. For the __git_find_on_cmdline() and __git_find_last_on_cmdline() pair of functions, these functions are only ever called in the context of a git command completion function. These functions will only care about words after the command so we can safely ignore the words before this. For _git_worktree(), this change is technically a no-op (once the __git_find_last_on_cmdline change is also applied). It was in poor style to have hard-coded on the index right after `worktree`. In case `git worktree` were to ever learn to accept options, the current situation would be inflexible. Signed-off-by: Denton Liu <liu.denton@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Denton Liu committed Apr 22, 2021 at 03:00 UTC 59d85a2a0528c3db2552b0786caac7bf0610c552
2 files changed +33 -12
contrib/completion/git-completion.bash
+14 -12
@@ -1006,8 +1006,8 @@ __git_complete_revlist ()
1006
1007 __git_complete_remote_or_refspec ()
1008 {
1009 - local cur_="$cur" cmd="${words[1]}"
1010 - local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0
1009 + local cur_="$cur" cmd="${words[__git_cmd_idx]}"
1010 + local i c=$((__git_cmd_idx+1)) remote="" pfx="" lhs=1 no_complete_refspec=0
1011 if [ "$cmd" = "remote" ]; then
1012 ((c++))
1013 fi
@@ -1176,7 +1176,7 @@ __git_aliased_command ()
1176 # --show-idx: Optionally show the index of the found word in the $words array.
1177 __git_find_on_cmdline ()
1178 {
1179 - local word c=1 show_idx
1179 + local word c="$__git_cmd_idx" show_idx
1180
1181 while test $# -gt 1; do
1182 case "$1" in
@@ -1221,7 +1221,7 @@ __git_find_last_on_cmdline ()
1221 done
1222 local wordlist="$1"
1223
1224 - while [ $c -gt 1 ]; do
1224 + while [ $c -gt "$__git_cmd_idx" ]; do
1225 ((c--))
1226 for word in $wordlist; do
1227 if [ "$word" = "${words[c]}" ]; then
@@ -1306,7 +1306,7 @@ __git_count_arguments ()
1306 local word i c=0
1307
1308 # Skip "git" (first argument)
1309 - for ((i=1; i < ${#words[@]}; i++)); do
1309 + for ((i="$__git_cmd_idx"; i < ${#words[@]}; i++)); do
1310 word="${words[i]}"
1311
1312 case "$word" in
@@ -1442,7 +1442,7 @@ __git_ref_fieldlist="refname objecttype objectsize objectname upstream push HEAD
1442
1443 _git_branch ()
1444 {
1445 - local i c=1 only_local_ref="n" has_r="n"
1445 + local i c="$__git_cmd_idx" only_local_ref="n" has_r="n"
1446
1447 while [ $c -lt $cword ]; do
1448 i="${words[c]}"
@@ -2474,7 +2474,7 @@ _git_switch ()
2474 __git_config_get_set_variables ()
2475 {
2476 local prevword word config_file= c=$cword
2477 - while [ $c -gt 1 ]; do
2477 + while [ $c -gt "$__git_cmd_idx" ]; do
2478 word="${words[c]}"
2479 case "$word" in
2480 --system|--global|--local|--file=*)
@@ -3224,7 +3224,7 @@ _git_svn ()
3224
3225 _git_tag ()
3226 {
3227 - local i c=1 f=0
3227 + local i c="$__git_cmd_idx" f=0
3228 while [ $c -lt $cword ]; do
3229 i="${words[c]}"
3230 case "$i" in
@@ -3276,9 +3276,11 @@ __git_complete_worktree_paths ()
3276 _git_worktree ()
3277 {
3278 local subcommands="add list lock move prune remove unlock"
3279 - local subcommand
3279 + local subcommand subcommand_idx
3280
3281 - subcommand="$(__git_find_on_cmdline "$subcommands")"
3281 + subcommand="$(__git_find_on_cmdline --show-idx "$subcommands")"
3282 + subcommand_idx="${subcommand% *}"
3283 + subcommand="${subcommand#* }"
3284
3285 case "$subcommand,$cur" in
3286 ,*)
@@ -3303,7 +3305,7 @@ _git_worktree ()
3305 # be either the 'add' subcommand, the unstuck
3306 # argument of an option (e.g. branch for -b|-B), or
3307 # the path for the new worktree.
3306 - if [ $cword -eq $((__git_cmd_idx+2)) ]; then
3308 + if [ $cword -eq $((subcommand_idx+1)) ]; then
3309 # Right after the 'add' subcommand: have to
3310 # complete the path, so fall back to Bash
3311 # filename completion.
@@ -3327,7 +3329,7 @@ _git_worktree ()
3329 __git_complete_worktree_paths
3330 ;;
3331 move,*)
3330 - if [ $cword -eq $((__git_cmd_idx+2)) ]; then
3332 + if [ $cword -eq $((subcommand_idx+1)) ]; then
3333 # The first parameter must be an existing working
3334 # tree to be moved.
3335 __git_complete_worktree_paths
t/t9902-completion.sh
+19
@@ -1879,6 +1879,7 @@ test_expect_success '__git_find_on_cmdline - single match' '
1879 (
1880 words=(git command --opt list) &&
1881 cword=${#words[@]} &&
1882 + __git_cmd_idx=1 &&
1883 __git_find_on_cmdline "add list remove" >actual
1884 ) &&
1885 test_cmp expect actual
@@ -1889,6 +1890,7 @@ test_expect_success '__git_find_on_cmdline - multiple matches' '
1890 (
1891 words=(git command -o --opt remove list add) &&
1892 cword=${#words[@]} &&
1893 + __git_cmd_idx=1 &&
1894 __git_find_on_cmdline "add list remove" >actual
1895 ) &&
1896 test_cmp expect actual
@@ -1898,6 +1900,7 @@ test_expect_success '__git_find_on_cmdline - no match' '
1900 (
1901 words=(git command --opt branch) &&
1902 cword=${#words[@]} &&
1903 + __git_cmd_idx=1 &&
1904 __git_find_on_cmdline "add list remove" >actual
1905 ) &&
1906 test_must_be_empty actual
@@ -1908,6 +1911,7 @@ test_expect_success '__git_find_on_cmdline - single match with index' '
1911 (
1912 words=(git command --opt list) &&
1913 cword=${#words[@]} &&
1914 + __git_cmd_idx=1 &&
1915 __git_find_on_cmdline --show-idx "add list remove" >actual
1916 ) &&
1917 test_cmp expect actual
@@ -1918,6 +1922,7 @@ test_expect_success '__git_find_on_cmdline - multiple matches with index' '
1922 (
1923 words=(git command -o --opt remove list add) &&
1924 cword=${#words[@]} &&
1925 + __git_cmd_idx=1 &&
1926 __git_find_on_cmdline --show-idx "add list remove" >actual
1927 ) &&
1928 test_cmp expect actual
@@ -1927,11 +1932,23 @@ test_expect_success '__git_find_on_cmdline - no match with index' '
1932 (
1933 words=(git command --opt branch) &&
1934 cword=${#words[@]} &&
1935 + __git_cmd_idx=1 &&
1936 __git_find_on_cmdline --show-idx "add list remove" >actual
1937 ) &&
1938 test_must_be_empty actual
1939 '
1940
1941 +test_expect_success '__git_find_on_cmdline - ignores matches before command with index' '
1942 + echo "6 remove" >expect &&
1943 + (
1944 + words=(git -C remove command -o --opt remove list add) &&
1945 + cword=${#words[@]} &&
1946 + __git_cmd_idx=3 &&
1947 + __git_find_on_cmdline --show-idx "add list remove" >actual
1948 + ) &&
1949 + test_cmp expect actual
1950 +'
1951 +
1952 test_expect_success '__git_get_config_variables' '
1953 cat >expect <<-EOF &&
1954 name-1
@@ -2275,6 +2292,7 @@ do
2292 (
2293 words=(git push '$flag' other ma) &&
2294 cword=${#words[@]} cur=${words[cword-1]} &&
2295 + __git_cmd_idx=1 &&
2296 __git_complete_remote_or_refspec &&
2297 print_comp
2298 ) &&
@@ -2288,6 +2306,7 @@ do
2306 (
2307 words=(git push other '$flag' ma) &&
2308 cword=${#words[@]} cur=${words[cword-1]} &&
2309 + __git_cmd_idx=1 &&
2310 __git_complete_remote_or_refspec &&
2311 print_comp
2312 ) &&