Skip to content

Commit 9e85b97

Browse files
committed
feat: Group options by tag (in zsh)
1 parent 2b1b0af commit 9e85b97

3 files changed

Lines changed: 81 additions & 33 deletions

File tree

clap_complete/src/env/shells.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::ffi::OsString;
22
use std::str::FromStr;
33

44
use super::EnvCompleter;
5+
use clap::builder::StyledStr;
56

67
/// Bash completion adapter
78
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -376,25 +377,39 @@ function _clap_dynamic_completer_NAME() {
376377
)}")
377378
378379
if [[ -n $completions ]]; then
380+
local -A tag_map
379381
local -a dirs=()
380-
local -a other=()
381382
local completion
383+
local tag
384+
local value
385+
382386
for completion in $completions; do
383-
local value="${completion%%:*}"
387+
IFS=: read -r tag value <<< "$completion"
384388
if [[ "$value" == */ ]]; then
385389
local dir_no_slash="${value%/}"
386-
if [[ "$completion" == *:* ]]; then
387-
local desc="${completion#*:}"
390+
if [[ "$value" == *:* ]]; then
391+
local desc="${value#*:}"
388392
dirs+=("$dir_no_slash:$desc")
389393
else
390394
dirs+=("$dir_no_slash")
391395
fi
392396
else
393-
other+=("$completion")
397+
if (( ${+tag_map["$tag"]} )); then # key exists?
398+
tag_map["$tag"]+=$'\n'"$value"
399+
else
400+
tag_map["$tag"]="$value"
401+
fi
402+
fi
403+
done
404+
[[ -n $dirs ]] && _describe -t dirs 'values' dirs -S '/' -r '/'
405+
for tag in ${(k)tag_map}; do
406+
values=("${(@f)tag_map[$tag]}") # split on newline
407+
if [[ -n $tag ]]; then
408+
_describe -t "$tag" "$tag options" values
409+
else
410+
_describe "options" values
394411
fi
395412
done
396-
[[ -n $dirs ]] && _describe 'values' dirs -S '/' -r '/'
397-
[[ -n $other ]] && _describe 'values' other
398413
fi
399414
}
400415
@@ -431,6 +446,12 @@ compdef _clap_dynamic_completer_NAME BIN"#
431446
if i != 0 {
432447
write!(buf, "{}", ifs.as_deref().unwrap_or("\n"))?;
433448
}
449+
write!(
450+
buf,
451+
"{}:",
452+
candidate.get_tag().unwrap_or(&StyledStr::from("")),
453+
)?;
454+
434455
write!(
435456
buf,
436457
"{}",

clap_complete/tests/snapshots/home/dynamic-env/exhaustive/zsh/zsh/_exhaustive

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,39 @@ function _clap_dynamic_completer_exhaustive() {
1111
)}")
1212

1313
if [[ -n $completions ]]; then
14+
local -A tag_map
1415
local -a dirs=()
15-
local -a other=()
1616
local completion
17+
local tag
18+
local value
19+
1720
for completion in $completions; do
18-
local value="${completion%%:*}"
21+
IFS=: read -r tag value <<< "$completion"
1922
if [[ "$value" == */ ]]; then
2023
local dir_no_slash="${value%/}"
21-
if [[ "$completion" == *:* ]]; then
22-
local desc="${completion#*:}"
24+
if [[ "$value" == *:* ]]; then
25+
local desc="${value#*:}"
2326
dirs+=("$dir_no_slash:$desc")
2427
else
2528
dirs+=("$dir_no_slash")
2629
fi
2730
else
28-
other+=("$completion")
31+
if (( ${+tag_map["$tag"]} )); then # key exists?
32+
tag_map["$tag"]+=$'\n'"$value"
33+
else
34+
tag_map["$tag"]="$value"
35+
fi
36+
fi
37+
done
38+
[[ -n $dirs ]] && _describe -t dirs 'values' dirs -S '/' -r '/'
39+
for tag in ${(k)tag_map}; do
40+
values=("${(@f)tag_map[$tag]}") # split on newline
41+
if [[ -n $tag ]]; then
42+
_describe -t "$tag" "$tag options" values
43+
else
44+
_describe "options" values
2945
fi
3046
done
31-
[[ -n $dirs ]] && _describe 'values' dirs -S '/' -r '/'
32-
[[ -n $other ]] && _describe 'values' other
3347
fi
3448
}
3549

clap_complete/tests/testsuite/zsh.rs

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ fn complete_dynamic_env_toplevel() {
253253
% exhaustive
254254
--generate -- generate
255255
--help -- Print help
256-
help -- Print this message or the help of the given subcommand(s)
256+
help -- Print this message or the help of the given subcommand(s)
257257
--empty-choice alias global last quote
258258
action empty hint pacman value
259259
"#]];
@@ -275,15 +275,21 @@ fn complete_dynamic_env_quoted_help() {
275275
let input = "exhaustive quote \t\t";
276276
let expected = snapbox::str![[r#"
277277
% exhaustive quote
278-
--help -- Print help (see more with '--help')
279-
cmd-backslash --backslash -- Avoid '/n'
280-
cmd-backticks --backticks -- For more information see `echo test`
281-
cmd-brackets --brackets -- List packages [filter]
282-
cmd-double-quotes --double-quotes -- Can be "always", "auto", or "never"
283-
cmd-expansions --expansions -- Execute the shell command with $SHELL
284-
cmd-single-quotes --single-quotes -- Can be 'always', 'auto', or 'never'
285-
escape-help -- /tab/t"'
286-
help -- Print this message or the help of the given subcommand(s)
278+
--backslash -- Avoid '/n'
279+
--backticks -- For more information see `echo test`
280+
--brackets -- List packages [filter]
281+
--double-quotes -- Can be "always", "auto", or "never"
282+
--expansions -- Execute the shell command with $SHELL
283+
--help -- Print help (see more with '--help')
284+
--single-quotes -- Can be 'always', 'auto', or 'never'
285+
cmd-backslash -- Avoid '/n'
286+
cmd-backticks -- For more information see `echo test`
287+
cmd-brackets -- List packages [filter]
288+
cmd-double-quotes -- Can be "always", "auto", or "never"
289+
cmd-expansions -- Execute the shell command with $SHELL
290+
cmd-single-quotes -- Can be 'always', 'auto', or 'never'
291+
escape-help -- /tab "'
292+
help -- Print this message or the help of the given subcommand(s)
287293
--choice
288294
"#]];
289295
let actual = runtime.complete(input, &term).unwrap();
@@ -392,15 +398,21 @@ fn complete_dynamic_empty_space() {
392398
let input = "exhaustive quote -\x1b[D\x1b[D\t\t";
393399
let expected = snapbox::str![[r#"
394400
% exhaustive quote -
395-
--help -- Print help (see more with '--help')
396-
cmd-backslash --backslash -- Avoid '/n'
397-
cmd-backticks --backticks -- For more information see `echo test`
398-
cmd-brackets --brackets -- List packages [filter]
399-
cmd-double-quotes --double-quotes -- Can be "always", "auto", or "never"
400-
cmd-expansions --expansions -- Execute the shell command with $SHELL
401-
cmd-single-quotes --single-quotes -- Can be 'always', 'auto', or 'never'
402-
escape-help -- /tab/t"'
403-
help -- Print this message or the help of the given subcommand(s)
401+
--backslash -- Avoid '/n'
402+
--backticks -- For more information see `echo test`
403+
--brackets -- List packages [filter]
404+
--double-quotes -- Can be "always", "auto", or "never"
405+
--expansions -- Execute the shell command with $SHELL
406+
--help -- Print help (see more with '--help')
407+
--single-quotes -- Can be 'always', 'auto', or 'never'
408+
cmd-backslash -- Avoid '/n'
409+
cmd-backticks -- For more information see `echo test`
410+
cmd-brackets -- List packages [filter]
411+
cmd-double-quotes -- Can be "always", "auto", or "never"
412+
cmd-expansions -- Execute the shell command with $SHELL
413+
cmd-single-quotes -- Can be 'always', 'auto', or 'never'
414+
escape-help -- /tab "'
415+
help -- Print this message or the help of the given subcommand(s)
404416
--choice
405417
"#]];
406418
let actual = runtime.complete(input, &term).unwrap();
@@ -457,6 +469,7 @@ fn complete_dynamic_tagged_options() {
457469
% zstyle ':completion:*' group-name ''
458470
% zstyle ':completion:*:descriptions' format '%d'
459471
% exhaustive -
472+
"Options" options
460473
--generate -- generate
461474
-h -- Print help
462475
--empty-choice

0 commit comments

Comments
 (0)