Skip to main content

ctl_core/
parser.rs

1//! Parser defaults. `-h` / `--help` and `-V` / `--version` stay on.
2
3use clap::{ColorChoice, Command};
4
5/// Apply the *ctl parser contract to a clap command.
6///
7/// `-h/--help` and `-V/--version` stay on. `disable_help_flag` is forbidden.
8/// Repeated flags last-win (`args_override_self`);
9/// [`crate::flags::chassis_warnings`] still reports the clash.
10#[must_use]
11pub fn apply_defaults(command: Command) -> Command {
12    assert_help_enabled(&command);
13    command
14        .arg_required_else_help(true)
15        .args_override_self(true)
16        .color(ColorChoice::Auto)
17        .disable_help_flag(false)
18        .disable_version_flag(false)
19}
20
21/// clap's recommended `Command::debug_assert` plus the help-flag contract.
22///
23/// # Panics
24///
25/// Panics if help or version flags were disabled.
26pub fn verify<C: clap::CommandFactory>() {
27    C::command().debug_assert();
28    assert_help_enabled(&C::command());
29}
30
31/// # Panics
32///
33/// Panics if `disable_help_flag` or `disable_version_flag` is set.
34pub fn assert_help_enabled(command: &Command) {
35    assert!(
36        !command.is_disable_help_flag_set(),
37        "disable_help_flag is forbidden; ctl-core owns -h/--help"
38    );
39    assert!(
40        !command.is_disable_version_flag_set(),
41        "disable_version_flag is forbidden; ctl-core owns -V/--version"
42    );
43}
44
45#[cfg(test)]
46mod tests {
47    use clap::{Command, CommandFactory, Parser};
48
49    use super::{apply_defaults, assert_help_enabled};
50
51    #[derive(Parser)]
52    #[command(version, about = "toy", arg_required_else_help = true)]
53    struct Toy {
54        #[command(subcommand)]
55        command: ToyCmd,
56    }
57
58    #[derive(clap::Subcommand)]
59    enum ToyCmd {
60        Status,
61    }
62
63    #[test]
64    fn verify_toy() {
65        super::verify::<Toy>();
66    }
67
68    #[test]
69    fn derive_keeps_help_and_version() {
70        let mut command = apply_defaults(Toy::command());
71        assert_help_enabled(&command);
72        assert!(command.is_args_override_self());
73        let help = command.render_long_help().to_string();
74        assert!(help.contains("-h, --help"));
75        assert!(help.contains("-V, --version"));
76    }
77
78    #[test]
79    #[should_panic(expected = "disable_help_flag is forbidden")]
80    fn rejects_disabled_help() {
81        let command = Command::new("x").disable_help_flag(true);
82        assert_help_enabled(&command);
83    }
84}