Args

Successful Parsing

Simple Arguments

Parse a struct with flags, options, and positional arguments.

Target Type
/// A simple CLI tool for file processing.
#[derive(Facet)]
struct SimpleArgs {
    /// Enable verbose output
    #[facet(args::named, args::short)]
    verbose: bool,

    /// Number of parallel jobs to run
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Input file to process
    #[facet(args::positional)]
    input: String,

    /// Output file (defaults to stdout)
    #[facet(args::positional)]
    output: Option<String>,
}

Rust Input

from_slice(&["-v", "-j", "4", "input.txt", "output.txt"])

Success

SimpleArgs {
  verbosetrue,
  jobsOption<usize>::Some(4),
  input"input.txt",
  outputOption<String>::Some("output.txt"),
}

Attached Short Flag Value

Short flags can have their values attached directly without a space.

Target Type
/// A simple CLI tool for file processing.
#[derive(Facet)]
struct SimpleArgs {
    /// Enable verbose output
    #[facet(args::named, args::short)]
    verbose: bool,

    /// Number of parallel jobs to run
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Input file to process
    #[facet(args::positional)]
    input: String,

    /// Output file (defaults to stdout)
    #[facet(args::positional)]
    output: Option<String>,
}

Rust Input

from_slice(&["-j4", "input.txt"])

Success

SimpleArgs {
  verbosefalse,
  jobsOption<usize>::Some(4),
  input"input.txt",
  outputOption<String>::None,
}

Boolean Flag with Explicit Value

Boolean flags can be explicitly set to true or false using =.

Target Type
/// A simple CLI tool for file processing.
#[derive(Facet)]
struct SimpleArgs {
    /// Enable verbose output
    #[facet(args::named, args::short)]
    verbose: bool,

    /// Number of parallel jobs to run
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Input file to process
    #[facet(args::positional)]
    input: String,

    /// Output file (defaults to stdout)
    #[facet(args::positional)]
    output: Option<String>,
}

Rust Input

from_slice(&["--verbose=true", "input.txt"])

Success

SimpleArgs {
  verbosetrue,
  jobsOption<usize>::None,
  input"input.txt",
  outputOption<String>::None,
}

Subcommands

Parse a CLI with subcommands, each with their own arguments.

Target Type
/// Git-like CLI with subcommands.
#[derive(Facet)]
struct GitLikeArgs {
    /// Show version information
    #[facet(args::named)]
    version: bool,

    /// Git command to run
    #[facet(args::subcommand)]
    command: GitCommand,
}

/// Available commands
#[derive(Facet)]
#[repr(u8)]
enum GitCommand {
    /// Clone a repository into a new directory
    Clone {
        /// The repository URL to clone
        #[facet(args::positional)]
        url: String,

        /// Directory to clone into
        #[facet(args::positional)]
        directory: Option<String>,

        /// Clone only the specified branch
        #[facet(args::named, args::short)]
        branch: Option<String>,

        /// Create a shallow clone with limited history
        #[facet(args::named)]
        depth: Option<usize>,
    },

    /// Show the working tree status
    Status {
        /// Show short-format output
        #[facet(args::named, args::short)]
        short: bool,

        /// Show the branch even in short-format
        #[facet(args::named, args::short)]
        branch: bool,
    },

    /// Manage set of tracked repositories
    Remote {
        /// Remote action to perform
        #[facet(args::subcommand)]
        action: RemoteAction,
    },
}

/// Remote management commands
#[derive(Facet)]
#[repr(u8)]
enum RemoteAction {
    /// Add a remote named <name> for the repository at <url>
    Add {
        /// Name of the remote
        #[facet(args::positional)]
        name: String,

        /// URL of the remote repository
        #[facet(args::positional)]
        url: String,
    },

    /// Remove the remote named <name>
    rm {
        /// Name of the remote to remove
        #[facet(args::positional)]
        name: String,
    },

    /// List all remotes
    ls {
        /// Show remote URLs after names
        #[facet(args::named, args::short)]
        verbose: bool,
    },
}

Rust Input

from_slice(&["clone", "--branch", "main", "https://github.com/user/repo"])

Success

GitLikeArgs {
  versionfalse,
  commandGitCommand::Clone {
    url"https://github.com/user/repo",
    directoryOption<String>::None,
    branchOption<String>::Some("main"),
    depthOption<usize>::None,
  },
}

Nested Subcommands

Parse deeply nested subcommands like git remote add.

Target Type
/// Git-like CLI with subcommands.
#[derive(Facet)]
struct GitLikeArgs {
    /// Show version information
    #[facet(args::named)]
    version: bool,

    /// Git command to run
    #[facet(args::subcommand)]
    command: GitCommand,
}

/// Available commands
#[derive(Facet)]
#[repr(u8)]
enum GitCommand {
    /// Clone a repository into a new directory
    Clone {
        /// The repository URL to clone
        #[facet(args::positional)]
        url: String,

        /// Directory to clone into
        #[facet(args::positional)]
        directory: Option<String>,

        /// Clone only the specified branch
        #[facet(args::named, args::short)]
        branch: Option<String>,

        /// Create a shallow clone with limited history
        #[facet(args::named)]
        depth: Option<usize>,
    },

    /// Show the working tree status
    Status {
        /// Show short-format output
        #[facet(args::named, args::short)]
        short: bool,

        /// Show the branch even in short-format
        #[facet(args::named, args::short)]
        branch: bool,
    },

    /// Manage set of tracked repositories
    Remote {
        /// Remote action to perform
        #[facet(args::subcommand)]
        action: RemoteAction,
    },
}

/// Remote management commands
#[derive(Facet)]
#[repr(u8)]
enum RemoteAction {
    /// Add a remote named <name> for the repository at <url>
    Add {
        /// Name of the remote
        #[facet(args::positional)]
        name: String,

        /// URL of the remote repository
        #[facet(args::positional)]
        url: String,
    },

    /// Remove the remote named <name>
    rm {
        /// Name of the remote to remove
        #[facet(args::positional)]
        name: String,
    },

    /// List all remotes
    ls {
        /// Show remote URLs after names
        #[facet(args::named, args::short)]
        verbose: bool,
    },
}

Rust Input

from_slice(&["remote", "add", "origin", "https://github.com/user/repo"])

Success

GitLikeArgs {
  versionfalse,
  commandGitCommand::Remote {
    actionRemoteAction::Add {
      name"origin",
      url"https://github.com/user/repo",
    },
  },
}

Help Generation

Simple Help

Auto-generated help text from struct definition and doc comments.

Target Type
/// A simple CLI tool for file processing.
#[derive(Facet)]
struct SimpleArgs {
    /// Enable verbose output
    #[facet(args::named, args::short)]
    verbose: bool,

    /// Number of parallel jobs to run
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Input file to process
    #[facet(args::positional)]
    input: String,

    /// Output file (defaults to stdout)
    #[facet(args::positional)]
    output: Option<String>,
}

Rust Output

mytool 1.0.0

A simple CLI tool for file processing.

USAGE:
    mytool [OPTIONS] <INPUT> [OUTPUT]

ARGUMENTS:
        <INPUT>
            Input file to process
        <OUTPUT>
            Output file (defaults to stdout)

OPTIONS:
    -v, --verbose
            Enable verbose output
    -j, --jobs <OPTION>
            Number of parallel jobs to run

Help with Subcommands

Help text automatically lists available subcommands with descriptions.

Target Type
/// Git-like CLI with subcommands.
#[derive(Facet)]
struct GitLikeArgs {
    /// Show version information
    #[facet(args::named)]
    version: bool,

    /// Git command to run
    #[facet(args::subcommand)]
    command: GitCommand,
}

/// Available commands
#[derive(Facet)]
#[repr(u8)]
enum GitCommand {
    /// Clone a repository into a new directory
    Clone {
        /// The repository URL to clone
        #[facet(args::positional)]
        url: String,

        /// Directory to clone into
        #[facet(args::positional)]
        directory: Option<String>,

        /// Clone only the specified branch
        #[facet(args::named, args::short)]
        branch: Option<String>,

        /// Create a shallow clone with limited history
        #[facet(args::named)]
        depth: Option<usize>,
    },

    /// Show the working tree status
    Status {
        /// Show short-format output
        #[facet(args::named, args::short)]
        short: bool,

        /// Show the branch even in short-format
        #[facet(args::named, args::short)]
        branch: bool,
    },

    /// Manage set of tracked repositories
    Remote {
        /// Remote action to perform
        #[facet(args::subcommand)]
        action: RemoteAction,
    },
}

/// Remote management commands
#[derive(Facet)]
#[repr(u8)]
enum RemoteAction {
    /// Add a remote named <name> for the repository at <url>
    Add {
        /// Name of the remote
        #[facet(args::positional)]
        name: String,

        /// URL of the remote repository
        #[facet(args::positional)]
        url: String,
    },

    /// Remove the remote named <name>
    rm {
        /// Name of the remote to remove
        #[facet(args::positional)]
        name: String,
    },

    /// List all remotes
    ls {
        /// Show remote URLs after names
        #[facet(args::named, args::short)]
        verbose: bool,
    },
}

Rust Output

git 2.40.0

Git-like CLI with subcommands.

USAGE:
    git [OPTIONS] <COMMAND>

OPTIONS:
        --version
            Show version information

COMMANDS:
    clone
            Clone a repository into a new directory
    status
            Show the working tree status
    remote
            Manage set of tracked repositories

Shell Completions

Bash Completions

Generated Bash completion script for tab-completion support.

Target Type
/// A build tool configuration
#[derive(Facet)]
struct BuildArgs {
    /// Build in release mode with optimizations
    #[facet(args::named, args::short)]
    release: bool,

    /// Number of parallel jobs
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Package to build
    #[facet(args::named, args::short)]
    package: Option<String>,

    /// Build all packages in the workspace
    #[facet(args::named)]
    workspace: bool,

    /// Space-separated list of features to enable
    #[facet(args::named, args::short)]
    features: Option<String>,

    /// Target triple to build for
    #[facet(args::named)]
    target: Option<String>,
}

Rust Output

_cargo-build() {
    local cur prev words cword
    _init_completion || return

    local commands=""
    local flags=""

    flags="--release -r --jobs -j --package -p --workspace --features -F --target"

    case "$prev" in
        # Add cases for flags that take values
        *)
            ;;
    esac

    if [[ "$cur" == -* ]]; then
        COMPREPLY=($(compgen -W "$flags" -- "$cur"))
    elif [[ -n "$commands" ]]; then
        COMPREPLY=($(compgen -W "$commands" -- "$cur"))
    fi
}

complete -F _cargo-build cargo-build

Zsh Completions

Generated Zsh completion script with argument descriptions.

Target Type
/// A build tool configuration
#[derive(Facet)]
struct BuildArgs {
    /// Build in release mode with optimizations
    #[facet(args::named, args::short)]
    release: bool,

    /// Number of parallel jobs
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Package to build
    #[facet(args::named, args::short)]
    package: Option<String>,

    /// Build all packages in the workspace
    #[facet(args::named)]
    workspace: bool,

    /// Space-separated list of features to enable
    #[facet(args::named, args::short)]
    features: Option<String>,

    /// Target triple to build for
    #[facet(args::named)]
    target: Option<String>,
}

Rust Output

#compdef cargo-build

_cargo-build() {
    local -a commands
    local -a options

    options=(
        '-r[Build in release mode with optimizations]'
        '--release[Build in release mode with optimizations]'
        '-j[Number of parallel jobs]'
        '--jobs[Number of parallel jobs]'
        '-p[Package to build]'
        '--package[Package to build]'
        '--workspace[Build all packages in the workspace]'
        '-F[Space-separated list of features to enable]'
        '--features[Space-separated list of features to enable]'
        '--target[Target triple to build for]'
    )

    _arguments $options
}

_cargo-build "$@"

Fish Completions

Generated Fish shell completion script.

Target Type
/// A build tool configuration
#[derive(Facet)]
struct BuildArgs {
    /// Build in release mode with optimizations
    #[facet(args::named, args::short)]
    release: bool,

    /// Number of parallel jobs
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Package to build
    #[facet(args::named, args::short)]
    package: Option<String>,

    /// Build all packages in the workspace
    #[facet(args::named)]
    workspace: bool,

    /// Space-separated list of features to enable
    #[facet(args::named, args::short)]
    features: Option<String>,

    /// Target triple to build for
    #[facet(args::named)]
    target: Option<String>,
}

Rust Output

# Fish completion for cargo-build

complete -c cargo-build -s r -l release -d 'Build in release mode with optimizations'
complete -c cargo-build -s j -l jobs -d 'Number of parallel jobs'
complete -c cargo-build -s p -l package -d 'Package to build'
complete -c cargo-build -l workspace -d 'Build all packages in the workspace'
complete -c cargo-build -s F -l features -d 'Space-separated list of features to enable'
complete -c cargo-build -l target -d 'Target triple to build for'

Error Diagnostics

Unknown Flag

Error when an unrecognized flag is provided.

Target Type
/// A simple CLI tool for file processing.
#[derive(Facet)]
struct SimpleArgs {
    /// Enable verbose output
    #[facet(args::named, args::short)]
    verbose: bool,

    /// Number of parallel jobs to run
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Input file to process
    #[facet(args::positional)]
    input: String,

    /// Output file (defaults to stdout)
    #[facet(args::positional)]
    output: Option<String>,
}

Rust Input

from_slice(&["--verbos", "input.txt"])

Error

args::unknown_long_flag

  × Could not parse CLI arguments    ╭────  1 │ --verbos input.txt     · ────┬───    ·     ╰── unknown flag `--verbos`    ╰────   help: did you mean `--verbose`?

Unknown Flag with Suggestion

When the flag name is close to a valid one, a suggestion is offered.

Target Type
/// A build tool configuration
#[derive(Facet)]
struct BuildArgs {
    /// Build in release mode with optimizations
    #[facet(args::named, args::short)]
    release: bool,

    /// Number of parallel jobs
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Package to build
    #[facet(args::named, args::short)]
    package: Option<String>,

    /// Build all packages in the workspace
    #[facet(args::named)]
    workspace: bool,

    /// Space-separated list of features to enable
    #[facet(args::named, args::short)]
    features: Option<String>,

    /// Target triple to build for
    #[facet(args::named)]
    target: Option<String>,
}

Rust Input

from_slice(&["--releas"])

Error

args::unknown_long_flag

  × Could not parse CLI arguments    ╭────  1 │ --releas     · ────┬───    ·     ╰── unknown flag `--releas`    ╰────   help: did you mean `--release`?

Invalid Short Flag

Boolean short flags cannot have trailing characters attached.

Target Type
/// A simple CLI tool for file processing.
#[derive(Facet)]
struct SimpleArgs {
    /// Enable verbose output
    #[facet(args::named, args::short)]
    verbose: bool,

    /// Number of parallel jobs to run
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Input file to process
    #[facet(args::positional)]
    input: String,

    /// Output file (defaults to stdout)
    #[facet(args::positional)]
    output: Option<String>,
}

Rust Input

from_slice(&["-vxyz", "input.txt"])

Error

args::unknown_short_flag

  × Could not parse CLI arguments    ╭────  1 │ -vxyz input.txt     · ──┬──    ·   ╰── unknown flag `-vxyz`    ╰────   help: `-vxyz` is `--verbose`

Triple Dash Flag

Flags with too many dashes are rejected.

Target Type
/// A simple CLI tool for file processing.
#[derive(Facet)]
struct SimpleArgs {
    /// Enable verbose output
    #[facet(args::named, args::short)]
    verbose: bool,

    /// Number of parallel jobs to run
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Input file to process
    #[facet(args::positional)]
    input: String,

    /// Output file (defaults to stdout)
    #[facet(args::positional)]
    output: Option<String>,
}

Rust Input

from_slice(&["---verbose", "input.txt"])

Error

args::unknown_long_flag

  × Could not parse CLI arguments    ╭────  1 │ ---verbose input.txt     · ─────┬────    ·      ╰── unknown flag `---verbose`    ╰────   help: available options:           -v, --verbose  Enable verbose output           -j, --jobs     Number of parallel jobs to run               <input>    Input file to process               <output>   Output file (defaults to stdout)

Single Dash with Long Name

Long flag names require double dashes.

Target Type
/// A simple CLI tool for file processing.
#[derive(Facet)]
struct SimpleArgs {
    /// Enable verbose output
    #[facet(args::named, args::short)]
    verbose: bool,

    /// Number of parallel jobs to run
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Input file to process
    #[facet(args::positional)]
    input: String,

    /// Output file (defaults to stdout)
    #[facet(args::positional)]
    output: Option<String>,
}

Rust Input

from_slice(&["-verbose", "input.txt"])

Error

args::unknown_short_flag

  × Could not parse CLI arguments    ╭────  1 │ -verbose input.txt     · ────┬───    ·     ╰── unknown flag `-verbose`    ╰────   help: `-verbose` is `--verbose`

Missing Value

Error when a flag that requires a value doesn't get one.

Target Type
/// A simple CLI tool for file processing.
#[derive(Facet)]
struct SimpleArgs {
    /// Enable verbose output
    #[facet(args::named, args::short)]
    verbose: bool,

    /// Number of parallel jobs to run
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Input file to process
    #[facet(args::positional)]
    input: String,

    /// Output file (defaults to stdout)
    #[facet(args::positional)]
    output: Option<String>,
}

Rust Input

from_slice(&["-j"])

Error

args::expected_value

  × Could not parse CLI arguments    ╭────  1 │ -j     · ─┬    ·  ╰── expected `usize` value    ╰────   help: provide a value after the flag

Missing Required Argument

Error when a required positional argument is not provided.

Target Type
/// A simple CLI tool for file processing.
#[derive(Facet)]
struct SimpleArgs {
    /// Enable verbose output
    #[facet(args::named, args::short)]
    verbose: bool,

    /// Number of parallel jobs to run
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Input file to process
    #[facet(args::positional)]
    input: String,

    /// Output file (defaults to stdout)
    #[facet(args::positional)]
    output: Option<String>,
}

Rust Input

from_slice(&["-v"])

Error

args::missing_argument

  × Could not parse CLI arguments    ╭────  1 │ -v     ╰────   help: provide a value for `<input>`

Unexpected Positional Argument

Error when a positional argument is provided but not expected.

Target Type
/// A build tool configuration
#[derive(Facet)]
struct BuildArgs {
    /// Build in release mode with optimizations
    #[facet(args::named, args::short)]
    release: bool,

    /// Number of parallel jobs
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Package to build
    #[facet(args::named, args::short)]
    package: Option<String>,

    /// Build all packages in the workspace
    #[facet(args::named)]
    workspace: bool,

    /// Space-separated list of features to enable
    #[facet(args::named, args::short)]
    features: Option<String>,

    /// Target triple to build for
    #[facet(args::named)]
    target: Option<String>,
}

Rust Input

from_slice(&["extra", "--release"])

Error

args::unexpected_positional

  × Could not parse CLI arguments    ╭────  1 │ extra --release     · ──┬──    ·   ╰── unexpected positional argument    ╰────   help: available options:           -r, --release    Build in release mode with optimizations           -j, --jobs       Number of parallel jobs           -p, --package    Package to build               --workspace  Build all packages in the workspace           -F, --features   Space-separated list of features to enable               --target     Target triple to build for

Unknown Subcommand

Error when an unrecognized subcommand is provided, with available options listed.

Target Type
/// Git-like CLI with subcommands.
#[derive(Facet)]
struct GitLikeArgs {
    /// Show version information
    #[facet(args::named)]
    version: bool,

    /// Git command to run
    #[facet(args::subcommand)]
    command: GitCommand,
}

/// Available commands
#[derive(Facet)]
#[repr(u8)]
enum GitCommand {
    /// Clone a repository into a new directory
    Clone {
        /// The repository URL to clone
        #[facet(args::positional)]
        url: String,

        /// Directory to clone into
        #[facet(args::positional)]
        directory: Option<String>,

        /// Clone only the specified branch
        #[facet(args::named, args::short)]
        branch: Option<String>,

        /// Create a shallow clone with limited history
        #[facet(args::named)]
        depth: Option<usize>,
    },

    /// Show the working tree status
    Status {
        /// Show short-format output
        #[facet(args::named, args::short)]
        short: bool,

        /// Show the branch even in short-format
        #[facet(args::named, args::short)]
        branch: bool,
    },

    /// Manage set of tracked repositories
    Remote {
        /// Remote action to perform
        #[facet(args::subcommand)]
        action: RemoteAction,
    },
}

/// Remote management commands
#[derive(Facet)]
#[repr(u8)]
enum RemoteAction {
    /// Add a remote named <name> for the repository at <url>
    Add {
        /// Name of the remote
        #[facet(args::positional)]
        name: String,

        /// URL of the remote repository
        #[facet(args::positional)]
        url: String,
    },

    /// Remove the remote named <name>
    rm {
        /// Name of the remote to remove
        #[facet(args::positional)]
        name: String,
    },

    /// List all remotes
    ls {
        /// Show remote URLs after names
        #[facet(args::named, args::short)]
        verbose: bool,
    },
}

Rust Input

from_slice(&["clon", "https://example.com"])

Error

args::unknown_subcommand

  × Could not parse CLI arguments    ╭────  1 │ clon https://example.com     · ──┬─    ·   ╰── unknown subcommand `clon`    ╰────   help: did you mean `clone`?

Missing Subcommand

Error when a required subcommand is not provided.

Target Type
/// Git-like CLI with subcommands.
#[derive(Facet)]
struct GitLikeArgs {
    /// Show version information
    #[facet(args::named)]
    version: bool,

    /// Git command to run
    #[facet(args::subcommand)]
    command: GitCommand,
}

/// Available commands
#[derive(Facet)]
#[repr(u8)]
enum GitCommand {
    /// Clone a repository into a new directory
    Clone {
        /// The repository URL to clone
        #[facet(args::positional)]
        url: String,

        /// Directory to clone into
        #[facet(args::positional)]
        directory: Option<String>,

        /// Clone only the specified branch
        #[facet(args::named, args::short)]
        branch: Option<String>,

        /// Create a shallow clone with limited history
        #[facet(args::named)]
        depth: Option<usize>,
    },

    /// Show the working tree status
    Status {
        /// Show short-format output
        #[facet(args::named, args::short)]
        short: bool,

        /// Show the branch even in short-format
        #[facet(args::named, args::short)]
        branch: bool,
    },

    /// Manage set of tracked repositories
    Remote {
        /// Remote action to perform
        #[facet(args::subcommand)]
        action: RemoteAction,
    },
}

/// Remote management commands
#[derive(Facet)]
#[repr(u8)]
enum RemoteAction {
    /// Add a remote named <name> for the repository at <url>
    Add {
        /// Name of the remote
        #[facet(args::positional)]
        name: String,

        /// URL of the remote repository
        #[facet(args::positional)]
        url: String,
    },

    /// Remove the remote named <name>
    rm {
        /// Name of the remote to remove
        #[facet(args::positional)]
        name: String,
    },

    /// List all remotes
    ls {
        /// Show remote URLs after names
        #[facet(args::named, args::short)]
        verbose: bool,
    },
}

Rust Input

from_slice(&["--version"])

Error

args::missing_subcommand

  × Could not parse CLI arguments    ╭────  1 │ --version     ╰────   help: available subcommands:           clone   Clone a repository into a new directory           status  Show the working tree status           remote  Manage set of tracked repositories

Missing Nested Subcommand Argument

Error when a required argument in a nested subcommand is missing.

Target Type
/// Git-like CLI with subcommands.
#[derive(Facet)]
struct GitLikeArgs {
    /// Show version information
    #[facet(args::named)]
    version: bool,

    /// Git command to run
    #[facet(args::subcommand)]
    command: GitCommand,
}

/// Available commands
#[derive(Facet)]
#[repr(u8)]
enum GitCommand {
    /// Clone a repository into a new directory
    Clone {
        /// The repository URL to clone
        #[facet(args::positional)]
        url: String,

        /// Directory to clone into
        #[facet(args::positional)]
        directory: Option<String>,

        /// Clone only the specified branch
        #[facet(args::named, args::short)]
        branch: Option<String>,

        /// Create a shallow clone with limited history
        #[facet(args::named)]
        depth: Option<usize>,
    },

    /// Show the working tree status
    Status {
        /// Show short-format output
        #[facet(args::named, args::short)]
        short: bool,

        /// Show the branch even in short-format
        #[facet(args::named, args::short)]
        branch: bool,
    },

    /// Manage set of tracked repositories
    Remote {
        /// Remote action to perform
        #[facet(args::subcommand)]
        action: RemoteAction,
    },
}

/// Remote management commands
#[derive(Facet)]
#[repr(u8)]
enum RemoteAction {
    /// Add a remote named <name> for the repository at <url>
    Add {
        /// Name of the remote
        #[facet(args::positional)]
        name: String,

        /// URL of the remote repository
        #[facet(args::positional)]
        url: String,
    },

    /// Remove the remote named <name>
    rm {
        /// Name of the remote to remove
        #[facet(args::positional)]
        name: String,
    },

    /// List all remotes
    ls {
        /// Show remote URLs after names
        #[facet(args::named, args::short)]
        verbose: bool,
    },
}

Rust Input

from_slice(&["remote", "add", "origin"])

Error

args::missing_argument

  × Could not parse CLI arguments    ╭────  1 │ remote add origin     ╰────   help: provide a value for `<url>`

Invalid Value Type

Error when a value cannot be parsed as the expected type.

Target Type
/// A simple CLI tool for file processing.
#[derive(Facet)]
struct SimpleArgs {
    /// Enable verbose output
    #[facet(args::named, args::short)]
    verbose: bool,

    /// Number of parallel jobs to run
    #[facet(args::named, args::short)]
    jobs: Option<usize>,

    /// Input file to process
    #[facet(args::positional)]
    input: String,

    /// Output file (defaults to stdout)
    #[facet(args::positional)]
    output: Option<String>,
}

Rust Input

from_slice(&["-j", "not-a-number", "input.txt"])

Error

args::reflect_error

  × Could not parse CLI arguments    ╭────  1 │ -j not-a-number input.txt     ·    ──────┬─────    ·          ╰── invalid value for `usize`    ╰────