argh

repository·master·Indexed 23 days ago

https://github.com/google/argh

An opinionated, derive-based argument parser for Rust, optimized for minimal code size and conformance to the Fuchsia command-line tools specification. It provides the FromArgs trait for parsing switches, options, and positional arguments, as well as FromArgValue for custom types. The library includes support for subcommands and a Generator trait via the argh_complete crate to produce shell completion scripts for Bash, Fish, Nushell, and Zsh.

Tokens
6.1K
Snippets
13
Records
35
Agent score
84%

What's inside argh

  1. Implement subcommands

    master

    To implement subcommands, define a separate FromArgs struct for each subcommand and an enum to represent the choice between them. Use the #[argh(subcommand)] attribute on the enum variants and on the field in the top-level struct.

    use argh::FromArgs;
    
    #[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", short = 't')]
    struct SubCommandTwo {
        #[argh(switch)]
        /// whether to fooey
        fooey: bool,
    }
  2. Basic usage of Argh

    master

    Argh is a derive-based argument parser for Rust. To use it, derive the FromArgs trait on a struct representing your command-line arguments and call argh::from_env() in your main function to parse the current program's arguments.

    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>,
    }
    
    fn main() {
        let up: GoUp = argh::from_env();
    }
  3. Implement subcommands with `argh`

    master

    Subcommands are implemented by defining an enum where each variant wraps a struct that also implements FromArgs. The parent struct must have a field with the #[argh(subcommand)] attribute.

    To name a subcommand explicitly (different from the variant name), use #[argh(subcommand, name = "name")] on the enum variant or the subcommand struct.

    Dynamic Subcommands: You can also discover subcommands at runtime by using the #[argh(dynamic)] attribute on an enum variant. The type inside that variant must implement the DynamicSubCommand trait, providing commands(), try_redact_arg_values(), and try_from_args().

    use argh::FromArgs;
    
    #[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,
    }
  4. Configure argument names and defaults

    master

    You can customize how arguments appear in the CLI using argh attributes:

    • Long Names: Use #[argh(long = "name")] to specify the --name flag. If omitted, argh converts the field name to kebab-case (e.g., my_field becomes --my-field).
    • Short Names: Use #[argh(short = 'c')] to specify a single-letter flag (e.g., -c).
    • Defaults: Use #[argh(default = "value")] to provide a default value if the argument is missing. This works for Option<T> and Vec<T> types.
    • Argument Names: For positional arguments, use #[argh(command = "name")] or similar to define how the argument is described in help text.
  5. Configure field kinds with `#[argh(...)]` attributes

    master

    When using #[derive(FromArgs)], every field must specify its kind using the argh attribute. Supported kinds include:

    • switch: A boolean flag (e.g., --verbose).
    • option: A keyed argument with a value (e.g., --name Alice).
    • positional: An argument identified by its position in the command line.
    • subcommand: A nested command structure.
    • remaining: (Internal/Advanced) used for capturing remaining arguments.
  6. FlagInfo and FlagInfoKind

    master

    Flags and options are represented by FlagInfo. The behavior of a flag is determined by its FlagInfoKind:

    • Switch: A boolean flag (e.g., --verbose).
    • Option { arg_name: &str }: A flag that requires an associated value (e.g., --output <file>).

    FlagInfo fields include:

    • kind: The FlagInfoKind.
    • optionality: How many times the flag can appear (Optionality).
    • long: The long-form string name.
    • short: An optional single-character short indicator.
    • description: A description of the flag.
    • hidden: A boolean to hide the flag from help messages.
  7. Fish completion script structure

    master

    The generated Fish completion script includes:

    1. A custom state machine function: __fish_<cmd_name>_using_command. This function inspects the current command line to determine if the user is currently using a specific command or subcommand, accounting for flags that take values.
    2. complete commands: A series of Fish complete commands that define:
      • -c <cmd>: The command name.
      • -l <long>: Long flags (stripped of leading dashes).
      • -s <short>: Short flags.
      • -r: Indicates the flag requires an argument (Option).
      • -d '<description>': The flag's description.
      • -a '<subcommand>': Available subcommands as arguments.
      • -f: Disables file completion for specific commands or subcommands if they have no positional arguments.
  8. CommandInfo and CommandInfoWithArgs data structures

    master

    The argh_shared crate provides structures used to represent command and argument metadata. While primarily intended for internal use between argh_derive and the argh runtime, these structures define the schema for command descriptions, flags, subcommands, and positional arguments.

    • CommandInfo: A lightweight structure containing a command's name, an optional short alias (as a char), and a description.
    • CommandInfoWithArgs: An extended structure that includes everything in CommandInfo plus examples, flags, notes, commands (subcommands), positionals, and error_codes.
  9. Rules for positional arguments

    master

    When defining positional arguments in a #[derive(FromArgs)] struct, there are specific constraints:

    1. Order of Optionality: Only the last positional argument can be optional (e.g., Option<T>), repeating (e.g., Vec<T>), or have a default value. All preceding positional arguments must be required.
    2. Greedy Arguments: The last positional argument can be marked as 'greedy' to consume all remaining arguments.
  10. Define command-line arguments with `FromArgs`

    master

    To use argh, define a struct that derives the FromArgs trait. You can specify different types of arguments using attributes:

    • Switches: Use #[argh(switch, short = 'x')] for boolean flags. They are true if present.
    • Options: Use #[argh(option)] for key-value pairs. They can be required, optional (Option<T>), or repeating (Vec<T>).
    • Positional Arguments: Use #[argh(positional)]. They are parsed in the order declared.
    • Greedy Positional Arguments: Use #[argh(positional, greedy)] on the last positional argument to consume all remaining arguments (similar to --).
    • Default Values: Use #[argh(option, default = "<expression>")] to make an option optional with a default value.
    • Custom Parsing: Use #[argh(option, from_str_fn(function_name))] to provide a custom parsing function fn(&str) -> Result<T, String>.
    • Help Triggers: Use #[argh(help_triggers("..."))] on the struct to define custom strings that trigger help output.
    • Hidden Arguments: Use #[argh(hidden_help)] to prevent an argument from appearing in the help text.
    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>,
    }
  11. Debug the `FromArgs` derive macro

    master

    To see the code generated by the argh::FromArgs macro, you can use the cargo-expand crate.

    1. Install cargo-expand (requires nightly Rust): cargo install cargo-expand.
    2. Run cargo expand within the package to view the expanded source code.