Right now, they are incompatible, but I'm not sure that's right. For example, I wanted something like my-app --db-path [DB], where there's a default database path if not set.
Is there another way to achieve that?
Can you give example of command line and corresponding struct, because I don't understand what you expect.
#[derive(Clone, Debug, StructOpt)]
pub struct Options {
#[structopt(long = "db", help = "Database path", default_value = "my-app.db")]
pub db: Option<String>,
}
Example usage:
$ my-app # db is None
$ my-app --db # db is Some("my-app.db")
$ my-app --db foo.db # db is Some("foo.db")
In clap, an argument takes value or not: https://docs.rs/clap/2.32.0/clap/struct.Arg.html#method.takes_value
Thus, I don't think that's possible to have an argument that can optionally take value, That's why default_value is prohibited in Option, as it will always have a value, and thus will always be Some(a).
I suppose default_value and occurrences_of could be used in this case. The latter will return zero if the argument wasn't passed at all.
I can't find any way to do it using clap. If you can show me a working program doing what you want with clap, I'll try to allow using the feature in structopt.
extern crate clap;
use clap::{App, Arg, ArgMatches};
fn get_optional_value<'a, 'b>(m: &'a ArgMatches, name: &'b str) -> Option<&'a str> {
if m.occurrences_of(name) == 0 {
None
} else {
m.value_of(name)
}
}
fn main() {
let app = App::new("my-app").arg(Arg::with_name("db").long("db").default_value("my-app.db"));
let m = app.clone().get_matches_from(vec!["my-app", "--db"]);
assert!(get_optional_value(&m, "db") == Some("my-app.db"));
let m = app
.clone()
.get_matches_from(vec!["my-app", "--db", "foo.db"]);
assert!(get_optional_value(&m, "db") == Some("foo.db"));
let m = app.clone().get_matches_from(vec!["my-app"]);
assert!(get_optional_value(&m, "db") == None);
}
I'll try to see how I can do it cleanly in structopt. Thanks for the example.
Another way of achieving optional value of the long argument in clap is to use Arg::min_values(0) as described here: https://github.com/clap-rs/clap/issues/892
Then we can distinguish between say --help and --help topic by checking matches.is_present("help") and pattern matching matches.value_of("help") against Some (as demonstrated in the code from the issue linked above).
I am now trying to describe this behaviour with structopt, but can't find a way :( It sets the field of the datatype to None in both cases when it's omitted and when its value is empty, so I can't tell the difference.
@sphynx That's a quite different topic. You'd want support for Option<Option<T>> or Option<Vec<T>>. If that's what you're looking for, then you can create an issue about this.
As a workaround, you can do the parsing "by hand":
let app = Opt::clap();
let matches = app.get_matches();
// do something special to retrive the needed information
let opt = Opt::from_matches(&matches);
@TeXitoi Thanks for your reply! As suggested, I've created a new issue: #188
I think I'll either have to use the workaround or restructure the arguments differently for now.
Most helpful comment