Search code examples
rustclap

Include long options without short options for help and version


I would like to include --help and --version long options without the -h and -V short options. Is this possible?

I'm using clap with yaml. The closest I've been able to come up with is to use hidden (unused) args that mask the short options.

# main.rs
use clap::{load_yaml, App};
fn main() {
  let y = load_yaml!("cli.yaml");
  let m = App::from_yaml(y).get_matches();
  println!("_help {}", m.is_present("_help"));
  println!("_version {}", m.is_present("_version"));
}
# Cargo.toml
[package]
name = "app"
version = "0.0.1"
edition = "2018"

[dependencies]
clap = {version = "~2.33.0", features = ["yaml"]}
# cli.yaml
name: app
version: 0.0.1
args:
  - opt: { short: "o", long: "opt" }
  - _help: { short: "h", hidden: true }
  - _version: { short: "V", hidden: true }
$ cargo -q run -- --help
app 0.0.1

USAGE:
    app [FLAGS]

FLAGS:
        --help       Prints help information
    -o, --opt        
        --version    Prints version information

$ cargo -q run -- -h    
_help true
_version false
$ cargo -q run -- -o
_help false
_version false
$ cargo -q run -- -V
_help false
_version true
$ cargo -q run -- -x
error: Found argument '-x' which wasn't expected, or isn't valid in this context

USAGE:
    app [FLAGS]

For more information try --help

This doesn't feel like a very clean approach. Is there another/better way?


Solution

  • Clap is designed more towards creating an args parser. So there aren't really that much functionality for getting and removing existing arguments.

    If you simply want to rename "-h" to e.g. "-?", then you can do that with help_short("-?") (see also version_short().)

    However, there are ways to work around it.


    Assuming you're using e.g. clap = "2.33". Then similarly to what you're already doing, you can override/replace the help and version args, and in that way "remove" the short versions. (For brevity, I'll only include examples for help.)

    You can of course keep it in cli.yaml if you want, but I'll add it to main.rs. In short, you want to add a new "help" arg and only give it a long version. It's important that you include help("Prints help information") as this is replacing the existing help arg, so if you don't it won't have the default help message for --help.

    The downside to overring "help" is that you'd need to handle print_help() yourself.

    use clap::{load_yaml, App, Arg};
    
    fn main() {
        let y = load_yaml!("cli.yaml");
        let mut app = App::from_yaml(y)
            .arg(
                Arg::with_name("help")
                    .long("help")
                    .help("Prints help information"),
            );
    
        let m = app.clone().get_matches();
    
        if m.is_present("help") {
            app.print_help().unwrap();
            // std::process::exit(0);
            // or just
            return;
        }
    }
    

    However, if you're using clap = "3.0.0-beta.2" then that simplifies things, with the introduction of mut_arg(). Because that allows us to mutate the argument. Thereby, we no longer need to call print_help() ourselves.

    use clap::{load_yaml, App, Arg};
    
    fn main() {
        let y = load_yaml!("cli.yaml");
        let m = App::from(y)
            .mut_arg("help", |h| {
                Arg::new("help")
                    .long("help")
                    .about("Prints help information")
            })
            .get_matches();
    }
    

    Note that App::from_yaml() is now App::from(), while Arg::with_name() has become Arg::new(), and help() is now about().