clap v4.2.0 is now out with styling of help descriptions! See the changelog for more details.

What Changed in v4.2.0

User Styling of Help Descriptions

By default, clap will style the output of --help but there wasn't a way for users to do the same, whether to emphasize something or for a custom section, like "Examples".

As previously discussed, we settled on using ANSI escape codes for this so you can use the library of your choice. For example, with the color-print crate, you can now do:

// `cstr!` converts tags to ANSI codes
let after_help: &'static str = color_print::cstr!(
r#"<bold><underline>Examples</underline></bold>

  <dim>$</dim> <bold>mybin --input file.toml</bold>
"#);

let cmd = clap::Command::new("mybin")
    .after_help(after_help)  // The `&str` gets converted into a `StyledStr`
    // ...

To know if ANSI escape codes will be handled properly, look for builder methods that accept StyledStr.

Further Error Tweaks

In clap v4.1, we changed error messages. This release further iterates on them based on feedback we received.

clap v4.0:

error: Found argument '--optio' which wasn't expected, or isn't valid in this context

  Did you mean '--option'?

Usage: clap-test --option <opt>... [positional] [positional2] [positional3]...

For more information try '--help'

clap v4.1:

error: unexpected argument '--optio'

  note: argument '--option' exists

Usage: clap-test --option <opt>... [positional] [positional2] [positional3]...

For more information, try '--help'.

clap v4.2:

error: unexpected argument '--optio'

  tip: a similar argument exists: '--option'

Usage: clap-test --option <opt>... [positional] [positional2] [positional3]...

For more information, try '--help'.

I'm sure there is room for improvement. We welcome further discussion on this on #4638.

Removed unstable-replace

We've had Command::replace behind the unstable-replace feature flag since 3.0.0 but there has been little interest expressed in it and the design doesn't align well with the rest of clap, so we've removed it.

As alternatives

If you have any feedback on this decision, we welcome it at #2836.

What Changed in v4.1.x

While minor releases get a lot more attention, there is still a lot of interesting work done in patch releases that deserve being highlighted.

Build Times

We've seen several different build-time improvements including

For very unscientific numbers:

v4.1.0v4.2.0
clap $ cargo build4.250s3.923s
clap $ cargo build -F derive6.419s4.602s

For more numbers, see argparse-rosetta-rs.

Deriving ArgGroup

In clap v4.0.0, we automatically generate an ArgGroup for each derived Args but there was no way to customize the ArgGroup, requiring people to still manually create them in some cases:

#[derive(Parser)]
#[command(group(
            ArgGroup::new("vers")
                .required(true)
                .args(["set_ver", "major", "minor", "patch"]),
        ))]
struct Cli {
    /// set version manually
    #[arg(long, value_name = "VER")]
    set_ver: Option<String>,

    /// auto inc major
    #[arg(long)]
    major: bool,

    /// auto inc minor
    #[arg(long)]
    minor: bool,

    /// auto inc patch
    #[arg(long)]
    patch: bool,

    /// some regular input
    #[arg(group = "input")]
    input_file: Option<String>,
}

We now support #[group] raw attributes, allowing any ArgGroup builder method to be used:

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
    #[command(flatten)]
    vers: Vers,

    /// some regular input
    #[arg(group = "input")]
    input_file: Option<String>,
}

#[derive(Args)]
#[group(required = true, multiple = false)]
struct Vers {
    /// set version manually
    #[arg(long, value_name = "VER")]
    set_ver: Option<String>,

    /// auto inc major
    #[arg(long)]
    major: bool,

    /// auto inc minor
    #[arg(long)]
    minor: bool,

    /// auto inc patch
    #[arg(long)]
    patch: bool,
}

Granted, the above would be better expressed as an enum which we are tracking in #2621.

Discuss on reddit mastadon