Skip to main content

Crate winnow_args

Crate winnow_args 

Source
Expand description

Command line parsing built from winnow parsers.

winnow-args parses a program’s arguments into typed values, typically a struct with one field per flag or positional. It distinguishes:

  • flags, long (--verbose) or short (-v); short flags can be bundled, -vq for -v -q;
  • values of flags, given as the next word (--path /tmp, -p /tmp) or attached (--path=/tmp, -p/tmp);
  • positionals, words identified by their position: a and b in cp a b;
  • subcommands, words that select a command with arguments of its own: add in git add -p;
  • --, after which every word is a positional.

A failed parse returns an Error with its kind, the word at fault and its offset.

There are two ways to say which of these a program takes:

  • #[derive(Args)] on a struct. A field is a flag or a positional, its type says how many values it takes and what they convert to, and its doc comment is its help. This is what most programs want, and the faster of the two.
  • By hand, with combinator. A flag is a winnow parser, and alt, repeat and the rest of winnow combine flags into a command line.

Either way the words are read where the shell left them: nothing is copied or re-split, and the bytes need not be UTF-8 until a value’s type asks for text. Both also cover command lines older than --long: +x options as in a bash builtin, and flags whose order matters as in ld.

use std::path::PathBuf;
use winnow_args::Args;

/// Look somewhere.
#[derive(Args, Debug)]
struct Cli {
    /// Say more.
    #[arg(short, long)]
    verbose: bool,
    /// Where to look.
    #[arg(short, long)]
    path: Option<PathBuf>,
    #[arg(positional)]
    files: Vec<String>,
}

// In `main`: `let cli = Cli::parse();`
let cli = Cli::parse_from(["-v", "--path=/tmp", "a", "b"])?;
assert!(cli.verbose);
assert_eq!(cli.path, Some(PathBuf::from("/tmp")));
assert_eq!(cli.files, ["a", "b"]);

§Where to look

  • Args, Subcommand, ValueEnum and Occurrence: the derives. Each page lists every attribute it takes.
  • combinator: the same command lines written by hand, and token, the lexer under both.
  • FromArg: what a value can be, and the types in value for a FromStr type, a C-syntax number and key=value.
  • Error and report: what a failed parse holds, and how it is printed.
  • help and color: the help text and its theme.
  • complete: completion scripts for bash, zsh, fish, elvish and PowerShell.
  • response: @file words.
  • with_env: a test’s own environment variables.

§Entry points

§Performance

The parser is generated at compile time, so a parse costs the same however many commands the program declares; clap and bpaf build theirs at each start. Cold instructions and warm time for one parse:

example -v --path /tmp/x a b cmise use -g node@20, 211 commands
derive2 939196 ns4 012328 ns
combinators4 574396 ns
usage5 683503 ns7 720782 ns
clap136 51415.3 µs4 943 837753 µs
bpaf 0.9142 99415.0 µs21 966 4002.65 ms

Test hardware: an Ampere-1a desktop (aarch64, 128 cores, 3.4 GHz), release profile, pinned to one core. The full tables and the method are in the repository’s benchmarks.

§Cargo features

  • derive (default): the derives.
  • help-text (default): the prose of derived help. Without it, help still lists commands, flags, values and defaults, and the binary is smaller.
  • terminal-size: wrap help to the terminal’s width when COLUMNS is unset.

§From clap and usage

The spellings that differ. Everything else is on the derive’s own page.

clapusagewinnow-args
the command#[derive(Parser)]#[derive(Cli)]#[derive(Args)]
its name, its version#[command(name, version)]#[usage(bin, version)]#[arg(name, version)]
an attribute#[arg], #[command]#[usage]#[arg]
subcommands#[derive(Subcommand)]#[derive(Subcommands)]#[derive(Subcommand)]
words after the program namenone: the name comes firstparse_fromparse_from
the whole linetry_parse_fromparse_from_argvparse_from_argv
a countaction = ArgAction::Countcountcount
a positionalno long or shortno short or long#[arg(positional)]
a field with no attributea positionala positional--field-name
a default, an environment variabledefault_value, envdefault, envdefault, env
several words, a delimiternum_args, value_delimiternum_args, delimitervalues, delimiter
a value that may be left offdefault_missing_valuedefault_missingdefault_missing
choices from an enum#[arg(value_enum)]#[usage(value_enum)]the type derives ValueEnum
a conflictconflicts_with = "file"conflicts("--file")conflicts("--file")
the flag that clears a switchArgAction::SetFalsenegate = "--no-force"negate = "no-force"
shared flags#[command(flatten)]#[usage(flatten)]#[arg(flatten)]
a subcommand field#[command(subcommand)]#[usage(subcommand)]#[arg(subcommand)]
an unknown flagan errora value, unless unknown_flags = "error"an error, unless unknown_flags = "value"

Re-exports§

pub use env::with_env;
pub use error::Error;
pub use error::ErrorKind;
pub use stream::Argv;
pub use stream::words;
pub use token::Arg;
pub use value::ChoiceError;
pub use value::FromArg;

Modules§

color
Colors for help and errors, for the terminal at hand.
combinator
Parsers written by hand: name a flag, then say what it is.
complete
Shell completion, answered by the program itself.
env
Environment variables as a source of values, after the command line and before defaults.
error
What went wrong, and where.
help
Help text: static data the derive emits, rendered only when asked for.
response
Response files: @file words that stand for the file’s contents.
stream
The input: argv as a slice of words.
token
Lexing: one command-line item at a time.
value
Turning a value’s bytes into a Rust type.

Structs§

BStr
A word of the command line, and a flag’s value: bytes, not necessarily UTF-8. What FromArg::from_arg is given. Improved Debug experience for &[u8] UTF-8-ish streams

Traits§

Args
A type parsed from a whole command line.
Globals
The global flags of a subcommand’s ancestors, which it accepts as its own.
Occurrence
Flags and words kept in command-line order: an enum deriving Occurrence, one variant per flag or positional, collected by an #[arg(sequence)] Vec field of an Args struct.
Subcommand
An enum of subcommands, selected by a word.

Functions§

globals
Globals from a closure. It does not answer Globals::short: the derive calls inherit, which forwards the parent’s letters, so a lenient subcommand still sees them.
report
Print what a failed parse means, and give the exit status: help and version on stdout with 0, a bare arg_required_else_help invocation’s help on stderr with 2, anything else as an error on stderr with 2. Colored with color::Theme::DEFAULT where the stream written to shows color; see report_with for another theme.
report_with
report, painted with theme: its palette for the depth color::Depth::detect finds on the stream written to.

Derive Macros§

Args
Derive Args for a struct with named fields: the generated loop parses the whole command line.
Occurrence
Derive Occurrence for an enum: one variant per flag or positional, kept in command-line order by an #[arg(sequence)] field of an Args struct.
Subcommand
Derive Subcommand (and Args, so the enum can be the whole command line) for an enum of subcommands.
ValueEnum
Derive FromArg for an enum of unit variants, matched on the value’s bytes; help lists them as possible values.