Expand description
Derive-based argument parsing optimized for code size and flexibility.
The public API of this library consists primarily of the FromArgs
derive and the from_env function, which can be used to produce
a top-level FromArgs type from the current program’s command-line
arguments.
Basic Example
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)]
height: usize,
/// An optional nickname for the pilot.
#[argp(option)]
pilot_nickname: Option<String>,
}
let up: GoUp = argp::from_env();./some_bin --help will then output the following:
Usage: cmdname [-j] --height <height> [--pilot-nickname <pilot-nickname>]
Reach new heights.
Options:
-j, --jump Whether or not to jump.
--height How high to go.
--pilot-nickname An optional nickname for the pilot.
--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::from_env();
}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:
/// 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:
/// 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.
If your final positional argument has the greedy option on it, it will consume
any arguments after it as if a -- were placed before the first argument to
match the greedy positional:
/// A command with a greedy positional argument at the end.
#[derive(FromArgs, PartialEq, Debug)]
struct WithGreedyPositional {
/// Some stuff.
#[argp(option)]
stuff: Option<String>,
#[argp(positional, greedy)]
all_the_rest: Vec<String>,
}Now if you pass --stuff Something after a positional argument, it will
be consumed by all_the_rest instead of setting the stuff field.
Note that all_the_rest won’t be listed as a positional argument in the
long text part of help output (and it will be listed at the end of the usage
line as [all_the_rest...]), and it’s up to the caller to append any
extra help output for the meaning of the captured arguments. This is to
enable situations where some amount of argument processing needs to happen
before the rest of the arguments can be interpreted, and shouldn’t be used
for regular use as it might be confusing.
Subcommands
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:
/// Top-level command.
#[derive(FromArgs, PartialEq, Debug)]
struct TopLevel {
/// Be verbose.
#[argp(switch, short = 'v', global)]
verbose: bool,
/// Run locally.
#[argp(switch)]
quiet: 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,
}Normally the options specified in TopLevel must be placed before the
subcommand name, e.g. ./some_bin --quiet one --x 42 will work, but
./some_bin one --quiet --x 42 won’t. To allow an option from a higher
level to be used at a lower level (in subcommands), you can specify the
global attribute to the option (--verbose in the example above).
Global options only propagate down, not up (to parent commands), but their values are propagated back up to the parent once a user has used them. In effect, this means that you should define all global arguments at the top level, but it doesn’t matter where the user uses the global argument.
You can also discover subcommands dynamically at runtime. To do this,
declare subcommands as usual and add a variant to the enum with the
dynamic attribute. Instead of deriving FromArgs, the value inside the
dynamic variant should implement DynamicSubCommand.
/// Top-level command.
#[derive(FromArgs, PartialEq, Debug)]
struct TopLevel {
#[argp(subcommand)]
nested: MySubCommandEnum,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argp(subcommand)]
enum MySubCommandEnum {
Normal(NormalSubCommand),
#[argp(dynamic)]
Dynamic(Dynamic),
}
/// Normal subcommand.
#[derive(FromArgs, PartialEq, Debug)]
#[argp(subcommand, name = "normal")]
struct NormalSubCommand {
/// How many x.
#[argp(option)]
x: usize,
}
/// Dynamic subcommand.
#[derive(PartialEq, Debug)]
struct Dynamic {
name: String
}
impl DynamicSubCommand for Dynamic {
fn commands() -> &'static [&'static CommandInfo] {
static RET: OnceCell<Vec<&'static CommandInfo>> = OnceCell::new();
RET.get_or_init(|| {
let mut commands = Vec::new();
// argp needs the `CommandInfo` structs we generate to be valid
// for the static lifetime. We can allocate the structures on
// the heap with `Box::new` and use `Box::leak` to get a static
// reference to them. We could also just use a constant
// reference, but only because this is a synthetic example; the
// point of using dynamic commands is to have commands you
// don't know about until runtime!
commands.push(&*Box::leak(Box::new(CommandInfo {
name: "dynamic_command",
description: "A dynamic command",
})));
commands
})
}
fn try_from_args(command_name: &[&str], args: &[&OsStr]) -> Option<Result<Self, EarlyExit>> {
for command in Self::commands() {
if command_name.last() == Some(&command.name) {
if !args.is_empty() {
return Some(Err(Error::other("Our example dynamic command never takes arguments!").into()));
}
return Some(Ok(Dynamic { name: command.name.to_string() }))
}
}
None
}
}Help message
Programs that are run from an environment such as cargo may find it
useful to have positional arguments present in the structure but
omitted from the usage output. This can be accomplished by adding
the hidden_help attribute to that argument:
/// Cargo arguments
#[derive(FromArgs)]
struct CargoArgs {
// Cargo puts the command name invoked into the first argument,
// so we don't want this argument to show up in the usage text.
#[argp(positional, hidden_help)]
command: String,
/// An option used for internal debugging.
#[argp(option, hidden_help)]
internal_debugging: String,
#[argp(positional)]
real_first_arg: String,
}Re-exports
pub use crate::help::CommandInfo;
Modules
- Struct in this module are all used by the generated code. They can be used outside the library, but without any guarantees - there may be breaking changes between minor versions.
- Items in this module are all used by the generated code, and should not be considered part of this library’s public API surface.
Enums
- Information to display to the user about why a
FromArgsconstruction exited early. - The error type for the argp parser.
Traits
- A
FromArgsimplementation with attached Help struct. - Trait implemented by values returned from a dynamic subcommand handler.
- Types which can be constructed from a single command-line value.
- Types which can be constructed from a set of command-line arguments.
- A
FromArgsimplementation that represents a single subcommand. - A
FromArgsimplementation that can parse into one or more subcommands. - A top-level
FromArgsimplementation that is not a subcommand.
Functions
- Create a
FromArgstype from the current process’senv::args. - Create a
FromArgstype from the current process’senv::args.
Derive Macros
- Entrypoint for
#[derive(FromArgs)].