2

The clap crate implements built-in behaviour for the -h option, but it doesn't seem to do the same for -?. Is there a way to tell it to do so?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Kağan Kayal
  • 2,303
  • 1
  • 19
  • 30

3 Answers3

2

I had opened an issue at the clap repository. The author / main contributor has answered there. Here is a copy of the code, which answers the question:

extern crate clap;

use std::env;
use std::process;

use clap::{App, Arg};

fn main() {
    // We build the App instance and save it, so we can
    // use it later if needed
    let mut app = App::new("prog").arg(
        Arg::with_name("help")
            .short("?")
            .help("Also prints the help message"),
    );

    // We call this method which will do all the
    //parsing, but not consume our App instance
    let res = app.get_matches_from_safe_borrow(env::args_os());

    // This calls all the normal clap error messages
    // if one should exist
    let matches = res.unwrap_or_else(|e| e.exit());

    // Now we check for ?
    if matches.is_present("help") {
        let _ = app.print_help();
        println!(""); // adds a newline
        process::exit(0);
    }

    // Now we can use matches like normal...
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Kağan Kayal
  • 2,303
  • 1
  • 19
  • 30
0

As of Clap 2.29.0, there's no built-in way to add multiple short names for the same option.

App::help_short lets you override the default -h option for help, but although the function accepts a string, it only cares about the first character (after stripping leading dashes). Arg::short does the same.

You could define the -? option as a separate option, and handle it yourself by calling App::print_help. This will have the effect of displaying -? separately in the help text, although you can hide the option.

Francis Gagné
  • 60,274
  • 7
  • 180
  • 155
  • Thanks for helping, but neither workarounds worked for me. The first one sounds like -h would not work anymore, which is not my intention. The second one doesn't work at all. I defined .arg(Arg::with_name("QUESTION_MARK").short("?") but later when I check if it the user entered a ? by calling value_of("QUESTION_MARK"), it returns None... And even if that would work, after calling .get_matches(), it seems it consumes App and returns clap::ArgMatches, which doesn't have a sort of print_help function, but only usage(), which is not what I was looking for. – Kağan Kayal Dec 11 '17 at 07:33
  • 2
    @KağanKayal In that case, you might want to fill a new [issue](https://github.com/kbknapp/clap-rs/issues) on Clap's repository. Basically, what you're asking for is the ability to define *short* aliases (the `alias` functions on `Arg` only define aliases for the `--long` option syntax). – Francis Gagné Dec 12 '17 at 01:38
-1

Tried to make this a comment, but it won't fit.

Another issue you're going to run into with this, at least on Unix-like systems, is that most shells assign a special meaning to '?'. I have a Rust program that just prints out the arguments it finds on the command line.

> $ cargo run one two three
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/cmdl one two three`
["target/debug/cmdl", "one", "two", "three"]
args len: 4
arg: target/debug/cmdl
arg: one
arg: two
arg: three

When I pass it -?:

> $ cargo run -?
zsh: no matches found: -?

I can pass in -? if I quote it and put -- in front of it:

> $ cargo run -- "-?"
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/cmdl '-?'`
["target/debug/cmdl", "-?"]
args len: 2
arg: target/debug/cmdl
arg: -?

It seems like that's a bit much to expect of someone looking for help but maybe it's friendlier on the OP's platform. I'm working on Mac OS X.

Update:

Most of the Bourne-based shells on Unix-like systems interpret ? as a globbing wildcard for matching a single character in file names. I don't know about fish but I've checked out /bin/sh, /bin/ksh, /bin/bash, and /bin/zsh below.

If you use -? as a command line option with these shells and there's a filename in the working directory that consists of a hyphen followed by a single character, your program will see the file name rather than the "-?" because the shell will do the substitution before the command line ever gets to your program.

Some of the shells (notably zsh) will stumble over -? before even checking files, as noted in my original message.

As shown below, if -? is enclosed in quotes, the shell won't mess with it but that's not something I'd expect most folks to know. I wouldn't even trust myself to remember that when I'm trying to find the help page for a program I'm not familiar with.

$ /bin/sh
$ ls
-a      -bb     -ccc    a       bb      ccc
$ echo -?
-a
$ echo ?
a
$ echo ??
-a bb
$ echo "-?"
-?

$ /bin/ksh
$ ls
-a      -bb     -ccc    a       bb      ccc
$ echo ?
a
$ echo -?
-a
$ echo ??
-a bb
$ echo "-?"
-?

$ /bin/bash
$ ls
-a      -bb     -ccc    a       bb      ccc
$ echo ?
a
$ echo -?
-a
$ echo ??
-a bb
$ echo "-?"
-?

$ /bin/zsh
$ ls
-a   -bb  -ccc a    bb   ccc
$ echo ?
a
$ echo -?
-a
$ echo ??
-a bb
$ echo "-?"
-?
Tom Barron
  • 1,554
  • 18
  • 23
  • 1 — Don't run it through `cargo`, which does its own command line handling. 2 — *most shells assign a special meaning* — running on bash: `./target/debug/echo -?` -> `["./target/debug/echo", "-?"]`. One shell does, one doesn't. You'll need to cite some statistics to claim "most". – Shepmaster Jan 16 '18 at 03:22
  • @Shepmaster: Thanks for calling me on my vague claim. I thought I remembered something about '?' being handled weirdly by the shells. I tried to use -? for help, like the OP, many years ago before eventually figuring out what I point out in my update and giving it up. The point is, -? is not a good option to use on Unix-like systems with shells in the Bourne family because of the potential inconsistent behavior due to file name matching. – Tom Barron Jan 16 '18 at 14:38
  • Using your set of shells and `echo -?` prints `-?` in each case on my machine, so your point is that if you have a file starting with a dash, then using `-?` can cause problems? – Shepmaster Jan 16 '18 at 15:07
  • Yes. If you have a file that matches -? (i.e., starts with dash and contains one other character), -? will return the file name, not '-?'. The program can't control the environment it runs in and -? behaves differently (at least in the set of shells we're talking about) depending on the contents of the current working directory. So using it as a command line option opens the door to obscure and weird bugs that are hard to figure out. – Tom Barron Jan 16 '18 at 18:10
  • Thanks for the interesting hints. I have no experiance with zsh. I use a mixture of bash, os-x and the windows 7 terminal. My anti-example is tar. This veteran understands -? and it doesn't understand -h and I grew up with that;-) My second example is python. It supports both. That shows to me that -? or -h is a preference of the developer. I would like to support both so that. – Kağan Kayal Jan 19 '18 at 12:41
  • Actually, to my understanding, the questionmark alone has a special meaning. For example if I have a file called `abc` and then do `ls a?c` I get `abc` as expected. But this doesn't mean that there is a special meaning for `-?` When I type `ls -?` it returns `invalid option`. In other words, bash passes `-?` very well to ls. It is just ls, which doesn't understand the -? option. – Kağan Kayal Jan 19 '18 at 13:11
  • @KağanKayal: In bash on Mac OS X, if I do "touch -- -a; ls -?" I get the same output as "ls -a". (If you want to remove the '-a' file, you can do 'rm -- -a'.) – Tom Barron Jan 20 '18 at 17:25