Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to enable -h / --help (short help) + --help-all (long help) #4687

Closed
2 tasks done
asottile opened this issue Jan 30, 2023 · 5 comments · Fixed by #5015
Closed
2 tasks done

how to enable -h / --help (short help) + --help-all (long help) #4687

asottile opened this issue Jan 30, 2023 · 5 comments · Fixed by #5015
Labels
A-help Area: documentation, including docs.rs, readme, examples, etc... C-enhancement Category: Raise on the bar on expectations S-waiting-on-decision Status: Waiting on a go/no-go before implementing

Comments

@asottile
Copy link

Please complete the following tasks

Clap Version

4.1.4

Describe your use case

I've found #3405 which hints at the same idea, but I wasn't able to follow whether this was implemented or not

I have this, which is close but doesn't satisfy the "--help gives short help" (mostly, I find clap's choice of -h and --help an odd one, and not one I've found precedence for elsewhere, the more common approach I've seen is --help-all or --help-full or --help-{thing} to give additional help for specific areas).

use clap::Parser;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
#[clap(disable_help_flag = true)]
struct Cli {
    /// Should always be shown in all helps
    #[arg(long)]
    someopt: String,
    /// Secret option, should only be shown in --help-all
    #[arg(long, hide_short_help = true)]
    wacky: String,
    /// Print help
    #[arg(short, long, action = clap::ArgAction::Help)]
    help: bool,
    /// Print help, including uncommon options
    #[arg(long, action = clap::ArgAction::Help)]
    help_all: bool,
}


fn main() {
    let args = Cli::parse();
    println!("Hello, world!, {:?}", args);
}

Describe the solution you'd like

maybe something like this?

    /// Print help
    #[arg(short, long, action = clap::ArgAction::HelpShort)]
    help: bool,
    /// Print help, including uncommon options
    #[arg(long, action = clap::ArgAction::HelpLong)]
    help_all: bool,

(HelpShort / HelpLong)

Alternatives, if applicable

I am very new to clap, so I'd be happy enough if there's already a solution to this

Additional Context

for example, python's help:

$ python3.12 --help
usage: python3.12 [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options (and corresponding environment variables):
-b     : issue warnings about str(bytes_instance), str(bytearray_instance)
         and comparing bytes/bytearray with str. (-bb: issue errors)
...
--help-env      : print help about Python environment variables and exit
--help-xoptions : print help about implementation-specific -X options and exit
--help-all      : print complete help information and exit
Arguments:
file   : program read from script file
-      : program read from stdin (default; interactive mode if a tty)
arg ...: arguments passed to program in sys.argv[1:]
@asottile asottile added the C-enhancement Category: Raise on the bar on expectations label Jan 30, 2023
@epage
Copy link
Member

epage commented Jan 30, 2023

For now, what you will need to do is use ArgAction::SetTrue, call CommandFactory::command on the top-level command, then call the appropriate short/long help rendering functions on Command.

Hmm, I'm not finding in the notes why HelpShort and HelpLong weren't implemented. I then assumed it was left to an issue but not finding an issue for it. I vaguely remember considering ways to generalize this but do not remember the details, seeing as we are trying to keep the API small for easier discovery and for reduced compile times / API size.

If we do this, we'd need similar for Version.

@epage epage added S-waiting-on-decision Status: Waiting on a go/no-go before implementing A-help Area: documentation, including docs.rs, readme, examples, etc... labels Jan 30, 2023
@asottile
Copy link
Author

cool! are those available in the derive notation? -- or would it be more that I check the arguments manually after Cli::parse() instead of using ArgAction::Help ?

@epage
Copy link
Member

epage commented Jan 30, 2023

Yes, those instructions are for doing it manually.

let args = Cli::parse();
if args.help {
    let mut cmd = Cli::command();
    cmd.build();
    cmd.print_help();
    std::process::exit(0);
} else if args.help_all {
    let mut cmd = Cli::command();
    cmd.build();
    cmd.print_long_help();
    std::process::exit(0);
}

@asottile
Copy link
Author

ah neat, unfortunately my case is a little more complicated and I've got subcommands -- so I need something more like:

    // I just let `help_all` use `action = ArgAction::Help` since it always triggers `long` help anyway!

    if matches!(res.command, Some(Commands::Run(Run { help: true, .. }))) {
        let mut cmd = Cli::command();
        cmd.build();
        cmd.find_subcommand_mut("run").unwrap().print_help()?;
        std::process::exit(0);
    }

this works fine for things which don't have any required arguments -- but as soon as there are required arguments it's too late to trigger the store_true or ::Help (as an error occurs on the missing required argument)

@epage
Copy link
Member

epage commented Jul 17, 2023

The main delay here is going back and forth on what this should look like from the API. I figured, rather than worrying about perfection, I'll implement something and we can always change it when v5 comes around

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-help Area: documentation, including docs.rs, readme, examples, etc... C-enhancement Category: Raise on the bar on expectations S-waiting-on-decision Status: Waiting on a go/no-go before implementing
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants