diff --git a/clap_complete/examples/dynamic.rs b/clap_complete/examples/dynamic.rs index ccaf7d8ad2d..0813b7fe6a0 100644 --- a/clap_complete/examples/dynamic.rs +++ b/clap_complete/examples/dynamic.rs @@ -1,19 +1,36 @@ +use clap::builder::PossibleValue; use clap::FromArgMatches; use clap::Subcommand; fn command() -> clap::Command { let cmd = clap::Command::new("dynamic") + .subcommand( + clap::Command::new("hidden") + .about("Hidden subcommand") + .hide(true), + ) .arg( clap::Arg::new("input") .long("input") .short('i') .value_hint(clap::ValueHint::FilePath), ) + .arg( + clap::Arg::new("output") + .long("output") + .short('o') + .hide(true) + .value_hint(clap::ValueHint::FilePath), + ) .arg( clap::Arg::new("format") .long("format") .short('F') - .value_parser(["json", "yaml", "toml"]), + .value_parser([ + PossibleValue::new("json"), + PossibleValue::new("yaml"), + PossibleValue::new("toml").hide(true), + ]), ) .args_conflicts_with_subcommands(true); clap_complete::dynamic::shells::CompleteCommand::augment_subcommands(cmd) diff --git a/clap_complete/src/dynamic/completer.rs b/clap_complete/src/dynamic/completer.rs index 232dd4bfc37..7267d178603 100644 --- a/clap_complete/src/dynamic/completer.rs +++ b/clap_complete/src/dynamic/completer.rs @@ -118,7 +118,10 @@ fn complete_arg( } } else { completions.extend(longs_and_visible_aliases(cmd).into_iter().filter_map( - |(f, help)| f.starts_with(flag).then(|| (format!("--{f}").into(), help)), + |(f, a)| { + f.starts_with(flag) + .then(|| (format!("--{f}").into(), a.get_help().cloned())) + }, )); } } @@ -127,7 +130,8 @@ fn complete_arg( completions.extend( longs_and_visible_aliases(cmd) .into_iter() - .map(|(f, help)| (format!("--{f}").into(), help)), + .filter(|(_, a)| !a.is_hide_set()) + .map(|(f, a)| (format!("--{f}").into(), a.get_help().cloned())), ); } @@ -171,11 +175,16 @@ fn complete_arg_value( if let Some(possible_values) = possible_values(arg) { if let Ok(value) = value { - values.extend(possible_values.into_iter().filter_map(|p| { - let name = p.get_name(); - name.starts_with(value) - .then(|| (name.into(), p.get_help().cloned())) - })); + values.extend( + possible_values + .into_iter() + .filter(|p| value != "" || !p.is_hide_set()) + .filter_map(|p| { + let name = p.get_name(); + name.starts_with(value) + .then(|| (name.into(), p.get_help().cloned())) + }), + ); } } else { let value_os = match value { @@ -277,8 +286,8 @@ fn complete_subcommand(value: &str, cmd: &clap::Command) -> Vec<(OsString, Optio let mut scs = subcommands(cmd) .into_iter() - .filter(|x| x.0.starts_with(value)) - .map(|x| (OsString::from(&x.0), x.1)) + .filter(|(n, sc)| n.starts_with(value) && (value != "" || !sc.is_hide_set())) + .map(|(n, sc)| (OsString::from(&n), sc.get_about().cloned())) .collect::>(); scs.sort(); scs.dedup(); @@ -287,16 +296,13 @@ fn complete_subcommand(value: &str, cmd: &clap::Command) -> Vec<(OsString, Optio /// Gets all the long options, their visible aliases and flags of a [`clap::Command`]. /// Includes `help` and `version` depending on the [`clap::Command`] settings. -fn longs_and_visible_aliases(p: &clap::Command) -> Vec<(String, Option)> { +fn longs_and_visible_aliases(p: &clap::Command) -> Vec<(String, &clap::Arg)> { debug!("longs: name={}", p.get_name()); p.get_arguments() .filter_map(|a| { - a.get_long_and_visible_aliases().map(|longs| { - longs - .into_iter() - .map(|s| (s.to_string(), a.get_help().cloned())) - }) + a.get_long_and_visible_aliases() + .map(move |longs| longs.into_iter().map(move |s| (s.to_string(), a))) }) .flatten() .collect() @@ -308,6 +314,7 @@ fn shorts_and_visible_aliases(p: &clap::Command) -> Vec<(char, Option debug!("shorts: name={}", p.get_name()); p.get_arguments() + .filter(|a| !a.is_hide_set()) .filter_map(|a| { a.get_short_and_visible_aliases() .map(|shorts| shorts.into_iter().map(|s| (s, a.get_help().cloned()))) @@ -331,11 +338,11 @@ fn possible_values(a: &clap::Arg) -> Option> { /// /// Subcommand `rustup toolchain install` would be converted to /// `("install", "rustup toolchain install")`. -fn subcommands(p: &clap::Command) -> Vec<(String, Option)> { +fn subcommands(p: &clap::Command) -> Vec<(String, &clap::Command)> { debug!("subcommands: name={}", p.get_name()); debug!("subcommands: Has subcommands...{:?}", p.has_subcommands()); p.get_subcommands() - .map(|sc| (sc.get_name().to_string(), sc.get_about().cloned())) + .map(|sc| (sc.get_name().to_string(), sc)) .collect() } diff --git a/clap_complete/tests/testsuite/dynamic.rs b/clap_complete/tests/testsuite/dynamic.rs index 7389713874f..8f8b3786319 100644 --- a/clap_complete/tests/testsuite/dynamic.rs +++ b/clap_complete/tests/testsuite/dynamic.rs @@ -19,7 +19,7 @@ macro_rules! complete { fn suggest_subcommand_subset() { let mut cmd = Command::new("exhaustive") .subcommand(Command::new("hello-world")) - .subcommand(Command::new("hello-moon")) + .subcommand(Command::new("hello-moon").hide(true)) .subcommand(Command::new("goodbye-world")); snapbox::assert_eq( @@ -28,6 +28,15 @@ hello-world help\tPrint this message or the help of the given subcommand(s)", complete!(cmd, "he"), ); + + snapbox::assert_eq( + "--help\tPrint help +-h\tPrint help +goodbye-world +hello-world +help\tPrint this message or the help of the given subcommand(s)", + complete!(cmd, " "), + ); } #[test] @@ -41,7 +50,8 @@ fn suggest_long_flag_subset() { .arg( clap::Arg::new("hello-moon") .long("hello-moon") - .action(clap::ArgAction::Count), + .action(clap::ArgAction::Count) + .hide(true), ) .arg( clap::Arg::new("goodbye-world") @@ -55,6 +65,14 @@ fn suggest_long_flag_subset() { --help\tPrint help", complete!(cmd, "--he"), ); + + snapbox::assert_eq( + "--hello-world +--goodbye-world +--help\tPrint help +-h\tPrint help", + complete!(cmd, " "), + ); } #[test] @@ -62,7 +80,7 @@ fn suggest_possible_value_subset() { let name = "exhaustive"; let mut cmd = Command::new(name).arg(clap::Arg::new("hello-world").value_parser([ PossibleValue::new("hello-world").help("Say hello to the world"), - "hello-moon".into(), + PossibleValue::new("hello-moon").hide(true), "goodbye-world".into(), ])); @@ -71,6 +89,14 @@ fn suggest_possible_value_subset() { hello-moon", complete!(cmd, "hello"), ); + + snapbox::assert_eq( + "--help\tPrint help (see more with '--help') +-h\tPrint help (see more with '--help') +hello-world\tSay hello to the world +goodbye-world", + complete!(cmd, " "), + ); } #[test]