Skip to content

Commit fec1ff9

Browse files
committed
Merge branch 'sg/completion-worktree'
The command line completion (in contrib/) learned to complete subcommands and arguments to "git worktree". * sg/completion-worktree: completion: list paths and refs for 'git worktree add' completion: list existing working trees for 'git worktree' subcommands completion: simplify completing 'git worktree' subcommands and options completion: return the index of found word from __git_find_on_cmdline() completion: clean up the __git_find_on_cmdline() helper function t9902-completion: add tests for the __git_find_on_cmdline() helper
2 parents c7372c9 + 7d5ecd7 commit fec1ff9

File tree

2 files changed

+150
-26
lines changed

2 files changed

+150
-26
lines changed

contrib/completion/git-completion.bash

Lines changed: 93 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,15 +1069,32 @@ __git_aliased_command ()
10691069
done
10701070
}
10711071

1072-
# __git_find_on_cmdline requires 1 argument
1072+
# Check whether one of the given words is present on the command line,
1073+
# and print the first word found.
1074+
#
1075+
# Usage: __git_find_on_cmdline [<option>]... "<wordlist>"
1076+
# --show-idx: Optionally show the index of the found word in the $words array.
10731077
__git_find_on_cmdline ()
10741078
{
1075-
local word subcommand c=1
1079+
local word c=1 show_idx
1080+
1081+
while test $# -gt 1; do
1082+
case "$1" in
1083+
--show-idx) show_idx=y ;;
1084+
*) return 1 ;;
1085+
esac
1086+
shift
1087+
done
1088+
local wordlist="$1"
1089+
10761090
while [ $c -lt $cword ]; do
1077-
word="${words[c]}"
1078-
for subcommand in $1; do
1079-
if [ "$subcommand" = "$word" ]; then
1080-
echo "$subcommand"
1091+
for word in $wordlist; do
1092+
if [ "$word" = "${words[c]}" ]; then
1093+
if [ -n "$show_idx" ]; then
1094+
echo "$c $word"
1095+
else
1096+
echo "$word"
1097+
fi
10811098
return
10821099
fi
10831100
done
@@ -2969,33 +2986,83 @@ _git_whatchanged ()
29692986
_git_log
29702987
}
29712988

2989+
__git_complete_worktree_paths ()
2990+
{
2991+
local IFS=$'\n'
2992+
__gitcomp_nl "$(git worktree list --porcelain |
2993+
# Skip the first entry: it's the path of the main worktree,
2994+
# which can't be moved, removed, locked, etc.
2995+
sed -n -e '2,$ s/^worktree //p')"
2996+
}
2997+
29722998
_git_worktree ()
29732999
{
29743000
local subcommands="add list lock move prune remove unlock"
2975-
local subcommand="$(__git_find_on_cmdline "$subcommands")"
2976-
if [ -z "$subcommand" ]; then
3001+
local subcommand subcommand_idx
3002+
3003+
subcommand="$(__git_find_on_cmdline --show-idx "$subcommands")"
3004+
subcommand_idx="${subcommand% *}"
3005+
subcommand="${subcommand#* }"
3006+
3007+
case "$subcommand,$cur" in
3008+
,*)
29773009
__gitcomp "$subcommands"
2978-
else
2979-
case "$subcommand,$cur" in
2980-
add,--*)
2981-
__gitcomp_builtin worktree_add
2982-
;;
2983-
list,--*)
2984-
__gitcomp_builtin worktree_list
2985-
;;
2986-
lock,--*)
2987-
__gitcomp_builtin worktree_lock
2988-
;;
2989-
prune,--*)
2990-
__gitcomp_builtin worktree_prune
2991-
;;
2992-
remove,--*)
2993-
__gitcomp "--force"
3010+
;;
3011+
*,--*)
3012+
__gitcomp_builtin worktree_$subcommand
3013+
;;
3014+
add,*) # usage: git worktree add [<options>] <path> [<commit-ish>]
3015+
# Here we are not completing an --option, it's either the
3016+
# path or a ref.
3017+
case "$prev" in
3018+
-b|-B) # Complete refs for branch to be created/reseted.
3019+
__git_complete_refs
29943020
;;
2995-
*)
3021+
-*) # The previous word is an -o|--option without an
3022+
# unstuck argument: have to complete the path for
3023+
# the new worktree, so don't list anything, but let
3024+
# Bash fall back to filename completion.
3025+
;;
3026+
*) # The previous word is not an --option, so it must
3027+
# be either the 'add' subcommand, the unstuck
3028+
# argument of an option (e.g. branch for -b|-B), or
3029+
# the path for the new worktree.
3030+
if [ $cword -eq $((subcommand_idx+1)) ]; then
3031+
# Right after the 'add' subcommand: have to
3032+
# complete the path, so fall back to Bash
3033+
# filename completion.
3034+
:
3035+
else
3036+
case "${words[cword-2]}" in
3037+
-b|-B) # After '-b <branch>': have to
3038+
# complete the path, so fall back
3039+
# to Bash filename completion.
3040+
;;
3041+
*) # After the path: have to complete
3042+
# the ref to be checked out.
3043+
__git_complete_refs
3044+
;;
3045+
esac
3046+
fi
29963047
;;
29973048
esac
2998-
fi
3049+
;;
3050+
lock,*|remove,*|unlock,*)
3051+
__git_complete_worktree_paths
3052+
;;
3053+
move,*)
3054+
if [ $cword -eq $((subcommand_idx+1)) ]; then
3055+
# The first parameter must be an existing working
3056+
# tree to be moved.
3057+
__git_complete_worktree_paths
3058+
else
3059+
# The second parameter is the destination: it could
3060+
# be any path, so don't list anything, but let Bash
3061+
# fall back to filename completion.
3062+
:
3063+
fi
3064+
;;
3065+
esac
29993066
}
30003067

30013068
__git_complete_common () {

t/t9902-completion.sh

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,63 @@ test_expect_success 'teardown after path completion tests' '
13631363
BS\\dir '$'separators\034in\035dir''
13641364
'
13651365

1366+
test_expect_success '__git_find_on_cmdline - single match' '
1367+
echo list >expect &&
1368+
(
1369+
words=(git command --opt list) &&
1370+
cword=${#words[@]} &&
1371+
__git_find_on_cmdline "add list remove" >actual
1372+
) &&
1373+
test_cmp expect actual
1374+
'
1375+
1376+
test_expect_success '__git_find_on_cmdline - multiple matches' '
1377+
echo remove >expect &&
1378+
(
1379+
words=(git command -o --opt remove list add) &&
1380+
cword=${#words[@]} &&
1381+
__git_find_on_cmdline "add list remove" >actual
1382+
) &&
1383+
test_cmp expect actual
1384+
'
1385+
1386+
test_expect_success '__git_find_on_cmdline - no match' '
1387+
(
1388+
words=(git command --opt branch) &&
1389+
cword=${#words[@]} &&
1390+
__git_find_on_cmdline "add list remove" >actual
1391+
) &&
1392+
test_must_be_empty actual
1393+
'
1394+
1395+
test_expect_success '__git_find_on_cmdline - single match with index' '
1396+
echo "3 list" >expect &&
1397+
(
1398+
words=(git command --opt list) &&
1399+
cword=${#words[@]} &&
1400+
__git_find_on_cmdline --show-idx "add list remove" >actual
1401+
) &&
1402+
test_cmp expect actual
1403+
'
1404+
1405+
test_expect_success '__git_find_on_cmdline - multiple matches with index' '
1406+
echo "4 remove" >expect &&
1407+
(
1408+
words=(git command -o --opt remove list add) &&
1409+
cword=${#words[@]} &&
1410+
__git_find_on_cmdline --show-idx "add list remove" >actual
1411+
) &&
1412+
test_cmp expect actual
1413+
'
1414+
1415+
test_expect_success '__git_find_on_cmdline - no match with index' '
1416+
(
1417+
words=(git command --opt branch) &&
1418+
cword=${#words[@]} &&
1419+
__git_find_on_cmdline --show-idx "add list remove" >actual
1420+
) &&
1421+
test_must_be_empty actual
1422+
'
13661423

13671424
test_expect_success '__git_get_config_variables' '
13681425
cat >expect <<-EOF &&

0 commit comments

Comments
 (0)