TeXitoi / structopt

Parse command line arguments by defining a struct.
Other
2.7k stars 149 forks source link

Long options like "--foo-option value" don't work #519

Closed westandskif closed 2 years ago

westandskif commented 2 years ago

Hello! Thank you for the great library!

I got a question about mine, which uses structopt. It looks like it doesn't support GNU accepted option syntax.

Code: permalink Code sample:

#[derive(Debug, PartialEq, Clone)]
pub enum Protocol {
    Http,
    Https,
}
impl FromStr for Protocol {
    type Err = &'static str;
    fn from_str(protocol: &str) -> Result<Self, Self::Err> {
        match protocol {
            "http" => Ok(Protocol::Http),
            "https" => Ok(Protocol::Https),
            _ => Err("could not parse protocol"),
        }
    }
}

#[derive(Debug, StructOpt)]
pub enum Target {
    /// accepts lines of urls OR lines with tab-separated urls and countries
    Stdin(StdinTarget),
    /// fetch & test archlinux mirrors
    Arch(ArchTarget),
    /// fetch & test manjaro mirrors
    Manjaro(ManjaroTarget),
    /// fetch & test rebornos mirrors
    #[structopt(name = "rebornos")]
    RebornOS(RebornOSTarget),
    /// fetch & test artix mirrors
    Artix(ArtixTarget),
}

#[derive(Debug, StructOpt)]
#[structopt(name = "rate-mirrors config")]
/// Usually default options should work
pub struct Config {
    /// Per-mirror speed test timeout in milliseconds
    #[structopt(subcommand)]
    pub target: Target,

    /// Test only specified protocols (can be passed multiple times)
    #[structopt(long = "protocol")]
    pub protocols: Vec<Protocol>,
    //...
}

rate-mirrors --protocol http arch just returns --help, while docs say:

/// This option can be specified with something like `--foo-option
    /// value` or `--foo-option=value`
    #[structopt(long)]
    foo_option: String,

If you run it this way: rate-mirrors --protocol=http arch, it works just fine. Am I doing something wrong? Can you please help?

TeXitoi commented 2 years ago

Look at the "pro tip" section in https://docs.rs/clap/2.33.3/clap/struct.Arg.html#method.multiple

use std::str::FromStr;
use structopt::StructOpt;

#[derive(Debug, PartialEq, Clone)]
pub enum Protocol {
    Http,
    Https,
}
impl FromStr for Protocol {
    type Err = &'static str;
    fn from_str(protocol: &str) -> Result<Self, Self::Err> {
        match protocol {
            "http" => Ok(Protocol::Http),
            "https" => Ok(Protocol::Https),
            _ => Err("could not parse protocol"),
        }
    }
}

#[derive(Debug, StructOpt)]
pub enum Target {
    /// accepts lines of urls OR lines with tab-separated urls and countries
    Stdin,
    /// fetch & test archlinux mirrors
    Arch,
    /// fetch & test manjaro mirrors
    Manjaro,
    /// fetch & test rebornos mirrors
    #[structopt(name = "rebornos")]
    RebornOS,
    /// fetch & test artix mirrors
    Artix,
}

#[derive(Debug, StructOpt)]
#[structopt(name = "rate-mirrors config")]
/// Usually default options should work
pub struct Config {
    /// Per-mirror speed test timeout in milliseconds
    #[structopt(subcommand)]
    pub target: Target,

    /// Test only specified protocols (can be passed multiple times)
    #[structopt(long = "protocol", number_of_values = 1)]
    pub protocols: Vec<Protocol>,
    //...
}

fn main() {
    println!("{:?}", Config::from_args());
}

Which works as you expect. Note that clap v3 does a better job than clap v2 on this.

westandskif commented 2 years ago

Thank you very much!