clap-rs / clap

A full featured, fast Command Line Argument Parser for Rust
docs.rs/clap
Apache License 2.0
13.94k stars 1.03k forks source link

Allow visible aliases for PossibleValue #4416

Open dbrgn opened 1 year ago

dbrgn commented 1 year ago

Please complete the following tasks

Clap Version

4.0.18

Describe your use case

Tealdeer has a parameter -p, --platform <PLATFORM> to select the platform. For historic reasons, this list must include "osx", but should also include the alias "macos". This alias should not be hidden, but should be visible.

With Clap 3, this was implemented using FromStr:

#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[allow(dead_code)]
pub enum PlatformType {
    Linux,
    OsX,
    SunOs,
    Windows,
    Android,
}

impl str::FromStr for PlatformType {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "linux" => Ok(Self::Linux),
            "osx" | "macos" => Ok(Self::OsX),
            "sunos" => Ok(Self::SunOs),
            "windows" => Ok(Self::Windows),
            "android" => Ok(Self::Android),
            other => Err(anyhow!(
                "Unknown OS: {}. Possible values: linux, macos, osx, sunos, windows, android",
                other
            )),
        }
    }
}
    /// Override the operating system
    #[clap(
        short = 'p',
        long = "platform",
        possible_values = ["linux", "macos", "windows", "sunos", "osx", "android"],
    )]
    pub platform: Option<PlatformType>,

With Clap 4, I tried to migrate to EnumValueParser:

impl clap::ValueEnum for PlatformType {
    fn value_variants<'a>() -> &'a [Self] {
        &[Self::Linux, Self::OsX, Self::Windows, Self::SunOs, Self::Android]
    }

    fn to_possible_value<'a>(&self) -> Option<clap::builder::PossibleValue> {
        match self {
            Self::Linux => Some(clap::builder::PossibleValue::new("linux")),
            Self::OsX => Some(clap::builder::PossibleValue::new("osx").alias("macos")),
            Self::Windows => Some(clap::builder::PossibleValue::new("windows")),
            Self::SunOs => Some(clap::builder::PossibleValue::new("sunos")),
            Self::Android => Some(clap::builder::PossibleValue::new("android")),
        }
    }
}

This works, but the alias is not visible in help output or error messages.

Describe the solution you'd like

Since Command has both .alias(...) and .visible_alias(...), would this be possible for PossibleValue as well?

Alternatives, if applicable

No response

Additional Context

No response

dbrgn commented 1 year ago

Note: This comment by @epage might be related / an alternative API to the suggested .visible_alias method:

Kind of like how clap switched from possible values being a &str to PossibleValue, I wonder if we should have an Alias<T> which has a hide method on it.

epage commented 1 year ago

I broke that comment out into #4421. I think I'd prefer not going that route for PossibleValue until we do it for everything as it'd be weird to have such a divergent API.

epage commented 2 months ago

The big question for me for this is how visible aliases for possible values should be rendered. In the short help, it feels weird to redundantly list options that map back to the same thing and would get weird nesting expressions into each other. With long help, we could have an [aliases: ...] after the item, I guess.

AmmarAbouZor commented 6 days ago

I thought of two solutions for the short help:

We can make printing aliases in short description optional be adding a boolean or a flag for the function. Something like:

// Boolean option 
pub fn visible_alias(mut self, name: impl IntoResettable<Str>, short-help: bool) -> ...

// Flag option 
pub fn visible_alias(mut self, name: impl IntoResettable<Str>, flags: AliasFlags) -> ...
bitflags! {
    pub struct AliasFlags: u32 {
        const ShortHelp = 0b00000001;
       ...
    }
}
epage commented 6 days ago

We can make printing aliases in short description optional be adding a boolean or a flag for the function.

We're trying to keep minimum the configuration we provide, focusing on a consistent, quality out of box experience.