What does `ArgAction` use for? (clap crate)

ArgAction in clap - Rust

I found some projects that made an update like:

#[derive(Debug, Parser)]
pub struct S {
-	#[clap(long)]
+	#[clap(long, action)]
	pub output: Option<PathBuf>,
}

But it looks like nothing different (for the execution result).

What does the action used for?

I'm also using clap on my project. So, I'd like to figure out how it works.

The documentation doesn't really talk about what the attribute does if no value is specified, so I ran some simple code through cargo-expand to see what changed if I added the attribute

Playground

You can expand the macros on the playground under Tools > Expand macros. Just add , action and re-run it if you want to see the before and after.

Looking at the diff I think the most relevant changes are in the impl clap::Args for App. The calls to required and value_parser are where the changes are in both methods. I'm not familiar enough with clap's internals to say what the precise semantic difference is, but it looks to me like adding action is opting in to newer behavior that may be breaking for some old code. Notably the StoreValue variant of ArgAction is documented as deprecated, and that's what the non-action expansion uses.

Before
#[deny(clippy::correctness)]
impl clap::Args for App {
    fn augment_args<'b>(__clap_app: clap::Command<'b>) -> clap::Command<'b> {
        {
            let __clap_app = __clap_app;
            let __clap_app = __clap_app.arg({
                #[allow(deprecated)]
                let arg = clap::Arg::new("value")
                    .takes_value(true)
                    .value_name("VALUE")
                    .required(true && clap::ArgAction::StoreValue.takes_values())
                    .validator(|s| ::std::str::FromStr::from_str(s).map(|_: String| ()))
                    .value_parser(clap::builder::ValueParser::string())
                    .action(clap::ArgAction::StoreValue);
                let arg = arg.long("value");
                arg
            });
            __clap_app
        }
    }
    fn augment_args_for_update<'b>(__clap_app: clap::Command<'b>) -> clap::Command<'b> {
        {
            let __clap_app = __clap_app;
            let __clap_app = __clap_app.arg({
                #[allow(deprecated)]
                let arg = clap::Arg::new("value")
                    .takes_value(true)
                    .value_name("VALUE")
                    .required(false && clap::ArgAction::StoreValue.takes_values())
                    .validator(|s| ::std::str::FromStr::from_str(s).map(|_: String| ()))
                    .value_parser(clap::builder::ValueParser::string())
                    .action(clap::ArgAction::StoreValue);
                let arg = arg.long("value");
                arg
            });
            __clap_app
        }
    }
}
After
#[deny(clippy::correctness)]
impl clap::Args for App {
    fn augment_args<'b>(__clap_app: clap::Command<'b>) -> clap::Command<'b> {
        {
            let __clap_app = __clap_app;
            let __clap_app = __clap_app.arg({
                #[allow(deprecated)]
                let arg = clap::Arg::new("value")
                    .takes_value(true)
                    .value_name("VALUE")
                    .required(true && clap::ArgAction::Set.takes_values())
                    .value_parser({
                        use ::clap::builder::via_prelude::*;
                        let auto = ::clap::builder::_AutoValueParser::<String>::new();
                        (&&&auto).value_parser()
                    })
                    .action(clap::ArgAction::Set);
                let arg = arg.long("value");
                arg
            });
            __clap_app
        }
    }
    fn augment_args_for_update<'b>(__clap_app: clap::Command<'b>) -> clap::Command<'b> {
        {
            let __clap_app = __clap_app;
            let __clap_app = __clap_app.arg({
                #[allow(deprecated)]
                let arg = clap::Arg::new("value")
                    .takes_value(true)
                    .value_name("VALUE")
                    .required(false && clap::ArgAction::Set.takes_values())
                    .value_parser({
                        use ::clap::builder::via_prelude::*;
                        let auto = ::clap::builder::_AutoValueParser::<String>::new();
                        (&&&auto).value_parser()
                    })
                    .action(clap::ArgAction::Set);
                let arg = arg.long("value");
                arg
            });
            __clap_app
        }
    }
}
1 Like

It looks like the playground is incorrect.

Whoops, fixed!

You can ask the Clap maintainer(s) directly here:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.