-
Zero runtime dependencies.
-
Small size overhead – ~40 kiB [1], that’s 10x less than clap or clap_derive! See argparse-rosetta-rs for more details.
-
Derive-based API – you define structs and enums for the parsed values, use attributes to specify how they should be parsed and a procedural derive macro will generate the parser at compile-time.
-
Context-sensitive parsing.
-
Support for subcommands.
-
Help message generator with Markdown support and dynamic wrapping based on terminal width.
Argp originally started as a fork of argh to make it less opinionated, more UNIXy and flexible.
Notable changes from argh:
-
Support for global options (i.e. options defined at the top level can be used in subcommands).
-
Support for combined short options (e.g.
-abis parsed as-a -b,-an 5as-a -n 5). -
Support for non-UTF8 arguments (OsStr).
-
The
from_str_fnattribute can also contain a function path, not just a single identifier, and can return anyErrtype which implementsToString. -
No pedantic requirement for descriptions to start with a lower-case letter.
-
Help message is dynamically wrapped based on terminal width (on unix systems).
-
The indentation of descriptions in the help message is dynamically calculated based on the widths of all elements.
-
The
arg_nameattribute can also be used even on positional arguments to customise how the argument is displayed in the help message. -
Errors are represented using an enum instead of a String and the information used to generate a help message is stored in a partially structured form in a struct; this opens the door to customisation of messages.
-
Specialised
example,note, anderror_codeattributes are replaced by a singlefooterattribute – you can use it for whatever you like. -
Positional arguments in the Usage string are displayed after options and switches and
<arg_name>is displayed in descriptions of options. -
Trailing options are allowed after the
-h, --helpswitch, but are not allowed after thehelpsubcommand only. -
The
from_envfunction has been renamed toparse_args_or_exit,cargo_from_envtocargo_parse_args_or_exit. -
redact_arg_valueshas been removed (if you happen to need it, let me know in Issues).
use argp::FromArgs;
/// Reach new heights.
#[derive(FromArgs)]
struct GoUp {
/// Whether or not to jump.
#[argp(switch, short = 'j')]
jump: bool,
/// How high to go.
#[argp(option, arg_name = "meters")]
height: usize,
/// An optional nickname for the pilot.
#[argp(option, arg_name = "name")]
pilot_nickname: Option<String>,
}
fn main() {
let up: GoUp = argp::parse_args_or_exit(argp::DEFAULT);
}./some_bin --help will then output the following:
Usage: cmdname [-j] --height <meters> [--pilot-nickname <name>]
Reach new heights.
Options:
-j, --jump Whether or not to jump.
--height <meters> How high to go.
--pilot-nickname <name> An optional nickname for the pilot.
-h, --help Show this help message and exit.
The resulting program can then be used in any of these ways:
-
./some_bin --height 5 -
./some_bin -j --height 5 -
./some_bin --jump --height 5 --pilot-nickname Wes
Switches, like jump, are optional and will be set to true if provided.
Options, like height and pilot_nickname, can be either required, optional, or repeating, depending on whether they are contained in an Option or a Vec.
Default values can be provided using the #[argp(default = "<your_code_here>")] attribute, and in this case an option is treated as optional.
use argp::FromArgs;
fn default_height() -> usize {
5
}
/// Reach new heights.
#[derive(FromArgs)]
struct GoUp {
/// An optional nickname for the pilot.
#[argp(option)]
pilot_nickname: Option<String>,
/// An optional height.
#[argp(option, default = "default_height()")]
height: usize,
/// An optional direction which is "up" by default.
#[argp(option, default = "String::from(\"only up\")")]
direction: String,
}
fn main() {
let up: GoUp = argp::parse_args_or_exit(argp::DEFAULT);
}Custom option types can be deserialized so long as they implement the FromArgValue trait (already implemented for most types in std for which the FromStr trait is implemented).
If more customized parsing is required, you can supply a custom fn(&str) → Result<T, E> using the from_str_fn attribute, or fn(&OsStr) → Result<T, E> using the from_os_str_fn attribute, where E implements ToString:
use argp::FromArgs;
use std::ffi::OsStr;
use std::path::PathBuf;
/// Goofy thing.
#[derive(FromArgs)]
struct FineStruct {
/// Always five.
#[argp(option, from_str_fn(always_five))]
five: usize,
/// File path.
#[argp(option, from_os_str_fn(convert_path))]
path: PathBuf,
}
fn always_five(_value: &str) -> Result<usize, String> {
Ok(5)
}
fn convert_path(value: &OsStr) -> Result<PathBuf, String> {
Ok(PathBuf::from("/tmp").join(value))
}Positional arguments can be declared using #[argp(positional)].
These arguments will be parsed in order of their declaration in the structure:
use argp::FromArgs;
/// A command with positional arguments.
#[derive(FromArgs, PartialEq, Debug)]
struct WithPositional {
#[argp(positional)]
first: String,
}The last positional argument may include a default, or be wrapped in Option or Vec to indicate an optional or repeating positional argument.
Subcommands are also supported.
To use a subcommand, declare a separate FromArgs type for each subcommand as well as an enum that cases over each command:
use argp::FromArgs;
/// Top-level command.
#[derive(FromArgs, PartialEq, Debug)]
struct TopLevel {
/// Be verbose.
#[argp(switch, short = 'v', global)]
verbose: bool,
#[argp(subcommand)]
nested: MySubCommandEnum,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argp(subcommand)]
enum MySubCommandEnum {
One(SubCommandOne),
Two(SubCommandTwo),
}
/// First subcommand.
#[derive(FromArgs, PartialEq, Debug)]
#[argp(subcommand, name = "one")]
struct SubCommandOne {
/// How many x.
#[argp(option)]
x: usize,
}
/// Second subcommand.
#[derive(FromArgs, PartialEq, Debug)]
#[argp(subcommand, name = "two")]
struct SubCommandTwo {
/// Whether to fooey.
#[argp(switch)]
fooey: bool,
}For more information, refer to the argp documentation.
The argp::FromArgs derive macro can be debugged with the cargo-expand crate.
See argp/examples/simple_example.rs for the example struct we wish to expand.
First, install cargo-expand by running cargo install cargo-expand.
Note this requires the nightly build of Rust.
Once installed, run cargo expand with in the argp package and you can see the expanded code.
This project is licensed under BSD-3-Clause license. For the full text of the license, see the LICENSE file.
strip = true and panic = "abort". The exact size depends on several factors, including the number of options and subcommands.