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 parse_args_or_exit
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::parse_args_or_exit(argp::DEFAULT);
./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::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
:
/// 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
The formatting of the help message can be customized using the HelpStyle
passed as an argument to parse_args_or_exit
:
let args: Args = argp::parse_args_or_exit(&HelpStyle {
blank_lines_spacing: 1,
description_indent: 8,
..HelpStyle::default()
});
Note that the HelpStyle
struct may be extended with more fields in the
future, so always initialise it using HelpStyle::default()
as shown
above.
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,
}
§Markdown
Any descriptions provided as a doc comment (or doc
attribute) are
interpreted as Markdown and converted to plain text (at build time) as shown
in the table below. The output format may change slightly in the future.
Markdown | Output |
---|---|
# Heading , ## Heading , … | Heading |
*italic* , _italic_ | italic |
**bold** , __bold__ | *bold* |
`monospace` | `monospace` |
[link title](https://example.org) | https://example.org |
* unordered list | * unordered list |
1. ordered list | 1. ordered list |
``` | code |
> block | block |
<p>html</p> | <p>html</p> |
Line<br>break | Line |
If you want to remove an implicit blank line between two blocks, for example
a paragraph and a list, you can do this with <br>
:
List of items:<br>
* one
* two
This can also be used to write several empty lines in a row, which would otherwise be stripped.
Re-exports§
pub use crate::error::MissingRequirements;
pub use crate::help::CommandInfo;
pub use crate::help::HelpStyle;
Modules§
- help
- 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.
- parser
- Items in this module are all used by the generated code, and should not be considered part of this library’s public API surface.
- term_
size - This module provides a lightweight, zero-dependencies implementation of a
function to get the terminal width on Unix systems. It’s replaced with a
no-op implementation on non-unix systems or when the
term_size
feature is disabled.
Enums§
- Early
Exit - Information to display to the user about why a
FromArgs
construction exited early. - Error
- The error type for the argp parser.
Constants§
- DEFAULT
- A convenient shortcut for
HelpStyle::default
.
Traits§
- Command
Help - A
FromArgs
implementation with attachedHelpInfo
struct. - Dynamic
SubCommand - Trait implemented by values returned from a dynamic subcommand handler.
- From
ArgValue - Types which can be constructed from a single command-line value.
- From
Args - Types which can be constructed from a set of command-line arguments.
- SubCommand
- A
FromArgs
implementation that represents a single subcommand. - SubCommands
- A
FromArgs
implementation that can parse into one or more subcommands. - TopLevel
Command - A top-level
FromArgs
implementation that is not a subcommand.
Functions§
- cargo_
parse_ args_ or_ exit - Create a
FromArgs
type from the current process’senv::args_os()
. - from_
env Deprecated - Deprecated alias for
parse_args_or_exit
. - parse_
args_ or_ exit - Create a
FromArgs
type from the current process’senv::args_os()
with the givenHelpStyle
. For the default help styleargp::DEFAULT
can be used.
Derive Macros§
- From
Args - Entrypoint for
#[derive(FromArgs)]
.