Crate argh

source · []
Expand description

Derive-based argument parsing optimized for code size and conformance to the Fuchsia commandline tools specification

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 commandline arguments.

Basic Example

use argh::FromArgs;

#[derive(FromArgs)]
/// Reach new heights.
struct GoUp {
    /// whether or not to jump
    #[argh(switch, short = 'j')]
    jump: bool,

    /// how high to go
    #[argh(option)]
    height: usize,

    /// an optional nickname for the pilot
    #[argh(option)]
    pilot_nickname: Option<String>,
}

let up: GoUp = argh::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            display usage information

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 #[argh(default = "<your_code_here>")] attribute, and in this case an option is treated as optional.

use argh::FromArgs;

fn default_height() -> usize {
    5
}

#[derive(FromArgs)]
/// Reach new heights.
struct GoUp {
    /// an optional nickname for the pilot
    #[argh(option)]
    pilot_nickname: Option<String>,

    /// an optional height
    #[argh(option, default = "default_height()")]
    height: usize,

    /// an optional direction which is "up" by default
    #[argh(option, default = "String::from(\"only up\")")]
    direction: String,
}

fn main() {
    let up: GoUp = argh::from_env();
}

Custom option types can be deserialized so long as they implement the FromArgValue trait (automatically implemented for all FromStr types). If more customized parsing is required, you can supply a custom fn(&str) -> Result<T, String> using the from_str_fn attribute:


#[derive(FromArgs)]
/// Goofy thing.
struct FiveStruct {
    /// always five
    #[argh(option, from_str_fn(always_five))]
    five: usize,
}

fn always_five(_value: &str) -> Result<usize, String> {
    Ok(5)
}

Positional arguments can be declared using #[argh(positional)]. These arguments will be parsed in order of their declaration in the structure:

use argh::FromArgs;
#[derive(FromArgs, PartialEq, Debug)]
/// A command with positional arguments.
struct WithPositional {
    #[argh(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:


#[derive(FromArgs, PartialEq, Debug)]
/// Top-level command.
struct TopLevel {
    #[argh(subcommand)]
    nested: MySubCommandEnum,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum MySubCommandEnum {
    One(SubCommandOne),
    Two(SubCommandTwo),
}

#[derive(FromArgs, PartialEq, Debug)]
/// First subcommand.
#[argh(subcommand, name = "one")]
struct SubCommandOne {
    #[argh(option)]
    /// how many x
    x: usize,
}

#[derive(FromArgs, PartialEq, Debug)]
/// Second subcommand.
#[argh(subcommand, name = "two")]
struct SubCommandTwo {
    #[argh(switch)]
    /// whether to fooey
    fooey: bool,
}

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.


#[derive(FromArgs, PartialEq, Debug)]
/// Top-level command.
struct TopLevel {
    #[argh(subcommand)]
    nested: MySubCommandEnum,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum MySubCommandEnum {
    Normal(NormalSubCommand),
    #[argh(dynamic)]
    Dynamic(Dynamic),
}

#[derive(FromArgs, PartialEq, Debug)]
/// Normal subcommand.
#[argh(subcommand, name = "normal")]
struct NormalSubCommand {
    #[argh(option)]
    /// how many x
    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();

            // argh 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_redact_arg_values(
        command_name: &[&str],
        args: &[&str],
    ) -> Option<Result<Vec<String>, EarlyExit>> {
        for command in Self::commands() {
            if command_name.last() == Some(&command.name) {
                // Process arguments and redact values here.
                if !args.is_empty() {
                    return Some(Err("Our example dynamic command never takes arguments!"
                                    .to_string().into()));
                }
                return Some(Ok(Vec::new()))
            }
        }
        None
    }

    fn try_from_args(command_name: &[&str], args: &[&str]) -> Option<Result<Self, EarlyExit>> {
        for command in Self::commands() {
            if command_name.last() == Some(&command.name) {
                if !args.is_empty() {
                    return Some(Err("Our example dynamic command never takes arguments!"
                                    .to_string().into()));
                }
                return Some(Ok(Dynamic { name: command.name.to_string() }))
            }
        }
        None
    }
}

Structs

Information to display to the user about why a FromArgs construction exited early.

Traits

Trait implemented by values returned from a dynamic subcommand handler.

A type which can be the receiver of a Flag.

Types which can be constructed from a single commandline value.

Types which can be constructed from a set of commandline arguments.

A FromArgs implementation that represents a single subcommand.

A FromArgs implementation that can parse into one or more subcommands.

A top-level FromArgs implementation that is not a subcommand.

Functions

Create a FromArgs type from the current process’s env::args.

Create a FromArgs type from the current process’s env::args.

Type Definitions

Information about a particular command used for output.

Derive Macros

Entrypoint for #[derive(FromArgs)].