Skip to content

feat(complete): group options by tag (in zsh)#6334

Open
bobrippling wants to merge 3 commits intoclap-rs:masterfrom
bobrippling:feat/zsh-completion-grouping
Open

feat(complete): group options by tag (in zsh)#6334
bobrippling wants to merge 3 commits intoclap-rs:masterfrom
bobrippling:feat/zsh-completion-grouping

Conversation

@bobrippling
Copy link
Copy Markdown

@bobrippling bobrippling commented Apr 3, 2026

This allows zsh to group completions by whether they're global, and then by their tag. For example:

$ dynamic -<tab>
completing "global" options
-v  -- --verbose
completing "Options" options
-F  -- --format
-h  -- Print help
-i  -- --input

Closes #6320

Outstanding Questions

Options name

completing "Options" options doesn't seem particulary nice, should we filter out the default "Options" tag?

arg.get_help_heading()
.unwrap_or("Options")
.to_owned()

when generating the completions in shells.rs

Tests

My new test is currently failing because it gets the zsh initial login setup:

This is the Z Shell configuration function for new users,
zsh-newuser-install.
You are seeing this message because you have no zsh startup files
(the files .zshenv, .zprofile, .zshrc, .zlogin in the directory
/tmp/.tmpQxncRl).  This function can help you with a few settings that should
make your use of the shell easier.
[...]
Aborting.
The function will be run again next time.  To prevent this, execute:
  touch /tmp/.tmpQxncRl/.zshrc

I'm not sure why my test gets this but the others don't

@bobrippling bobrippling force-pushed the feat/zsh-completion-grouping branch 11 times, most recently from e5a4b4d to 629cac1 Compare April 11, 2026 16:26
@bobrippling bobrippling marked this pull request as ready for review April 11, 2026 16:37
@bobrippling bobrippling changed the title feat(complete): group options by tag (in zsh) feat(complete): group options by global state and tag (in zsh) Apr 11, 2026
@bobrippling bobrippling force-pushed the feat/zsh-completion-grouping branch 3 times, most recently from a419619 to 65f0b45 Compare April 11, 2026 17:19
This allows us to label an option as `global`, for testing

Also register `dynamic` as a test example
@bobrippling bobrippling force-pushed the feat/zsh-completion-grouping branch from 65f0b45 to b161c88 Compare April 11, 2026 19:35
Comment thread clap_complete/src/engine/candidate.rs Outdated
Comment on lines +50 to +53
/// Group candidates based on if they are global
///
/// Future: these may become user-visible
pub fn global(mut self, global: bool) -> Self {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is separate from the rest of this PR and should be split out. Likely we should even discuss it in an issue first, per our contrib guide

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I've split out the global change. I've created a new issue to discuss it - #6343.
My goal with the current issue was to split global and non-global options, let me know if you'd like me to tweak it so it's more clear it's about tagging

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review and feedback btw - I'm currently not home but I'll be able to get round to making changes soon

@bobrippling bobrippling force-pushed the feat/zsh-completion-grouping branch from b161c88 to 0609ae5 Compare April 13, 2026 17:11
@epage epage changed the title feat(complete): group options by global state and tag (in zsh) feat(complete): group options by tag (in zsh) Apr 13, 2026
#[cfg(feature = "unstable-shell-tests")]
fn register_dynamic_env() {
common::register_example::<RuntimeBuilder>("dynamic-env", "exhaustive");
common::register_example::<RuntimeBuilder>("dynamic-env", "dynamic");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests are testing using exhaustive which already has a global(true) on it.

Is this unused? Do we then need to add the global arg?

Comment on lines 388 to +402
if [[ "$value" == */ ]]; then
local dir_no_slash="${value%/}"
if [[ "$completion" == *:* ]]; then
local desc="${completion#*:}"
if [[ "$value" == *:* ]]; then
local desc="${value#*:}"
dirs+=("$dir_no_slash:$desc")
else
dirs+=("$dir_no_slash")
fi
else
other+=("$completion")
if (( ${+tag_map["$tag"]} )); then # key exists?
tag_map["$tag"]+=$'\n'"$value"
else
tag_map["$tag"]="$value"
fi
fi
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean we aren't getting the / handling if a tag is present?

}
write!(
buf,
"{}:",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is : is in a tag?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No test output changed in this commit. Are the commits not atomic or are they not covering the right behavior?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Zsh completion tagging / grouping

3 participants