Skip to content

Commit e1c3575

Browse files
authored
Merge pull request #5256 from Serock3/master
fix(clap_complete): Use bin name instead of package name for bash completions in subcommands
2 parents ef45f2d + ba378e6 commit e1c3575

File tree

11 files changed

+393
-5
lines changed

11 files changed

+393
-5
lines changed

clap_complete/src/shells/bash.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ impl Generator for Bash {
1818
.get_bin_name()
1919
.expect("crate::generate should have set the bin_name");
2020

21+
let fn_name = bin_name.replace('-', "__");
22+
2123
w!(
2224
buf,
2325
format!(
@@ -65,18 +67,18 @@ else
6567
fi
6668
",
6769
name = bin_name,
68-
cmd = bin_name.replace('-', "__"),
70+
cmd = fn_name,
6971
name_opts = all_options_for_path(cmd, bin_name),
7072
name_opts_details = option_details_for_path(cmd, bin_name),
71-
subcmds = all_subcommands(cmd),
73+
subcmds = all_subcommands(cmd, &fn_name),
7274
subcmd_details = subcommand_details(cmd)
7375
)
7476
.as_bytes()
7577
);
7678
}
7779
}
7880

79-
fn all_subcommands(cmd: &Command) -> String {
81+
fn all_subcommands(cmd: &Command, parent_fn_name: &str) -> String {
8082
debug!("all_subcommands");
8183

8284
fn add_command(
@@ -106,9 +108,8 @@ fn all_subcommands(cmd: &Command) -> String {
106108
}
107109
}
108110
let mut subcmds = vec![];
109-
let fn_name = cmd.get_name().replace('-', "__");
110111
for subcmd in cmd.get_subcommands() {
111-
add_command(&fn_name, subcmd, &mut subcmds);
112+
add_command(parent_fn_name, subcmd, &mut subcmds);
112113
}
113114
subcmds.sort();
114115

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
_bin-name() {
2+
local i cur prev opts cmd
3+
COMPREPLY=()
4+
cur="${COMP_WORDS[COMP_CWORD]}"
5+
prev="${COMP_WORDS[COMP_CWORD-1]}"
6+
cmd=""
7+
opts=""
8+
9+
for i in ${COMP_WORDS[@]}
10+
do
11+
case "${cmd},${i}" in
12+
",$1")
13+
cmd="bin__name"
14+
;;
15+
bin__name,help)
16+
cmd="bin__name__help"
17+
;;
18+
bin__name,test)
19+
cmd="bin__name__test"
20+
;;
21+
bin__name__help,help)
22+
cmd="bin__name__help__help"
23+
;;
24+
bin__name__help,test)
25+
cmd="bin__name__help__test"
26+
;;
27+
*)
28+
;;
29+
esac
30+
done
31+
32+
case "${cmd}" in
33+
bin__name)
34+
opts="-c -v -h --help test help"
35+
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
36+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
37+
return 0
38+
fi
39+
case "${prev}" in
40+
*)
41+
COMPREPLY=()
42+
;;
43+
esac
44+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
45+
return 0
46+
;;
47+
bin__name__help)
48+
opts="test help"
49+
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
50+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
51+
return 0
52+
fi
53+
case "${prev}" in
54+
*)
55+
COMPREPLY=()
56+
;;
57+
esac
58+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
59+
return 0
60+
;;
61+
bin__name__help__help)
62+
opts=""
63+
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
64+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
65+
return 0
66+
fi
67+
case "${prev}" in
68+
*)
69+
COMPREPLY=()
70+
;;
71+
esac
72+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
73+
return 0
74+
;;
75+
bin__name__help__test)
76+
opts=""
77+
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
78+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
79+
return 0
80+
fi
81+
case "${prev}" in
82+
*)
83+
COMPREPLY=()
84+
;;
85+
esac
86+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
87+
return 0
88+
;;
89+
bin__name__test)
90+
opts="-d -c -h --help"
91+
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
92+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
93+
return 0
94+
fi
95+
case "${prev}" in
96+
*)
97+
COMPREPLY=()
98+
;;
99+
esac
100+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
101+
return 0
102+
;;
103+
esac
104+
}
105+
106+
if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then
107+
complete -F _bin-name -o nosort -o bashdefault -o default bin-name
108+
else
109+
complete -F _bin-name -o bashdefault -o default bin-name
110+
fi
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
use builtin;
3+
use str;
4+
5+
set edit:completion:arg-completer[bin-name] = {|@words|
6+
fn spaces {|n|
7+
builtin:repeat $n ' ' | str:join ''
8+
}
9+
fn cand {|text desc|
10+
edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc
11+
}
12+
var command = 'bin-name'
13+
for word $words[1..-1] {
14+
if (str:has-prefix $word '-') {
15+
break
16+
}
17+
set command = $command';'$word
18+
}
19+
var completions = [
20+
&'bin-name'= {
21+
cand -c 'c'
22+
cand -v 'v'
23+
cand -h 'Print help'
24+
cand --help 'Print help'
25+
cand test 'Subcommand'
26+
cand help 'Print this message or the help of the given subcommand(s)'
27+
}
28+
&'bin-name;test'= {
29+
cand -d 'd'
30+
cand -c 'c'
31+
cand -h 'Print help'
32+
cand --help 'Print help'
33+
}
34+
&'bin-name;help'= {
35+
cand test 'Subcommand'
36+
cand help 'Print this message or the help of the given subcommand(s)'
37+
}
38+
&'bin-name;help;test'= {
39+
}
40+
&'bin-name;help;help'= {
41+
}
42+
]
43+
$completions[$command]
44+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
complete -c bin-name -n "__fish_use_subcommand" -s c
2+
complete -c bin-name -n "__fish_use_subcommand" -s v
3+
complete -c bin-name -n "__fish_use_subcommand" -s h -l help -d 'Print help'
4+
complete -c bin-name -n "__fish_use_subcommand" -f -a "test" -d 'Subcommand'
5+
complete -c bin-name -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
6+
complete -c bin-name -n "__fish_seen_subcommand_from test" -s d
7+
complete -c bin-name -n "__fish_seen_subcommand_from test" -s c
8+
complete -c bin-name -n "__fish_seen_subcommand_from test" -s h -l help -d 'Print help'
9+
complete -c bin-name -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from test; and not __fish_seen_subcommand_from help" -f -a "test" -d 'Subcommand'
10+
complete -c bin-name -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from test; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
2+
using namespace System.Management.Automation
3+
using namespace System.Management.Automation.Language
4+
5+
Register-ArgumentCompleter -Native -CommandName 'bin-name' -ScriptBlock {
6+
param($wordToComplete, $commandAst, $cursorPosition)
7+
8+
$commandElements = $commandAst.CommandElements
9+
$command = @(
10+
'bin-name'
11+
for ($i = 1; $i -lt $commandElements.Count; $i++) {
12+
$element = $commandElements[$i]
13+
if ($element -isnot [StringConstantExpressionAst] -or
14+
$element.StringConstantType -ne [StringConstantType]::BareWord -or
15+
$element.Value.StartsWith('-') -or
16+
$element.Value -eq $wordToComplete) {
17+
break
18+
}
19+
$element.Value
20+
}) -join ';'
21+
22+
$completions = @(switch ($command) {
23+
'bin-name' {
24+
[CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'c')
25+
[CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'v')
26+
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help')
27+
[CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help')
28+
[CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'Subcommand')
29+
[CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)')
30+
break
31+
}
32+
'bin-name;test' {
33+
[CompletionResult]::new('-d', 'd', [CompletionResultType]::ParameterName, 'd')
34+
[CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'c')
35+
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help')
36+
[CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help')
37+
break
38+
}
39+
'bin-name;help' {
40+
[CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'Subcommand')
41+
[CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)')
42+
break
43+
}
44+
'bin-name;help;test' {
45+
break
46+
}
47+
'bin-name;help;help' {
48+
break
49+
}
50+
})
51+
52+
$completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
53+
Sort-Object -Property ListItemText
54+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#compdef bin-name
2+
3+
autoload -U is-at-least
4+
5+
_bin-name() {
6+
typeset -A opt_args
7+
typeset -a _arguments_options
8+
local ret=1
9+
10+
if is-at-least 5.2; then
11+
_arguments_options=(-s -S -C)
12+
else
13+
_arguments_options=(-s -C)
14+
fi
15+
16+
local context curcontext="$curcontext" state line
17+
_arguments "${_arguments_options[@]}" \
18+
'-c[]' \
19+
'(-c)-v[]' \
20+
'-h[Print help]' \
21+
'--help[Print help]' \
22+
":: :_bin-name_commands" \
23+
"*::: :->my-app" \
24+
&& ret=0
25+
case $state in
26+
(my-app)
27+
words=($line[1] "${words[@]}")
28+
(( CURRENT += 1 ))
29+
curcontext="${curcontext%:*:*}:bin-name-command-$line[1]:"
30+
case $line[1] in
31+
(test)
32+
_arguments "${_arguments_options[@]}" \
33+
'*-d[]' \
34+
'-c[]' \
35+
'-h[Print help]' \
36+
'--help[Print help]' \
37+
&& ret=0
38+
;;
39+
(help)
40+
_arguments "${_arguments_options[@]}" \
41+
":: :_bin-name__help_commands" \
42+
"*::: :->help" \
43+
&& ret=0
44+
45+
case $state in
46+
(help)
47+
words=($line[1] "${words[@]}")
48+
(( CURRENT += 1 ))
49+
curcontext="${curcontext%:*:*}:bin-name-help-command-$line[1]:"
50+
case $line[1] in
51+
(test)
52+
_arguments "${_arguments_options[@]}" \
53+
&& ret=0
54+
;;
55+
(help)
56+
_arguments "${_arguments_options[@]}" \
57+
&& ret=0
58+
;;
59+
esac
60+
;;
61+
esac
62+
;;
63+
esac
64+
;;
65+
esac
66+
}
67+
68+
(( $+functions[_bin-name_commands] )) ||
69+
_bin-name_commands() {
70+
local commands; commands=(
71+
'test:Subcommand' \
72+
'help:Print this message or the help of the given subcommand(s)' \
73+
)
74+
_describe -t commands 'bin-name commands' commands "$@"
75+
}
76+
(( $+functions[_bin-name__help_commands] )) ||
77+
_bin-name__help_commands() {
78+
local commands; commands=(
79+
'test:Subcommand' \
80+
'help:Print this message or the help of the given subcommand(s)' \
81+
)
82+
_describe -t commands 'bin-name help commands' commands "$@"
83+
}
84+
(( $+functions[_bin-name__help__help_commands] )) ||
85+
_bin-name__help__help_commands() {
86+
local commands; commands=()
87+
_describe -t commands 'bin-name help help commands' commands "$@"
88+
}
89+
(( $+functions[_bin-name__help__test_commands] )) ||
90+
_bin-name__help__test_commands() {
91+
local commands; commands=()
92+
_describe -t commands 'bin-name help test commands' commands "$@"
93+
}
94+
(( $+functions[_bin-name__test_commands] )) ||
95+
_bin-name__test_commands() {
96+
local commands; commands=()
97+
_describe -t commands 'bin-name test commands' commands "$@"
98+
}
99+
100+
if [ "$funcstack[1]" = "_bin-name" ]; then
101+
_bin-name "$@"
102+
else
103+
compdef _bin-name bin-name
104+
fi

clap_complete/tests/testsuite/bash.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@ fn sub_subcommands() {
7272
);
7373
}
7474

75+
#[test]
76+
fn custom_bin_name() {
77+
let name = "my-app";
78+
let bin_name = "bin-name";
79+
let cmd = common::basic_command(name);
80+
common::assert_matches_path(
81+
"tests/snapshots/custom_bin_name.bash",
82+
clap_complete::shells::Bash,
83+
cmd,
84+
bin_name,
85+
);
86+
}
87+
7588
#[test]
7689
fn value_hint() {
7790
let name = "my-app";

0 commit comments

Comments
 (0)