diff --git a/.lock b/.lock new file mode 100644 index 00000000..e69de29b diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/bpaf/_documentation/_0_intro/index.html b/bpaf/_documentation/_0_intro/index.html new file mode 100644 index 00000000..5d3d79c3 --- /dev/null +++ b/bpaf/_documentation/_0_intro/index.html @@ -0,0 +1,144 @@ +bpaf::_documentation::_0_intro - Rust +
Expand description

 

+ + + + +
+ +

↑ Project documentation ↑

+
+

Tutorials →

+
+
§Introduction and design goals
+

A quick intro. What, why and how

+

bpaf is a lightweight and flexible command line parser that uses both combinatoric and derive +style API

+

Combinatoric API usually means a bit more typing but no dependency on proc macros and more help +from the IDE, derive API uses proc macro to save on typing but your IDE will be less likely to +help you. Picking one API style does not lock you out from using the other style, you can mix +and match both in a single parser

+

§Examples of both styles

Combinatoric example + +
use bpaf::*;
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    message: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let message = positional("MESSAGE").help("Message to print in a big friendly letters");
+    construct!(Options { message }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
use bpaf::*;
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Message to print in a big friendly letters
+    #[bpaf(positional("MESSAGE"))]
+    message: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

With everything in place users should be able to pass their arguments

+
+$ app "Hello world"
+Options { message: "Hello world" } +
+

As well as read the help message generated by the library

+
+$ app --help
+

Usage: app MESSAGE

+Available positional items:
MESSAGE
+
Message to print in a big friendly letters
+
+

+Available options:
-h, --help
+
Prints help information
+
+

+ +
+
+

§Design goals

§Parse, don’t validate

+

bpaf tries hard to let you move as many invariants about the user input you are +trying to parse into rust types: for mutually exclusive options you can get enum with +exclusive items going into separate branches, and you can collect results into types like +BTreeSet, or whatever custom type you might have with +custom parsing. Ideas for +making invalid states unrepresentable +and using parsing over validation +are not new.

+

That said you can also validate your inputs if this fits your situation better. If you want to +ensure that the sum of every numeric field must be divisible by both 3 and 5, but only when it’s +Thursday - you can do that too.

+

§Flexibility

+

While aiming to be a general-purpose command line parser bpaf offers a few backdoors that +allow you to parse pretty much anything you want: chained commands, custom blocks of options, +DOS-style options (/ofile.pas), dd style options (if=file of=out), etc. A similar idea applies +to what the parser can produce - if your app operates with boxed string slices internally - bpaf +will give you Box<str> instead of String if you ask it to.

+

The only restriction is that you cannot use information from items parsed earlier (but not +the fact that something was parsed successfully or not) to decide to how to parse further +options, and even then you can side step this restriction by passing some shared state as a +parameter to the parsers.

+

§Reusability

+

Parsers in bpaf are not monolithic and you can share their parts across multiple binaries, +workspace members or even independent projects. Say you have multiple binaries in a workspace +that perform different operations on some input. You can declare a parser for the input +specifically, along with all the validations, help messages or shell dynamic completion +functions you need and use it across all the binaries alongside the arguments specific to +those binaries.

+

§Composition, transformation

+

Parsers in bpaf are not finalized either, say you have a parser that describes a single input +for your program, it can take multiple arguments or perform extra validations, etc. You can +always compose this parser with any other parser to produce tuples of both results for example. +Or to make it so parser runs multiple times and collects results into a Vec.

+

§Performance

+

While performance is an explicit non-goal - bpaf does nothing that would pessimize it either, +so performance is on par or better compared to other fully featured parsers.

+

§Correctness

+

bpaf would parse only items it can represent and will reject anything it cannot represent +in the output. Say your parser accepts both --intel and --att flags, but encodes the result +into enum Style { Intel, Att }, bpaf will accept those flags separately, but not if they +are used both at once. If the parser later collects multiple styles into a Vec<Style> then it +will accept any combinationof those flags.

+

§User friendly

+

bpaf tries to provide user-friendly error messages, and suggestions for typos but also scripts +for shell completion, man pages and markdown documentation for the web.

+

 

+ + + + +
+ +

↑ Project documentation ↑

+
+

Tutorials →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_0_intro/sidebar-items.js b/bpaf/_documentation/_0_intro/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_0_intro/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_0_switch/index.html b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_0_switch/index.html new file mode 100644 index 00000000..8f63548c --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_0_switch/index.html @@ -0,0 +1,173 @@ +bpaf::_documentation::_1_tutorials::_0_types_of_arguments::_0_switch - Rust +
Expand description

 

+ + + + +
+ +

↑ Types of arguments ↑

+
+

Option arguments or arguments →

+
+
§Options, switches or flags
+

Options or flags usually starts with a dash, a single dash for short options and a double dash for +long one. Several short options can usually be squashed together with a single dash in front of +them to save on typing: -vvv can be parsed the same as -v -v -v. Options don’t have any +other information apart from being there or not. Relative position usually does not matter and +--alpha --beta should parse the same as --beta --alpha.

+
+
+$ cargo --help
+$ ls -la
+$ ls --time --reverse
+
+
+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    release: bool,
+    default_features: bool,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help("Produce verbose output")
+        .switch();
+    let release = long("release")
+        .help("Build artifacts in release mode")
+        .flag(true, false);
+    let default_features = long("no-default-features")
+        .help("Do not activate default features")
+        // default_features uses opposite values,
+        // producing `true` when value is absent
+        .flag(false, true);
+
+    construct!(Options {
+        verbose,
+        release,
+        default_features,
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Produce verbose output
+    // bpaf uses `switch` for `bool` fields in named
+    // structs unless consumer attribute is present.
+    // But it is also possible to give it explicit
+    // consumer annotation to serve as a reminder:
+    // #[bpaf(short, long, switch)]
+    #[bpaf(short, long)]
+    verbose: bool,
+
+    #[bpaf(flag(true, false))]
+    /// Build artifacts in release mode
+    release: bool,
+
+    /// Do not activate default features
+    // default_features uses opposite values,
+    // producing `true` when value is absent
+    #[bpaf(long("no-default-features"), flag(false, true))]
+    default_features: bool,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help output bpaf shows switches as usual flags with no meta variable attached

+
+$ app --help
+

Usage: app [-v] [--release] [--no-default-features]

+Available options:
-v, --verbose
+
Produce verbose output
+
--release
+
Build artifacts in release mode
+
--no-default-features
+
Do not activate default features
+
-h, --help
+
Prints help information
+
+

+ +
+

Both switch and flag succeed if value is not present, switch returns true, flag returns +second value.

+
+$ app
+Options { verbose: false, release: false, default_features: true } +
+

When value is present - switch returns true, flag returns first value.

+
+$ app --verbose --no-default-features --detailed
+Error: --detailed is not expected in this context + +
+

Like with most parsrs unless specified switch and flag consume at most one item from the +command line:

+
+$ app --no-default-features --no-default-features
+Error: argument --no-default-features cannot be used multiple times in this context + +
+
+

For more detailed info see NamedArg::switch and +NamedArg::flag

+

 

+ + + + +
+ +

↑ Types of arguments ↑

+
+

Option arguments or arguments →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_0_switch/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_0_switch/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_0_switch/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_1_argument/index.html b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_1_argument/index.html new file mode 100644 index 00000000..78d977c4 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_1_argument/index.html @@ -0,0 +1,179 @@ +bpaf::_documentation::_1_tutorials::_0_types_of_arguments::_1_argument - Rust +
Expand description

 

+ + + + +
+

← Options, switches or flags

+
+

↑ Types of arguments ↑

+
+

Operands or positional items →

+
+
§Option arguments or arguments
+

Option arguments are similar to regular options but they come with an extra value attached. +Value can be separated by a space, = or directly adjacent to a short name. Same as with +options - their relative position usually doesn’t matter.

+
+
+$ cargo build --package bpaf
+$ cargo test -j2
+$ cargo check --bin=megapotato
+
+
+

In the generated help message or documentation they come with a placeholder metavariable, +usually a short, all-caps word describing what the value means: NAME, AGE, SPEC, and CODE +are all valid examples.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    name: String,
+    age: usize,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let name = short('n')
+        .long("name")
+        .help("Specify user name")
+        // you can specify exact type argument should produce
+        // for as long as it implements `FromStr`
+        .argument::<String>("NAME");
+
+    let age = long("age")
+        .help("Specify user age")
+        // but often rust can figure it out from the context,
+        // here age is going to be `usize`
+        .argument("AGE")
+        .fallback(18)
+        .display_fallback();
+
+    construct!(Options { name, age }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    // you can specify exact type argument should produce
+    // for as long as it implements `FromStr`
+    #[bpaf(short, long, argument::<String>("NAME"))]
+    /// Specify user name
+    name: String,
+    // but often rust can figure it out from the context,
+    // here age is going to be `usize`
+    #[bpaf(argument("AGE"), fallback(18), display_fallback)]
+    /// Specify user age
+    age: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +
+$ app --help
+

Usage: app -n=NAME [--age=AGE]

+Available options:
-n, --name=NAME
+
Specify user name
+
--age=AGE
+
Specify user age
+
+
[default: 18]
+
-h, --help
+
Prints help information
+
+

+ +
+

--help shows arguments as a short name with attached metavariable

+

Value can be separated from flag by space, = sign

+
+$ app --name Bob --age 12
+Options { name: "Bob", age: 12 } +
+
+$ app --name "Bob" --age=12
+Options { name: "Bob", age: 12 } +
+
+$ app --name=Bob
+Options { name: "Bob", age: 18 } +
+
+$ app --name="Bob"
+Options { name: "Bob", age: 18 } +
+

Or in case of short name - be directly adjacent to it

+
+$ app -nBob
+Options { name: "Bob", age: 18 } +
+

For long names - this doesn’t work since parser can’t tell where name +stops and argument begins:

+
+$ app --age12
+Error: no such flag: --age12, did you mean --age? + +
+

Either way - value is required, passing just the argument name results in parse failure

+
+$ app --name
+Error: --name requires an argument NAME + +
+
+

For more detailed info see NamedArg::argument

+

 

+ + + + +
+

← Options, switches or flags

+
+

↑ Types of arguments ↑

+
+

Operands or positional items →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_1_argument/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_1_argument/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_1_argument/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_2_positional/index.html b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_2_positional/index.html new file mode 100644 index 00000000..9f479935 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_2_positional/index.html @@ -0,0 +1,190 @@ +bpaf::_documentation::_1_tutorials::_0_types_of_arguments::_2_positional - Rust +
Expand description

 

+ + + + +
+

← Option arguments or arguments

+
+

↑ Types of arguments ↑

+
+

Commands or subcommands →

+
+
§Operands or positional items
+

Operands are usually items that are present on a command line and not prefixed by a short or +long name. They are usually used to represent the most important part of the operation: +cat Cargo.toml - display THIS file, rm -rf target - remove THIS folder and so on.

+
+
+$ cat /etc/passwd
+$ rm -rf target
+$ man gcc
+
+
+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    crate_name: String,
+    feature_name: Option<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help("Display detailed information")
+        .switch();
+
+    let crate_name = positional("CRATE").help("Crate name to use");
+
+    let feature_name = positional("FEATURE")
+        .help("Display information about this feature")
+        .optional();
+
+    construct!(Options {
+        verbose,
+        // You must place positional items and commands after
+        // all other parsers
+        crate_name,
+        feature_name
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Display detailed information
+    #[bpaf(short, long)]
+    verbose: bool,
+
+    // You must place positional items and commands after
+    // all other parsers
+    #[bpaf(positional("CRATE"))]
+    /// Crate name to use
+    crate_name: String,
+
+    #[bpaf(positional("FEATURE"))]
+    /// Display information about this feature
+    feature_name: Option<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Positional items show up in a separate group of arguments if they contain a help message, +otherwise they will show up only in Usage part.

+
+$ app --help
+

Usage: app [-v] CRATE [FEATURE]

+Available positional items:
CRATE
+
Crate name to use
+
FEATURE
+
Display information about this feature
+
+

+Available options:
-v, --verbose
+
Display detailed information
+
-h, --help
+
Prints help information
+
+

+ +
+

You can mix positional items with regular items

+
+$ app --verbose bpaf
+Options { verbose: true, crate_name: "bpaf", feature_name: None } +
+

And since bpaf API expects to have non positional items consumed before positional ones - you +can use them in a different order. In this example bpaf corresponds to a crate_name field and +--verbose – to verbose.

+
+$ app bpaf --verbose
+Options { verbose: true, crate_name: "bpaf", feature_name: None } +
+

In previous examples optional field feature was missing, this one contains it.

+
+$ app bpaf autocomplete
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("autocomplete") } +
+

Users can use -- to tell bpaf to treat remaining items as positionals - this might be +required to handle unusual items.

+
+$ app bpaf -- --verbose
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("--verbose") } +
+
+$ app -- bpaf --verbose
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("--verbose") } +
+

Without using -- bpaf would only accept items that don’t start with - as positional.

+
+$ app --detailed
+Error: expected CRATE, got --detailed. Pass --help for usage information + +
+
+$ app --verbose
+Error: expected CRATE, pass --help for usage information + +
+

You can use any to work around this restriction.

+
+

For more detailed info see positional and

+

 

+ + + + +
+

← Option arguments or arguments

+
+

↑ Types of arguments ↑

+
+

Commands or subcommands →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_2_positional/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_2_positional/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_2_positional/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_3_command/index.html b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_3_command/index.html new file mode 100644 index 00000000..ce6cf329 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_3_command/index.html @@ -0,0 +1,181 @@ +bpaf::_documentation::_1_tutorials::_0_types_of_arguments::_3_command - Rust +
Expand description

 

+ + + + +
+

← Operands or positional items

+
+

↑ Types of arguments ↑

+
+

Exotic schemas →

+
+
§Commands or subcommands
+

Commands are similar to positional items, but instead of representing an item they start +a whole new parser, usually with its help and other arguments. Commands allow a single +application to perform multiple different functions. The command parser will be able to parse all +the command line options to the right of the command name

+
+
+$ cargo build --release
+$ cargo clippy
+$ cargo asm --intel --everything
+
+
+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Cmd {
+    flag: bool,
+    arg: usize,
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    flag: bool,
+    cmd: Cmd,
+}
+
+fn cmd() -> impl Parser<Cmd> {
+    let flag = long("flag")
+        .help("This flag is specific to command")
+        .switch();
+    let arg = long("arg").argument::<usize>("ARG");
+    construct!(Cmd { flag, arg })
+        .to_options()
+        .descr("Command to do something")
+        .command("cmd")
+        // you can chain add extra short and long names
+        .short('c')
+}
+
+pub fn options() -> OptionParser<Options> {
+    let flag = long("flag")
+        .help("This flag is specific to the outer layer")
+        .switch();
+    construct!(Options { flag, cmd() }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+// `command` annotation with no name gets the name from the object it is attached to,
+// but you can override it using something like #[bpaf(command("my_command"))]
+// you can chain more short and long names here to serve as aliases
+#[bpaf(command("cmd"), short('c'))]
+/// Command to do something
+pub struct Cmd {
+    /// This flag is specific to command
+    flag: bool,
+    arg: usize,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// This flag is specific to the outer layer
+    flag: bool,
+    #[bpaf(external)]
+    cmd: Cmd,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Commands show up on both outer level help

+
+$ app --help
+

Usage: app [--flag] COMMAND ...

+Available options:
--flag
+
This flag is specific to the outer layer
+
-h, --help
+
Prints help information
+
+

+Available commands:
cmd, c
+
Command to do something
+
+

+ +
+

As well as showing their own help

+
+$ app cmd --help
+

Command to do something

Usage: app cmd [--flag] --arg=ARG

+Available options:
--flag
+
This flag is specific to command
+
--arg=ARG
+
-h, --help
+
Prints help information
+
+

+ +
+

In this example there’s only one command and it is required, so is the argument inside of it

+
+$ app cmd --arg 42
+Options { flag: false, cmd: Cmd { flag: false, arg: 42 } } +
+

If you don’t specify this command - parsing will fail

+

You can have the same flag names inside and outside of the command, but it might be confusing +for the end user. This example enables the outer flag

+
+$ app --flag cmd --arg 42
+Options { flag: true, cmd: Cmd { flag: false, arg: 42 } } +
+

And this one - both inside and outside

+
+$ app --flag cmd --arg 42 --flag
+Options { flag: true, cmd: Cmd { flag: true, arg: 42 } } +
+

And that’s the confusing part - unless you add context restrictions with +adjacent and parse command first - outer flag wins. +So it’s best not to mix names on different levels

+
+$ app cmd --arg 42 --flag
+Options { flag: true, cmd: Cmd { flag: false, arg: 42 } } +
+
+

For more detailed info see OptionParser::command

+

 

+ + + + +
+

← Operands or positional items

+
+

↑ Types of arguments ↑

+
+

Exotic schemas →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_3_command/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_3_command/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_3_command/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_4_exotic/index.html b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_4_exotic/index.html new file mode 100644 index 00000000..fec068ed --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_4_exotic/index.html @@ -0,0 +1,52 @@ +bpaf::_documentation::_1_tutorials::_0_types_of_arguments::_4_exotic - Rust +
Expand description

 

+ + + + +
+

← Commands or subcommands

+
+

↑ Types of arguments ↑

+
+
+
§Exotic schemas
+

While modern software tends to use just the options listed above you can still encounter +programs created before those options became the norm and they use something completely different, +let me give a few examples, see the parsing cookbook +about actually parsing them

+

su takes an option that consists of a single dash -

+
+$ su -
+
+

find considers everything between --exec and ; to be a single item. +this example calls ls -l on every file find finds.

+
+$ find /etc --exec ls -l '{}' \;
+
+

Xorg and related tools use flag-like items that start with a single + to enable a +feature and with - to disable it.

+
+$ xorg -backing +xinerama
+
+

dd takes several key-value pairs, this would create a 100M file

+
+$ dd if=/dev/zero of=dummy.bin bs=1M count=100
+
+

Most of the command line arguments in Turbo C++ 3.0 start with /. For example, option +/x tells it to use all available extended memory, while /x[=n] limits it to n kilobytes

+
+C:\PROJECT>TC /x=200
+
+

 

+ + + + +
+

← Commands or subcommands

+
+

↑ Types of arguments ↑

+
+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_4_exotic/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_4_exotic/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/_4_exotic/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/index.html b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/index.html new file mode 100644 index 00000000..fc184572 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/index.html @@ -0,0 +1,47 @@ +bpaf::_documentation::_1_tutorials::_0_types_of_arguments - Rust +
Expand description

 

+ + + + +
+ +

↑ Tutorials ↑

+
+

Combinatoric API →

+
+
§Types of arguments
+

common types of line options and conventions

+

This chapter serves as an introduction to available command line options and tries to set the +terminology. If you are familiar with command line argument parsers in general - feel free to +skip it.

+

If you ever used any software from a command line (say cargo) you used command line options. +Let’s recap how you might run tests for a crate in your rust project:

+
+
+$ cargo test -p my_project --verbose
+
+
+

cargo here is an executable name, everything to the right of it separated by spaces are the +options.

+

Nowadays programs share mostly similar conventions about what a command line argument is, it +wasn’t the case before though. Let’s cover the basic types.

+ +

 

+ + + + +
+ +

↑ Tutorials ↑

+
+

Combinatoric API →

+
+

Modules§

\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/sidebar-items.js new file mode 100644 index 00000000..db5815e5 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_0_types_of_arguments/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["_0_switch","_1_argument","_2_positional","_3_command","_4_exotic"]}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_0_switch/index.html b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_0_switch/index.html new file mode 100644 index 00000000..be4224cc --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_0_switch/index.html @@ -0,0 +1,93 @@ +bpaf::_documentation::_1_tutorials::_1_combinatoric_api::_0_simple_parser::_0_switch - Rust +
Expand description

 

+ + + + +
+ +

↑ Making a simple parser ↑

+
+

Argument parser →

+
+
§Switch parser
+

Let’s start with the simplest possible one - a simple switch that gets parsed into a bool.

+

First of all - the switch needs a name - you can start with short or long and add more +names if you want: long("simple") or short('s').long("simple"). This gives something with +the type NamedArg:

+ +
use bpaf::parsers::NamedArg;
+fn simple_switch() -> NamedArg {
+    short('s').long("simple")
+}
+

From NamedArg you make a switch parser by calling NamedArg::switch. Usually, you do it +right away without assigning NamedArg to a variable.

+ +
fn simple_switch() -> impl Parser<bool> {
+    short('s').long("simple").switch()
+}
+

The switch parser we just made implements trait Parser and to run it you convert it to OptionParser with +Parser::to_options and run it with OptionParser::run

+

Full example with some sample inputs and outputs:

+ +
use bpaf::*;
+
+pub fn options() -> OptionParser<bool> {
+    let simple = short('s').long("simple").switch();
+    simple.to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

If you run the app with no parameters - switch will parse as false

+
+$ app
+false +
+

Both short and long names produce true

+
+$ app -s
+true +
+
+$ app --simple
+true +
+

In addition to the switch you defined bpaf generates switch for user help

+
+$ app --help
+

Usage: app [-s]

+Available options:
-s, --simple
+
-h, --help
+
Prints help information
+
+

+ +
+
+

With NamedArg::help you can attach a help message that will be used in --help output.

+

 

+ + + + +
+ +

↑ Making a simple parser ↑

+
+

Argument parser →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_0_switch/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_0_switch/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_0_switch/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_1_argument/index.html b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_1_argument/index.html new file mode 100644 index 00000000..9129a618 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_1_argument/index.html @@ -0,0 +1,144 @@ +bpaf::_documentation::_1_tutorials::_1_combinatoric_api::_0_simple_parser::_1_argument - Rust +
Expand description

 

+ + + + +
+

← Switch parser

+
+

↑ Making a simple parser ↑

+
+

Positional item parser →

+
+
§Argument parser
+

Next in complexity would be a parser to consume a named argument, such as -p my_crate. Same +as with the switch parser it starts from a NamedArg but the next method is NamedArg::argument. +This method takes a metavariable name - a short description that will be used in the --help +output. rustc also needs to know the parameter type you are trying to parse, there are +several ways to do it:

+ +
fn simple_argument_1() -> impl Parser<u32> {
+    // rustc figures out the type from returned value
+    long("number").argument("NUM")
+}
+ 
+fn simple_argument_2() -> impl Parser<String> {
+    // type is specified explicitly with turbofish
+    long("name").argument::<String>("NAME")
+}
+ 
+fn file_parser() -> OptionParser<PathBuf> {
+    // OptionParser is a type for finalized parser, at this point you can
+    // start adding extra information to the `--help` message
+    long("file").argument::<PathBuf>("FILE").to_options()
+}
+

You can use any type for as long as it implements FromStr. To parse items that don’t +implement it you can first parse a String or OsString and then use Parser::parse, see +the next chapter on how to do that.

+

Full example with some sample inputs and outputs:

+ +
use bpaf::*;
+
+pub fn options() -> OptionParser<usize> {
+    short('s')
+        .long("size")
+        .help("Defines size of an object")
+        .argument::<usize>("SIZE")
+        .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

By default all arguments are required so running with no arguments produces an error

+
+$ app
+Error: expected --size=SIZE, pass --help for usage information + +
+

Bpaf accepts various combinations of names and adjacencies:

+
+$ app -s100
+100 +
+
+$ app --size 300
+300 +
+
+$ app -s=42
+42 +
+
+$ app --size=14
+14 +
+

Since not every string is a valid number - bpaf would report any parsing failures to the user +directly

+
+$ app --size fifty
+Error: couldn't parse fifty: invalid digit found in string + +
+

In addition to the switch you defined bpaf generates switch for user help which will include +the description from the help method

+
+$ app --help
+

Usage: app -s=SIZE

+Available options:
-s, --size=SIZE
+
Defines size of an object
+
-h, --help
+
Prints help information
+
+

+ +
+
+

 

+ + + + +
+

← Switch parser

+
+

↑ Making a simple parser ↑

+
+

Positional item parser →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_1_argument/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_1_argument/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_1_argument/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_2_positional/index.html b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_2_positional/index.html new file mode 100644 index 00000000..92e22585 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_2_positional/index.html @@ -0,0 +1,99 @@ +bpaf::_documentation::_1_tutorials::_1_combinatoric_api::_0_simple_parser::_2_positional - Rust +
Expand description

 

+ + + + +
+

← Argument parser

+
+

↑ Making a simple parser ↑

+
+
+
§Positional item parser
+

And the last simple option type is a parser for positional items. Since there’s no name you use +the positional function directly. Similar to NamedArg::argument this method takes +a metavariable name and a type parameter in some form. You can also attach the help message +thanks to ParsePositional::help

+

Full example:

+ +
use bpaf::*;
+
+pub fn options() -> OptionParser<String> {
+    let simple = positional("URL").help("Url to open");
+    simple.to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

Same as with argument by default there’s no fallback so with no arguments parser fails

+
+$ app
+Error: expected URL, pass --help for usage information + +
+

Other than that any name that does not start with a dash or explicitly converted to positional +parameter gets parsed:

+
+$ app https://lemmyrs.org
+"https://lemmyrs.org" +
+
+$ app "strange url"
+"strange url" +
+
+$ app -- --can-start-with-dash-too
+"--can-start-with-dash-too" +
+

And as usual there’s help message

+
+$ app --help
+

Usage: app URL

+Available positional items:
URL
+
Url to open
+
+

+Available options:
-h, --help
+
Prints help information
+
+

+ +
+
+

 

+ + + + +
+

← Argument parser

+
+

↑ Making a simple parser ↑

+
+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_2_positional/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_2_positional/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_2_positional/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/index.html b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/index.html new file mode 100644 index 00000000..663668ed --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/index.html @@ -0,0 +1,31 @@ +bpaf::_documentation::_1_tutorials::_1_combinatoric_api::_0_simple_parser - Rust +
Expand description

 

+ + + + +
+ +

↑ Combinatoric API ↑

+
+

Transforming parsers →

+
+
§Making a simple parser
+

In this chapter we’ll go over making a few simple parsers.

+ +

 

+ + + + +
+ +

↑ Combinatoric API ↑

+
+

Transforming parsers →

+
+

Modules§

\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/sidebar-items.js new file mode 100644 index 00000000..14763b59 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["_0_switch","_1_argument","_2_positional"]}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_1_chaining/index.html b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_1_chaining/index.html new file mode 100644 index 00000000..0b2a215a --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_1_chaining/index.html @@ -0,0 +1,152 @@ +bpaf::_documentation::_1_tutorials::_1_combinatoric_api::_1_chaining - Rust +
Expand description

 

+ + + + +
+

← Making a simple parser

+
+

↑ Combinatoric API ↑

+
+

Combining multiple simple parsers →

+
+
§Transforming parsers
+

Once you have your primitive parsers done you might want to improve them a bit - add fallback +values, or change them to consume multiple items, etc. Every primitive (or composite) parser +implements Parser so most of the transformations are coming from this trait.

+

Say you have a parser that takes a crate name as a required argument you want to use in your own +cargo test replacement

+ +
use bpaf::*;
+fn krate() -> impl Parser<String> {
+    long("crate").help("Crate name to process").argument("CRATE")
+}
+

You can turn it into, for example, an optional argument - something that returns +Some("my_crate") if specified or None if it wasn’t. Or to let the user to pass a multiple +of them and collect them all into a Vec

+ +
use bpaf::*;
+fn maybe_krate() -> impl Parser<Option<String>> {
+    long("crate")
+        .help("Crate name to process")
+        .argument("CRATE")
+        .optional()
+}
+ 
+fn krates() -> impl Parser<Vec<String>> {
+    long("crate")
+        .help("Crate name to process")
+        .argument("CRATE")
+        .many()
+}
+

A complete example:

+ +
use bpaf::*;
+
+pub fn options() -> OptionParser<Vec<u32>> {
+    let argument = long("argument")
+        .help("important argument")
+        .argument("ARG")
+        .many();
+    argument.to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

Run inner parser as many times as possible collecting all the new results +First false is collected from a switch even if it is not consuming anything

+
+$ app --argument 10 --argument 20
+[10, 20] +
+

If there’s no matching parameters - it would produce an empty vector.

+
+$ app
+[] +
+

In usage lines many items are indicated with ...

+
+$ app --help
+

Usage: app [--argument=ARG]...

+Available options:
--argument=ARG
+
important argument
+
-h, --help
+
Prints help information
+
+

+ +
+
+

Transforming a parser with a method from the Parser trait usually gives you a new parser back and +you can chain as many transformations as you need.

+

Transformations available in the Parser trait things like adding fallback values, making +the parser optional, making it so it consumes many but at least one value, changing how it is +being shown in --help output, adding additional validation and parsing on top and so on.

+

The order of those chained transformations matters and for some operations using the right order +makes code cleaner. For example, suppose you are trying to write a parser that takes an even +number and this parser should be optional. There are two ways to write it:

+

Validation first:

+ +
fn even() -> impl Parser<Option<usize>> {
+    long("even")
+        .argument("N")
+        .guard(|&n| n % 2 == 0, "number must be even")
+        .optional()
+}
+

Optional first:

+ +
fn even() -> impl Parser<Option<usize>> {
+    long("even")
+        .argument("N")
+        .optional()
+        .guard(|&n| n.map_or(true, |n| n % 2 == 0), "number must be even")
+}
+

In later case validation function must deal with a possibility where a number is absent, for this +specific example it makes code less readable.

+

One of the important types of transformations you can apply is a set of failing +transformations. Suppose your application operates with numbers and uses newtype pattern to +keep track of what numbers are odd or even. A parser that consumes an even number can use +Parser::parse and may look like this:

+ +
pub struct Even(usize);
+ 
+fn mk_even(n: usize) -> Result<Even, &'static str> {
+    if n % 2 == 0 {
+        Ok(Even(n))
+    } else {
+        Err("Not an even number")
+    }
+}
+ 
+fn even() -> impl Parser<Even> {
+    long("even")
+        .argument::<usize>("N")
+        .parse(mk_even)
+}
+

 

+ + + + +
+

← Making a simple parser

+
+

↑ Combinatoric API ↑

+
+

Combining multiple simple parsers →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_1_chaining/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_1_chaining/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_1_chaining/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_2_combining/index.html b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_2_combining/index.html new file mode 100644 index 00000000..7690446c --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_2_combining/index.html @@ -0,0 +1,217 @@ +bpaf::_documentation::_1_tutorials::_1_combinatoric_api::_2_combining - Rust +
Expand description

 

+ + + + +
+

← Transforming parsers

+
+

↑ Combinatoric API ↑

+
+

Subcommand parsers →

+
+
§Combining multiple simple parsers
+

A single-item option parser can only get you so far. Fortunately, you can combine multiple +parsers with construct! macro.

+

For sequential composition (all the fields must be present) you write your code as if you are +constructing a structure, enum variant or a tuple and wrap it with construct!. Both +a constructor and parsers must be present in the scope. If instead of a parser you have a function +that creates one - just add () after the name:

+ +
struct Options {
+    alpha: usize,
+    beta: usize
+}
+ 
+fn alpha() -> impl Parser<usize> {
+    long("alpha").argument("ALPHA")
+}
+ 
+fn both() -> impl Parser<Options> {
+    let beta = long("beta").argument("BETA");
+    // call `alpha` function, and use result to make parser
+    // for field `alpha`, use parser `beta` for field `beta`
+    construct!(Options { alpha(), beta })
+}
+

Full example:

+ +
use bpaf::*;
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    argument: Vec<u32>,
+    switches: Vec<bool>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = long("argument")
+        .help("important argument")
+        .argument("ARG")
+        .many();
+    let switches = long("switch").help("some switch").switch().many();
+    construct!(Options { argument, switches }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

Help message describes all the parser combined

+
+$ app --help
+

Usage: app [--argument=ARG]... [--switch]...

+Available options:
--argument=ARG
+
important argument
+
--switch
+
some switch
+
-h, --help
+
Prints help information
+
+

+ +
+

And users can pass any combinations of options, resulting parser will handle them as long as they are valid

+
+$ app --argument 10 --argument 20
+Options { argument: [10, 20], switches: [false] } +
+
+$ app --switch
+Options { argument: [], switches: [true] } +
+
+$ app --switch --switch --argument 20
+Options { argument: [20], switches: [true, true] } +
+
+

If you are using positional parsers - they must go to the right-most side and will run in +the order you specify them. For named parsers order affects only the --help message.

+

The second type of composition construct! offers is a parallel composition. You pass multiple +parsers that produce the same result type in [] and bpaf selects one that fits best with +the data user gave.

+ +
use bpaf::*;
+
+pub fn options() -> OptionParser<f64> {
+    let miles = long("miles").help("Distance in miles").argument("MI");
+    let km = long("kilo").help("Distance in kilometers").argument("KM");
+    construct!([miles, km]).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

Help message describes all the parser combined

+
+$ app --help
+

Usage: app (--miles=MI | --kilo=KM)

+Available options:
--miles=MI
+
Distance in miles
+
--kilo=KM
+
Distance in kilometers
+
-h, --help
+
Prints help information
+
+

+ +
+

Users can pass value that satisfy either parser

+
+$ app --miles 42
+42.0 +
+
+$ app --kilo 15
+15.0 +
+

But not both at once or not at all:

+
+$ app --miles 53 --kilo 10
+Error: --kilo cannot be used at the same time as --miles + +
+
+$ app
+Error: expected --miles=MI or --kilo=KM, pass --help for usage information + +
+

If those cases are valid you can handle them with optional and many

+
+

If parsers inside parallel composition can parse the same object - the longest possible match +should go first since bpaf picks an earlier parser if everything else is equal, otherwise it +does not matter. In this example construct!([miles, km]) produces the same results as +construct!([km, miles]) and only --help message is going to be different.

+

Parsers created with construct! still implement the Parser trait so you can apply more +transformation on top. For example same as you can make a simple parser optional - you can make +a composite parser optional. Parser transformed this way will succeed if both --alpha and +--beta are present or neither of them:

+ +
struct Options {
+    alpha: usize,
+    beta: usize
+}
+ 
+fn parser() -> impl Parser<Option<Options>> {
+    let alpha = long("alpha").argument("ALPHA");
+    let beta = long("beta").argument("BETA");
+    construct!(Options { alpha, beta }).optional()
+}
+

 

+ + + + +
+

← Transforming parsers

+
+

↑ Combinatoric API ↑

+
+

Subcommand parsers →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_2_combining/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_2_combining/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_2_combining/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_3_subcommands/index.html b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_3_subcommands/index.html new file mode 100644 index 00000000..1a4ed835 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_3_subcommands/index.html @@ -0,0 +1,149 @@ +bpaf::_documentation::_1_tutorials::_1_combinatoric_api::_3_subcommands - Rust +
Expand description

 

+ + + + +
+

← Combining multiple simple parsers

+
+

↑ Combinatoric API ↑

+
+

Improving the user experience →

+
+
§Subcommand parsers
+

To make a parser for a subcommand you make an OptionParser for that subcommand first as if it +was the only thing your application would parse then turn it into a regular Parser +you can further compose with OptionParser::command.

+

This gives ParseCommand back, you can add aliases or tweak the help message if you want to.

+ +
#[derive(Debug, Clone)]
+pub enum Options {
+    /// Run a binary
+    Run {
+        /// Name of a binary to run
+        bin: String,
+
+        /// Arguments to pass to a binary
+        args: Vec<String>,
+    },
+    /// Compile a binary
+    Build {
+        /// Name of a binary to build
+        bin: String,
+
+        /// Compile the binary in release mode
+        release: bool,
+    },
+}
+
+// combine mode gives more flexibility to share the same code across multiple parsers
+fn run() -> impl Parser<Options> {
+    let bin = long("bin").help("Name of a binary to run").argument("BIN");
+    let args = positional("ARG")
+        .strict()
+        .help("Arguments to pass to a binary")
+        .many();
+
+    construct!(Options::Run { bin, args })
+}
+
+pub fn options() -> OptionParser<Options> {
+    let run = run().to_options().descr("Run a binary").command("run");
+
+    let bin = long("bin")
+        .help("Name of a binary to build ")
+        .argument("BIN");
+    let release = long("release")
+        .help("Compile the binary in release mode")
+        .switch();
+    let build = construct!(Options::Build { bin, release })
+        .to_options()
+        .descr("Compile a binary")
+        .command("build");
+
+    construct!([run, build]).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

Help contains both commands, bpaf takes short command description from the inner command +description

+
+$ app --help
+

Usage: app COMMAND ...

+Available options:
-h, --help
+
Prints help information
+
+

+Available commands:
run
+
Run a binary
+
build
+
Compile a binary
+
+

+ +
+

Same as before each command gets its own help message

+
+$ app run --help
+

Run a binary

Usage: app run --bin=BIN -- [ARG]...

+Available positional items:
ARG
+
Arguments to pass to a binary
+
+

+Available options:
--bin=BIN
+
Name of a binary to run
+
-h, --help
+
Prints help information
+
+

+ +
+

And can be executed separately

+
+$ app run --bin basic
+Run { bin: "basic", args: [] } +
+
+$ app build --bin demo --release
+Build { bin: "demo", release: true } +
+
+

 

+ + + + +
+

← Combining multiple simple parsers

+
+

↑ Combinatoric API ↑

+
+

Improving the user experience →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_3_subcommands/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_3_subcommands/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_3_subcommands/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_4_decorating/index.html b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_4_decorating/index.html new file mode 100644 index 00000000..2a619171 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_4_decorating/index.html @@ -0,0 +1,125 @@ +bpaf::_documentation::_1_tutorials::_1_combinatoric_api::_4_decorating - Rust +
Expand description

 

+ + + + +
+

← Subcommand parsers

+
+

↑ Combinatoric API ↑

+
+
+
§Improving the user experience
+

Once you have the final parser done there are still a few ways you can improve user experience. +OptionParser comes equipped with a few methods that let you set version number, +description, help message header and footer and so on.

+ +
#[derive(Debug, Clone)]
+pub struct Options {
+    argument: u32,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = short('i').argument::<u32>("ARG");
+    construct!(Options { argument })
+        .to_options()
+        .version("3.1415")
+        .descr("This is a short description")
+        .header("It can contain multiple blocks, this block goes before options")
+        .footer("This one goes after")
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

In addition to all the arguments specified by user bpaf adds a few more. One of them is +--help:

+
+$ app --help
+

This is a short description

Usage: app -i=ARG

It can contain multiple blocks, this block goes before options

+Available options:
-i=ARG
+
-h, --help
+
Prints help information
+
-V, --version
+
Prints version information
+
+

This one goes after

+ +
+

The other one is --version - passing a string literal or something like +env!("CARGO_PKG_VERSION") to get version from cargo directly usually works

+
+$ app --version
+

Version: 3.1415

+ +
+

Other than that bpaf tries its best to provide a helpful error messages

+
+$ app
+Error: expected -i=ARG, pass --help for usage information + +
+

And if all parsers are satisfied run produces the result

+
+$ app -i 10
+Options { argument: 10 } +
+
+

There are a few other things you can do:

+ +

 

+ + + + +
+

← Subcommand parsers

+
+

↑ Combinatoric API ↑

+
+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_4_decorating/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_4_decorating/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/_4_decorating/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/index.html b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/index.html new file mode 100644 index 00000000..21795f8f --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/index.html @@ -0,0 +1,44 @@ +bpaf::_documentation::_1_tutorials::_1_combinatoric_api - Rust +
Expand description

 

+ + + + +
+

← Types of arguments

+
+

↑ Tutorials ↑

+
+

Derive API tutorial →

+
+
§Combinatoric API
+

Parse arguments without using proc macros

+

When making a parser in the Combinatoric style API you usually go through those steps

+
    +
  1. Design data type your application will receive
  2. +
  3. Design command line options user will have to pass
  4. +
  5. Create a set of simple parsers
  6. +
  7. Combine and transform simple parsers to create the final data type
  8. +
  9. Transform the resulting Parser into OptionParser and run it
  10. +
+

Let’s go through some of them in more detail:

+ +

 

+ + + + +
+

← Types of arguments

+
+

↑ Tutorials ↑

+
+

Derive API tutorial →

+
+

Modules§

\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/sidebar-items.js new file mode 100644 index 00000000..a18aeb63 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_1_combinatoric_api/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["_0_simple_parser","_1_chaining","_2_combining","_3_subcommands","_4_decorating"]}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_0_intro/index.html b/bpaf/_documentation/_1_tutorials/_2_derive_api/_0_intro/index.html new file mode 100644 index 00000000..cb4d510a --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_0_intro/index.html @@ -0,0 +1,98 @@ +bpaf::_documentation::_1_tutorials::_2_derive_api::_0_intro - Rust +
Expand description

 

+ + + + +
+ +

↑ Derive API tutorial ↑

+
+

Customizing flag and argument names →

+
+
§Getting started with derive macro
+

Let’s take a look at a simple example

+ +
use bpaf::*;
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// A custom switch
+    switch: bool,
+
+    /// A custom argument
+    argument: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

bpaf generates a help message

+
+$ app --help
+

Usage: app [--switch] --argument=ARG

+Available options:
--switch
+
A custom switch
+
--argument=ARG
+
A custom argument
+
-h, --help
+
Prints help information
+
+

+ +
+

And two parsers. Numeric argument is required, boolean switch is optional and fall back value +is false.

+
+$ app --switch
+Error: expected --argument=ARG, pass --help for usage information + +
+
+$ app --switch --argument 42
+Options { switch: true, argument: 42 } +
+
+$ app --argument 42
+Options { switch: false, argument: 42 } +
+
+

bpaf is trying hard to guess what you are trying to achieve just from the types so it will +pick up types, doc comments, presence or absence of names, but it is possible to customize all +of it, add custom transformations, validations and more.

+

 

+ + + + +
+ +

↑ Derive API tutorial ↑

+
+

Customizing flag and argument names →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_0_intro/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_2_derive_api/_0_intro/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_0_intro/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_1_custom_names/index.html b/bpaf/_documentation/_1_tutorials/_2_derive_api/_1_custom_names/index.html new file mode 100644 index 00000000..b746394a --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_1_custom_names/index.html @@ -0,0 +1,104 @@ +bpaf::_documentation::_1_tutorials::_2_derive_api::_1_custom_names - Rust +
Expand description

 

+ + + + +
+

← Getting started with derive macro

+
+

↑ Derive API tutorial ↑

+
+

Customizing the consumers →

+
+
§Customizing flag and argument names
+

By default names for flag names are taken directly from the field names so usually you don’t +have to do anything about it, but you can change it with annotations on the fields themselves:

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// A custom switch
+    #[bpaf(short, long)]
+    switch: bool,
+
+    /// A custom argument
+    #[bpaf(long("my-argument"), short('A'))]
+    argument: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

bpaf uses custom names in help message

+
+$ app --help
+

Usage: app [-s] -A=ARG

+Available options:
-s, --switch
+
A custom switch
+
-A, --my-argument=ARG
+
A custom argument
+
-h, --help
+
Prints help information
+
+

+ +
+

As well as accepts them on a command line and uses in error message

+
+$ app --switch
+Error: expected --my-argument=ARG, pass --help for usage information + +
+
+$ app -A 42 -s
+Options { switch: true, argument: 42 } +
+
+

Rules for picking the name are:

+
    +
  1. With no annotations field name longer than a single character becomes a long name, +single character name becomes a short name
  2. +
  3. Adding either long or short disables item 1, so adding short disables the long name
  4. +
  5. long or short annotation without a parameter derives a value from a field name
  6. +
  7. long or short with a parameter uses that instead
  8. +
  9. You can have multiple long and short annotations, the first of each type becomes a +visible name, remaining are used as hidden aliases
  10. +
+

And if you decide to add names - they should go to the left side of the annotation list

+

 

+ + + + +
+

← Getting started with derive macro

+
+

↑ Derive API tutorial ↑

+
+

Customizing the consumers →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_1_custom_names/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_2_derive_api/_1_custom_names/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_1_custom_names/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_2_custom_consumers/index.html b/bpaf/_documentation/_1_tutorials/_2_derive_api/_2_custom_consumers/index.html new file mode 100644 index 00000000..33426925 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_2_custom_consumers/index.html @@ -0,0 +1,120 @@ +bpaf::_documentation::_1_tutorials::_2_derive_api::_2_custom_consumers - Rust +
Expand description

 

+ + + + +
+

← Customizing flag and argument names

+
+

↑ Derive API tutorial ↑

+
+

Transforming parsed values →

+
+
§Customizing the consumers
+

By default, bpaf picks parsers depending on a field type according to those rules:

+
    +
  1. bool fields are converted into switches: NamedArg::switch
  2. +
  3. () (unit) fields, unit variants of an enum or unit structs themselves are handled as +NamedArg::req_flag and thus users must always specify +them for the parser to succeed
  4. +
  5. All other types with no Vec/Option are parsed using FromStr, but +smartly, so non-utf8 PathBuf/OsString are working as expected.
  6. +
  7. For values wrapped in Option or Vec bpaf derives the inner parser and then applies +applies logic from Parser::optional and Parser::many respectively.
  8. +
+

You can change it with annotations like switch, argument or positional

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// A custom switch
+    #[bpaf(short, switch)]
+    switch: bool,
+
+    /// Custom number
+    #[bpaf(positional("NUM"))]
+    argument: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

bpaf generates help message with a short name only as described

+
+$ app --help
+

Usage: app [-s] NUM

+Available positional items:
NUM
+
Custom number
+
+

+Available options:
-s
+
A custom switch
+
-h, --help
+
Prints help information
+
+

+ +
+

And accepts the short name only

+
+$ app -s 42
+Options { switch: true, argument: 42 } +
+

long name is missing

+
+$ app --switch 42
+Error: --switch is not expected in this context + +
+
+

With arguments that consume a value you can specify its type using turbofish-line syntax

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// A custom argument
+    #[bpaf(positional::<usize>("LENGTH"))]
+    argument: usize,
+}
+ 
+fn main() {
+    let opts = options().run();
+    println!("{:?}", opts)
+}
+

 

+ + + + +
+

← Customizing flag and argument names

+
+

↑ Derive API tutorial ↑

+
+

Transforming parsed values →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_2_custom_consumers/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_2_derive_api/_2_custom_consumers/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_2_custom_consumers/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_3_postpr/index.html b/bpaf/_documentation/_1_tutorials/_2_derive_api/_3_postpr/index.html new file mode 100644 index 00000000..3f9bce52 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_3_postpr/index.html @@ -0,0 +1,108 @@ +bpaf::_documentation::_1_tutorials::_2_derive_api::_3_postpr - Rust +
Expand description

 

+ + + + +
+

← Customizing the consumers

+
+

↑ Derive API tutorial ↑

+
+

Parsing structs and enums →

+
+
§Transforming parsed values
+

Once the field has a consumer you can start applying transformations from the Parser trait. +Annotation share the same names and follow the same composition rules as in Combinatoric API.

+ +
fn small(size: &usize) -> bool {
+    *size < 10
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    // double the width
+    #[bpaf(short, argument::<usize>("PX"), map(|w| w*2))]
+    width: usize,
+
+    // make sure the hight is below 10
+    #[bpaf(argument::<usize>("LENGTH"), guard(small, "must be less than 10"))]
+    height: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

Help as usual

+
+$ app --help
+

Usage: app -w=PX --height=LENGTH

+Available options:
-w=PX
+
--height=LENGTH
+
-h, --help
+
Prints help information
+
+

+ +
+

And parsed values are differnt from what user passes

+
+$ app --width 10 --height 3
+Error: expected -w=PX, got --width. Pass --help for usage information + +
+

Additionally height cannot exceed 10

+
+$ app --width 555 --height 42
+Error: expected -w=PX, got --width. Pass --help for usage information + +
+
+

 

+ + + + +
+

← Customizing the consumers

+
+

↑ Derive API tutorial ↑

+
+

Parsing structs and enums →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_3_postpr/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_2_derive_api/_3_postpr/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_3_postpr/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_4_enums_and_structs/index.html b/bpaf/_documentation/_1_tutorials/_2_derive_api/_4_enums_and_structs/index.html new file mode 100644 index 00000000..c7c76df2 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_4_enums_and_structs/index.html @@ -0,0 +1,126 @@ +bpaf::_documentation::_1_tutorials::_2_derive_api::_4_enums_and_structs - Rust +
Expand description

 

+ + + + +
+

← Transforming parsed values

+
+

↑ Derive API tutorial ↑

+
+

What gets generated →

+
+
§Parsing structs and enums
+

To produce a struct bpaf needs for all the field parsers to succeed. If you are planning to use +it for some other purpose as well and want to skip them during parsing you can use pure to +fill in values in member fields and #[bpaf(skip)] on enum variants you want to ignore, see +combinatoric example in Parser::last.

+

If you use #[derive(Bpaf)] on an enum parser will produce a variant for which all the parsers +succeed.

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub enum Options {
+    File {
+        /// Read input from a file
+        name: String,
+    },
+
+    Url {
+        /// Read input from URL
+        url: String,
+        /// Authentication method to use for the URL
+        auth_method: String,
+    },
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

Help message reflects mutually exclusive parts

+
+$ app --help
+

Usage: app (--name=ARG | --url=ARG --auth-method=ARG)

+Available options:
--name=ARG
+
Read input from a file
+
--url=ARG
+
Read input from URL
+
--auth-method=ARG
+
Authentication method to use for the URL
+
-h, --help
+
Prints help information
+
+

+ +
+

At least one branch needs to succeed

+
+$ app
+Error: expected --name=ARG or --url=ARG, pass --help for usage information + +
+

And in this example only one branch can succeed

+
+$ app --name Cargo.toml
+File { name: "Cargo.toml" } +
+
+$ app --url https://crates.io --auth-method digest
+Url { url: "https://crates.io", auth_method: "digest" } +
+

While both branches can succeed at once - only one will actually succeed and afetr that +parsing fails since there are unconsumed items

+
+$ app --url https://crates.io --auth-method digest --name Cargo.toml
+Error: --name cannot be used at the same time as --url + +
+
+

 

+ + + + +
+

← Transforming parsed values

+
+

↑ Derive API tutorial ↑

+
+

What gets generated →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_4_enums_and_structs/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_2_derive_api/_4_enums_and_structs/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_4_enums_and_structs/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_5_generate/index.html b/bpaf/_documentation/_1_tutorials/_2_derive_api/_5_generate/index.html new file mode 100644 index 00000000..0a9bbd9c --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_5_generate/index.html @@ -0,0 +1,45 @@ +bpaf::_documentation::_1_tutorials::_2_derive_api::_5_generate - Rust +
Expand description

 

+ + + + +
+

← Parsing structs and enums

+
+

↑ Derive API tutorial ↑

+
+

Making nested parsers →

+
+
§What gets generated
+

Usually calling derive macro on a type generates code to derive a trait implementation for this +type. With bpaf it’s slightly different. It instead generates a function with a name that +depends on the name of the type and gives either a composable parser (Parser) or option parser +(OptionParser) back.

+

You can customize the function name with generate annotation at the top level:

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options, generate(my_options))]
+pub struct Options {
+    /// A simple switch
+    switch: bool
+}
+ 
+ 
+fn main() {
+    let opts = my_options().run();
+    println!("{:?}", opts);
+}
+

 

+ + + + +
+

← Parsing structs and enums

+
+

↑ Derive API tutorial ↑

+
+

Making nested parsers →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_5_generate/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_2_derive_api/_5_generate/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_5_generate/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_6_nesting/index.html b/bpaf/_documentation/_1_tutorials/_2_derive_api/_6_nesting/index.html new file mode 100644 index 00000000..b8e91353 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_6_nesting/index.html @@ -0,0 +1,131 @@ +bpaf::_documentation::_1_tutorials::_2_derive_api::_6_nesting - Rust +
Expand description

 

+ + + + +
+

← What gets generated

+
+

↑ Derive API tutorial ↑

+
+

Parsing subcommands →

+
+
§Making nested parsers
+

Up to this point, we’ve been looking at cases where fields of a structure are all simple +parsers, possibly wrapped in Option or Vec, but it is also possible to nest derived parsers +too:

+ +
#[derive(Debug, Clone, Bpaf)]
+pub enum Format {
+    /// Produce output in HTML format
+    Html,
+    /// Produce output in Markdown format
+    Markdown,
+    /// Produce output in manpage format
+    Manpage,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// File to process
+    input: String,
+    #[bpaf(external(format))]
+    format: Format,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

Help message lists all possible options

+
+$ app --help
+

Usage: app --input=ARG (--html | --markdown | --manpage)

+Available options:
--input=ARG
+
File to process
+
--html
+
Produce output in HTML format
+
--markdown
+
Produce output in Markdown format
+
--manpage
+
Produce output in manpage format
+
-h, --help
+
Prints help information
+
+

+ +
+

Parser accepts one and only one value from enum in this example

+
+$ app --input Cargo.toml --html
+Options { input: "Cargo.toml", format: Html } +
+
+$ app --input Cargo.toml --manpage
+Options { input: "Cargo.toml", format: Manpage } +
+
+$ app --input hello
+Error: expected --html, --markdown, or more, pass --help for usage information + +
+
+

external takes an optional function name and will call that function to make the parser for +the field. You can chain more transformations after the external and if the name is absent - +bpaf would use the field name instead, so you can also write the example above as

+ +
#[derive(Debug, Clone, Bpaf)]
+pub enum Format {
+    /// Produce output in HTML format
+    Html,
+    /// Produce output in Markdown format
+    Markdown,
+    /// Produce output in manpage format
+    Manpage,
+}
+ 
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// File to process
+    input: String,
+    #[bpaf(external)]
+    format: Format,
+}
+

 

+ + + + +
+

← What gets generated

+
+

↑ Derive API tutorial ↑

+
+

Parsing subcommands →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_6_nesting/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_2_derive_api/_6_nesting/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_6_nesting/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_7_commands/index.html b/bpaf/_documentation/_1_tutorials/_2_derive_api/_7_commands/index.html new file mode 100644 index 00000000..c776a4e2 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_7_commands/index.html @@ -0,0 +1,102 @@ +bpaf::_documentation::_1_tutorials::_2_derive_api::_7_commands - Rust +
Expand description

 

+ + + + +
+

← Making nested parsers

+
+

↑ Derive API tutorial ↑

+
+

Making a cargo command →

+
+
§Parsing subcommands
+

The easiest way to define a group of subcommands is to have them inside the same enum with variant +constructors annotated with #[bpaf(command("name"))] with or without the name

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub enum Options {
+    #[bpaf(command("run"))]
+    /// Run a binary
+    Run {
+        /// Name of a binary crate
+        name: String,
+    },
+
+    /// Run a self test
+    #[bpaf(command)]
+    Test,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

Help message lists subcommand

+
+$ app --help
+

Usage: app COMMAND ...

+Available options:
-h, --help
+
Prints help information
+
+

+Available commands:
run
+
Run a binary
+
test
+
Run a self test
+
+

+ +
+

Commands have their own arguments

+
+$ app run --name Bob
+Run { name: "Bob" } +
+
+$ app test
+Test +
+
+$ app test --name bob
+Error: --name is not expected in this context + +
+
+

 

+ + + + +
+

← Making nested parsers

+
+

↑ Derive API tutorial ↑

+
+

Making a cargo command →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_7_commands/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_2_derive_api/_7_commands/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_7_commands/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_8_cargo/index.html b/bpaf/_documentation/_1_tutorials/_2_derive_api/_8_cargo/index.html new file mode 100644 index 00000000..0efc71a8 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_8_cargo/index.html @@ -0,0 +1,41 @@ +bpaf::_documentation::_1_tutorials::_2_derive_api::_8_cargo - Rust +
Expand description

 

+ + + + +
+

← Parsing subcommands

+
+

↑ Derive API tutorial ↑

+
+
+
§Making a cargo command
+

To make a cargo command you should pass its name as a parameter to options. In this example, +bpaf will parse extra parameter cargo passes and you will be able to use it either directly +with cargo run from the repository, running it by cargo-asm name or with cargo asm name.

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options("asm"))]
+pub struct Options {
+    /// A simple switch
+    switch: bool
+}
+ 
+ 
+fn main() {
+    let opts = options().run();
+    println!("{:?}", opts);
+}
+

 

+ + + + +
+

← Parsing subcommands

+
+

↑ Derive API tutorial ↑

+
+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/_8_cargo/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_2_derive_api/_8_cargo/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/_8_cargo/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/index.html b/bpaf/_documentation/_1_tutorials/_2_derive_api/index.html new file mode 100644 index 00000000..582c77e4 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/index.html @@ -0,0 +1,49 @@ +bpaf::_documentation::_1_tutorials::_2_derive_api - Rust +
Expand description

 

+ + + + +
+

← Combinatoric API

+
+

↑ Tutorials ↑

+
+

Designing a good datatype →

+
+
§Derive API tutorial
+

Create a parser by defining a structure

+

When making a parser using Derive API you should go through approximately following steps:

+
    +
  1. Design data type your application will receive
  2. +
  3. Design command line options user will have to pass
  4. +
  5. Add #[derive(Bpaf, Debug, Clone)] on top of your type or types
  6. +
  7. Add #[bpaf(xxx)] annotations on types and fields
  8. +
  9. And #[bpaf(options)] to the top type
  10. +
  11. Run the resulting parser
  12. +
+

Let’s go through some of them in more detail:

+ +

 

+ + + + +
+

← Combinatoric API

+
+

↑ Tutorials ↑

+
+

Designing a good datatype →

+
+

Modules§

\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_2_derive_api/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_2_derive_api/sidebar-items.js new file mode 100644 index 00000000..4f9768dd --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_2_derive_api/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["_0_intro","_1_custom_names","_2_custom_consumers","_3_postpr","_4_enums_and_structs","_5_generate","_6_nesting","_7_commands","_8_cargo"]}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_3_picking_type/index.html b/bpaf/_documentation/_1_tutorials/_3_picking_type/index.html new file mode 100644 index 00000000..176cf5d2 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_3_picking_type/index.html @@ -0,0 +1,144 @@ +bpaf::_documentation::_1_tutorials::_3_picking_type - Rust +
Expand description

 

+ + + + +
+

← Derive API tutorial

+
+

↑ Tutorials ↑

+
+
+
§Designing a good datatype
+

bpaf allows you to reduce the size of legal values to valid ones

+

Parsing usually starts with deciding what kind of data your application wants to get from the user. +You should try to take advantage of the Rust type system, try to represent the result such that more +validation can be done during parsing.

+

Data types can represent a set of legal states - for example, for u8 this is all the numbers +from 0 to 255, while your app logic may only operate correctly only on some set of valid +states: if this u8 represents a fill ratio for something in percents - only valid numbers are +from 0 to 100. You can try to narrow down the set of legal states to valid states with newtype +pattern. This newtype will +indicate through the type when you’ve already done validation. For the fill ratio example you can +implement a newtype along with FromStr implementation to get validation for free during +parsing.

+ +
#[derive(Debug, Clone, Copy)]
+pub struct Ratio(u8);
+ 
+impl FromStr for Ratio {
+    type Err = &'static str;
+ 
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s.parse() {
+            Ok(n) if n <= 100 => Ok(Ratio(n)),
+            _ => Err("Invalid fill ratio")
+        }
+    }
+}
+ 
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+struct Options {
+    /// Fill ratio
+    ratio: Ratio
+}
+ 
+fn main() {
+    println!("{:?}", options().run());
+}
+

Try using enums instead of structs for mutually exclusive options:

+
/// Good format selection
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+enum OutputFormat {
+    Intel,
+    Att,
+    Llvm
+}
+ 
+fn main() {
+    let format = output_format().run();
+ 
+    // `rustc` ensures you handle each case, parser won't try to consume
+    // combinations of flags it can't represent. For example it won't accept
+    // both `--intel` and `--att` at once
+    // (unless it can collect multiple of them in a vector)
+    match format {
+        OutputFormat::Intel => ...,
+        OutputFormat::Att => ...,
+        OutputFormat::Llvm => ...,
+    }
+}
+
+

While it’s easy to see how flags like --intel and --att maps to each of those bools, +consuming inside your app is more fragile

+
/// Bad format selection
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+struct OutputFormat {
+    intel: bool,
+    att: bool,
+    llvm: bool,
+}
+ 
+fn main() {
+    let format = output_format().run();
+    // what happens when none matches? Or all of them?
+    // What happens when you add a new output format?
+    if format.intel {
+        ...
+    } else if format.att {
+        ...
+    } else if format.llvm {
+        ...
+    } else {
+        // can this branch be reached?
+    }
+}
+
+

Mutually exclusive things are not limited to just flags. For example if your program can take +input from several different sources such as file, database or interactive input it’s a good +idea to use enum as well:

+
/// Good input selection
+#[derive(Debug, Clone, Bpaf)]
+enum Input {
+    File {
+        filepath: PathBuf,
+    }
+    Database {
+        user: String,
+        password: String.
+    }
+    Interactive,
+}
+
+

If your codebase uses newtype pattern - it’s a good idea to use it starting from the command +options:

+
#[derive(Debug, Clone, Bpaf)]
+struct Options {
+    // better than taking a String and parsing internally
+    date: NaiveDate,
+    // f64 might work too, but you can start from some basic sanity checks
+    speed: Speed
+}
+

§More reading

+ +

 

+ + + + +
+

← Derive API tutorial

+
+

↑ Tutorials ↑

+
+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/_3_picking_type/sidebar-items.js b/bpaf/_documentation/_1_tutorials/_3_picking_type/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/_3_picking_type/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/index.html b/bpaf/_documentation/_1_tutorials/index.html new file mode 100644 index 00000000..aac94e0e --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/index.html @@ -0,0 +1,34 @@ +bpaf::_documentation::_1_tutorials - Rust +
Expand description

 

+ + + + +
+

← Introduction and design goals

+
+

↑ Project documentation ↑

+
+

HOWTO - practical, oriented to solving problems guides →

+
+
§Tutorials
+

practical, learning oriented guides

+ +

 

+ + + + +
+

← Introduction and design goals

+
+

↑ Project documentation ↑

+
+

HOWTO - practical, oriented to solving problems guides →

+
+

Modules§

\ No newline at end of file diff --git a/bpaf/_documentation/_1_tutorials/sidebar-items.js b/bpaf/_documentation/_1_tutorials/sidebar-items.js new file mode 100644 index 00000000..ed7c847f --- /dev/null +++ b/bpaf/_documentation/_1_tutorials/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["_0_types_of_arguments","_1_combinatoric_api","_2_derive_api","_3_picking_type"]}; \ No newline at end of file diff --git a/bpaf/_documentation/_2_howto/_0_testing/index.html b/bpaf/_documentation/_2_howto/_0_testing/index.html new file mode 100644 index 00000000..34ce0efd --- /dev/null +++ b/bpaf/_documentation/_2_howto/_0_testing/index.html @@ -0,0 +1,61 @@ +bpaf::_documentation::_2_howto::_0_testing - Rust +
Expand description

 

+ + + + +
+ +

↑ HOWTO - practical, oriented to solving problems guides ↑

+
+

Dynamic shell completion →

+
+
§Testing your parsers
+

You can test values your parser produces and expected output

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    pub user: String
+}
+ 
+#[test]
+fn test_my_options() {
+    let help = options()
+        .run_inner(&["--help"])
+        .unwrap_err()
+        .unwrap_stdout();
+    let expected_help = "\
+Usage --user=ARG
+<skip>
+";
+ 
+    assert_eq!(help, expected_help);
+}
+ 
+#[test]
+fn test_value() {
+    let value = options()
+         .run_inner(&["--user", "Bob"])
+         .unwrap();
+    assert_eq!(value.user, "Bob");
+}
+

OptionParser::run_inner takes Args or anything that can be converted to it, in most +cases using a static slice with strings is enough.

+

Easiest way to consume ParseFailure for testing purposes is with +ParseFailure::unwrap_stderr and ParseFailure::unwrap_stdout - result will lack any colors +even with them enabled which makes testing easier.

+

Successful result parse produces a value, “failed” parse produces stdout or stderr outputs - +stdout to print help message or version number and stderr to print the error message.

+

 

+ + + + +
+ +

↑ HOWTO - practical, oriented to solving problems guides ↑

+
+

Dynamic shell completion →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_2_howto/_0_testing/sidebar-items.js b/bpaf/_documentation/_2_howto/_0_testing/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_2_howto/_0_testing/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_2_howto/_1_completion/index.html b/bpaf/_documentation/_2_howto/_1_completion/index.html new file mode 100644 index 00000000..7ad5e179 --- /dev/null +++ b/bpaf/_documentation/_2_howto/_1_completion/index.html @@ -0,0 +1,68 @@ +bpaf::_documentation::_2_howto::_1_completion - Rust +
Expand description

 

+ + + + +
+

← Testing your parsers

+
+

↑ HOWTO - practical, oriented to solving problems guides ↑

+
+
+
§Dynamic shell completion
+

bpaf implements shell completion to allow to automatically fill in not only flag and command +names, but also argument and positional item values.

+
    +
  1. +

    Enable autocomplete feature:

    +
    bpaf = { version = "0.9", features = ["autocomplete"] }
    +
  2. +
  3. +

    Decorate argument and positional parsers with +Parser::complete to provide completion functions for arguments

    +
  4. +
  5. +

    Depending on your shell generate appropriate completion file and place it to whereever your +shell is going to look for it, name of the file should correspond in some way to name of +your program. Consult manual for your shell for the location and named conventions:

    +
      +
    1. +

      bash

      +
      $ your_program --bpaf-complete-style-bash >> ~/.bash_completion
      +
    2. +
    3. +

      zsh: note _ at the beginning of the filename

      +
      $ your_program --bpaf-complete-style-zsh > ~/.zsh/_your_program
      +
    4. +
    5. +

      fish

      +
      $ your_program --bpaf-complete-style-fish > ~/.config/fish/completions/your_program.fish
      +
    6. +
    7. +

      elvish

      +
      $ your_program --bpaf-complete-style-elvish >> ~/.config/elvish/rc.elv
      +
    8. +
    +
  6. +
  7. +

    Restart your shell - you need to done it only once or optionally after bpaf major version +upgrade: generated completion files contain only instructions how to ask your program for +possible completions and don’t change even if options are different.

    +
  8. +
  9. +

    Generated scripts rely on your program being accessible in $PATH

    +
  10. +
+

 

+ + + + +
+

← Testing your parsers

+
+

↑ HOWTO - practical, oriented to solving problems guides ↑

+
+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_2_howto/_1_completion/sidebar-items.js b/bpaf/_documentation/_2_howto/_1_completion/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_2_howto/_1_completion/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_2_howto/index.html b/bpaf/_documentation/_2_howto/index.html new file mode 100644 index 00000000..707410fe --- /dev/null +++ b/bpaf/_documentation/_2_howto/index.html @@ -0,0 +1,31 @@ +bpaf::_documentation::_2_howto - Rust +
Expand description

 

+ + + + +
+

← Tutorials

+
+

↑ Project documentation ↑

+
+

Parsing cookbook →

+
+
§HOWTO - practical, oriented to solving problems guides
+ +

 

+ + + + +
+

← Tutorials

+
+

↑ Project documentation ↑

+
+

Parsing cookbook →

+
+

Modules§

\ No newline at end of file diff --git a/bpaf/_documentation/_2_howto/sidebar-items.js b/bpaf/_documentation/_2_howto/sidebar-items.js new file mode 100644 index 00000000..1b0544b6 --- /dev/null +++ b/bpaf/_documentation/_2_howto/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["_0_testing","_1_completion"]}; \ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_00_find/index.html b/bpaf/_documentation/_3_cookbook/_00_find/index.html new file mode 100644 index 00000000..bfc4e502 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_00_find/index.html @@ -0,0 +1,218 @@ +bpaf::_documentation::_3_cookbook::_00_find - Rust +
Expand description

 

+ + + + +
+ +

↑ Parsing cookbook ↑

+
+

dd(1): dd if=/dev/zero of=/dev/null bs=1000

+
+
§find(1): find -exec commands -flags terminated by \;
+

An Example for find shows how to implement 3 different unusual options:

+
    +
  • an option with a long name but a single dash as a prefix: -user bob
  • +
  • an option that captures everything until the next fixed character
  • +
  • an option that takes a set of characters: -mode -rw, mode /rw
  • +
+

In all cases, long name with a single dash is implemented by the literal with +ParseAny::anywhere with some items made adjacent to it.

+

To parse -user bob this is simply literal -user adjacent to a positional item with map to +focus on the interesting part.

+

For -exec more things here ; this is a combination of literal -exec, followed by many +items that are not ; parsed positionally with any followed by ; - again with any, but +literal works too.

+

And lastly to parse mode - after the tag, we accept any to be able to handle a combination of +modes that may or may not start with - and use Parser::parse to parse them or fail.

+

All special cases are made optional with Parser::optional, but Parser::fallback also +works.

+
examples/find.rs + +
//! This is not a typical bpaf usage,
+//! but you should be able to replicate command line used by find
+
+use bpaf::*;
+use std::{ffi::OsString, path::PathBuf};
+
+#[derive(Debug, Clone, Default)]
+pub struct Perms {
+    read: bool,
+    write: bool,
+    exec: bool,
+}
+
+#[derive(Debug, Clone)]
+pub enum Perm {
+    All(Perms),
+    Any(Perms),
+    Exact(Perms),
+}
+
+#[derive(Debug, Clone)]
+#[allow(dead_code)]
+pub struct Options {
+    paths: Vec<PathBuf>,
+    exec: Option<Vec<OsString>>,
+    user: Option<String>,
+    perm: Option<Perm>,
+}
+
+// Parses -user xxx
+fn user() -> impl Parser<Option<String>> {
+    // match only literal "-user"
+    let tag = literal("-user").anywhere();
+    let value = positional("USER").help("User name");
+    construct!(tag, value)
+        .adjacent()
+        .map(|pair| pair.1)
+        .optional()
+}
+
+// parsers -exec xxx yyy zzz ;
+fn exec() -> impl Parser<Option<Vec<OsString>>> {
+    let tag = literal("-exec")
+        .help("for every file find finds execute a separate shell command")
+        .anywhere();
+
+    let item = any::<OsString, _, _>("ITEM", |s| (s != ";").then_some(s))
+        .help("command with its arguments, find will replace {} with a file name")
+        .many();
+
+    let endtag = any::<String, _, _>(";", |s| (s == ";").then_some(()))
+        .help("anything after literal \";\" will be considered a regular option again");
+
+    construct!(tag, item, endtag)
+        .adjacent()
+        .map(|triple| triple.1)
+        .optional()
+}
+
+/// parses symbolic permissions `-perm -mode`, `-perm /mode` and `-perm mode`
+fn perm() -> impl Parser<Option<Perm>> {
+    fn parse_mode(input: &str) -> Result<Perms, String> {
+        let mut perms = Perms::default();
+        for c in input.chars() {
+            match c {
+                'r' => perms.read = true,
+                'w' => perms.write = true,
+                'x' => perms.exec = true,
+                _ => return Err(format!("{} is not a valid permission string", input)),
+            }
+        }
+        Ok(perms)
+    }
+
+    let tag = literal("-mode").anywhere();
+
+    // `any` here is used to parse an arbitrary string that can also start with dash (-)
+    // regular positional parser won't work here
+    let mode = any("MODE", Some)
+        .help("(perm | -perm | /perm), where perm is any subset of rwx characters, ex +rw")
+        .parse::<_, _, String>(|s: String| {
+            if let Some(m) = s.strip_prefix('-') {
+                Ok(Perm::All(parse_mode(m)?))
+            } else if let Some(m) = s.strip_prefix('/') {
+                Ok(Perm::Any(parse_mode(m)?))
+            } else {
+                Ok(Perm::Exact(parse_mode(&s)?))
+            }
+        });
+
+    construct!(tag, mode)
+        .adjacent()
+        .map(|pair| pair.1)
+        .optional()
+}
+
+pub fn options() -> OptionParser<Options> {
+    let paths = positional::<PathBuf>("PATH").many();
+
+    construct!(Options {
+        exec(),
+        user(),
+        perm(),
+        paths,
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:#?}", options().run());
+}
+
+
+
Output +

Usually find takes a path where to look, the rest is optional

+
+$ app src tests
+Options { paths: ["src", "tests"], exec: None, user: None, perm: None } +
+

In addition to paths find can take some more options, typically unusual: username, note a +single dash with a long name:

+
+$ app -user bob
+Options { paths: [], exec: None, user: Some("bob"), perm: None } +
+

Permissions, in an unusual format:

+
+$ app -mode /x
+Options { paths: [], exec: None, user: None, perm: Some(Any(Perms { read: false, write: false, exec: true })) } +
+

And the most interesting one is -exec which takes multiple arbitrary parameters terminated +by ; (in shell you have to escape it as \\;)

+
+$ app -exec cat -A '{}' \;
+Options { paths: [], exec: Some(["cat", "-A", "{}"]), user: None, perm: None } +
+

As usuall you can mix them and order doesn’t matter

+
+$ app src -mode -r -user bob -exec rustc '{}' \;
+Options { paths: ["src"], exec: Some(["rustc", "{}"]), user: Some("bob"), perm: Some(All(Perms { read: true, write: false, exec: false })) } +
+

While bpaf takes some effort to render the help even for custom stuff - you can always +bypass it by hiding options and substituting your own with custom header/footer.

+
+$ app --help
+

Usage: app [-exec [ITEM]... ;] [-user USER] [-mode MODE] [PATH]...

+Available options:
-exec [ITEM]... ;
-exec
+
for every file find finds execute a separate shell command
+
ITEM
+
command with its arguments, find will replace {} with a file name
+
;
+
anything after literal ";" will be considered a regular option again
+

-user USER
USER
+
User name
+

-mode MODE
MODE
+
(perm | -perm | /perm), where perm is any subset of rwx characters, ex +rw
+

-h, --help
+
Prints help information
+
+

+ +
+
+

 

+ + + + +
+ +

↑ Parsing cookbook ↑

+
+

dd(1): dd if=/dev/zero of=/dev/null bs=1000

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_00_find/sidebar-items.js b/bpaf/_documentation/_3_cookbook/_00_find/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_00_find/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_01_dd/index.html b/bpaf/_documentation/_3_cookbook/_01_dd/index.html new file mode 100644 index 00000000..a7c6ef99 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_01_dd/index.html @@ -0,0 +1,153 @@ +bpaf::_documentation::_3_cookbook::_01_dd - Rust +
Expand description

 

+ + + + +
+

find(1): find -exec commands -flags terminated by \;

+
+

↑ Parsing cookbook ↑

+
+

Xorg(1): Xorg +xinerama +extension name

+
+
§dd(1): dd if=/dev/zero of=/dev/null bs=1000
+

This example implements syntax similar to dd command. The main idea is to implement something to +make it simple to make parsers for PREFIX=SUFFIX, where prefix is fixed for each parser - for +example if= or of= and suffix is parsed with usual FromStr trait.

+

The function tag serves this purpose. It performs the following steps:

+
    +
  • consume any item that starts with a prefix at any argument position with any and +ParseAny::anywhere
  • +
  • attaches help message and custom metadata to make --help friendlier
  • +
  • parses suffix with Parser::parse
  • +
+

The rest of the parser simply uses tag to parse a few of dd arguments

+
examples/dd.rs + +
//! This is not a typical bpaf usage,
+//! but you should be able to replicate command line used by dd
+use bpaf::{any, construct, doc::Style, short, OptionParser, Parser};
+use std::str::FromStr;
+
+#[derive(Debug, Clone)]
+#[allow(dead_code)]
+pub struct Options {
+    magic: bool,
+    in_file: String,
+    out_file: String,
+    block_size: usize,
+}
+
+/// Parses a string that starts with `name`, returns the suffix parsed in a usual way
+fn tag<T>(name: &'static str, meta: &str, help: &'static str) -> impl Parser<T>
+where
+    T: FromStr,
+    <T as std::str::FromStr>::Err: std::fmt::Display,
+{
+    // it is possible to parse OsString here and strip the prefix with
+    // `os_str_bytes` or a similar crate
+    any("", move |s: String| Some(s.strip_prefix(name)?.to_owned()))
+        // this defines custom metavar for the help message
+        .metavar(&[(name, Style::Literal), (meta, Style::Metavar)][..])
+        .help(help)
+        .anywhere()
+        .parse(|s| s.parse())
+}
+
+fn in_file() -> impl Parser<String> {
+    tag::<String>("if=", "FILE", "read from FILE")
+        .fallback(String::from("-"))
+        .display_fallback()
+}
+
+fn out_file() -> impl Parser<String> {
+    tag::<String>("of=", "FILE", "write to FILE")
+        .fallback(String::from("-"))
+        .display_fallback()
+}
+
+fn block_size() -> impl Parser<usize> {
+    // it is possible to parse notation used by dd itself as well,
+    // using usuze only for simplicity
+    tag::<usize>("bs=", "SIZE", "read/write SIZE blocks at once")
+        .fallback(512)
+        .display_fallback()
+}
+
+pub fn options() -> OptionParser<Options> {
+    let magic = short('m')
+        .long("magic")
+        .help("a usual switch still works")
+        .switch();
+    construct!(Options {
+        magic,
+        in_file(),
+        out_file(),
+        block_size(),
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:#?}", options().run());
+}
+
+
+
Output +

bpaf generates usual help message with

+
+$ app --help
+

Usage: app [-m] [if=FILE] [of=FILE] [bs=SIZE]

+Available options:
-m, --magic
+
a usual switch still works
+
if=FILE
+
read from FILE
+
+
[default: -]
+
of=FILE
+
write to FILE
+
+
[default: -]
+
bs=SIZE
+
read/write SIZE blocks at once
+
+
[default: 512]
+
-h, --help
+
Prints help information
+
+

+ +
+

Unlike usual application dd takes it arguments in shape of operations +KEY=VAL without any dashes, plus usual --help and --version flags.

+

To handle that we define custom basic parsers that make handling such operations easy

+
+$ app if=/dev/zero of=/tmp/blob bs=1024
+Options { magic: false, in_file: "/dev/zero", out_file: "/tmp/blob", block_size: 1024 } +
+
+

 

+ + + + +
+

find(1): find -exec commands -flags terminated by \;

+
+

↑ Parsing cookbook ↑

+
+

Xorg(1): Xorg +xinerama +extension name

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_01_dd/sidebar-items.js b/bpaf/_documentation/_3_cookbook/_01_dd/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_01_dd/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_02_xorg/index.html b/bpaf/_documentation/_3_cookbook/_02_xorg/index.html new file mode 100644 index 00000000..02e87f5f --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_02_xorg/index.html @@ -0,0 +1,143 @@ +bpaf::_documentation::_3_cookbook::_02_xorg - Rust +
Expand description

 

+ + + + +
+

dd(1): dd if=/dev/zero of=/dev/null bs=1000

+
+

↑ Parsing cookbook ↑

+
+

Command chaining →

+
+
§Xorg(1): Xorg +xinerama +extension name
+

This example implements syntax similar to used by Xorg or similar programs. As usual with +strange examples any serves an important role.

+

The example implements the following parsers:

+
    +
  • enable or disable an extension using +ext name and -ext name like syntax
  • +
  • enable or disable specific extensions with syntax like -xinerama or +backing
  • +
+

Both parsers use any with ParseAny::anywhere

+
examples/xorg.rs + +
/// A way to represent xorg like flags, not a typical usage
+use bpaf::*;
+#[derive(Debug, Clone)]
+#[allow(dead_code)]
+pub struct Options {
+    turbo: bool,
+    backing: bool,
+    xinerama: bool,
+    extensions: Vec<(String, bool)>,
+}
+
+// matches literal name prefixed with - or +
+fn toggle_options(meta: &'static str, name: &'static str, help: &'static str) -> impl Parser<bool> {
+    any(meta, move |s: String| {
+        if let Some(suf) = s.strip_prefix('+') {
+            (suf == name).then_some(true)
+        } else if let Some(suf) = s.strip_prefix('-') {
+            (suf == name).then_some(false)
+        } else {
+            None
+        }
+    })
+    .help(help)
+    .anywhere()
+}
+
+// matches literal +ext and -ext followed by extension name
+fn extension() -> impl Parser<(String, bool)> {
+    let state = any("(+|-)ext", |s: String| match s.as_str() {
+        "-ext" => Some(false),
+        "+ext" => Some(true),
+        _ => None,
+    })
+    .anywhere();
+
+    let name = positional::<String>("EXT")
+        .help("Extension to enable or disable, see documentation for the full list");
+    construct!(state, name).adjacent().map(|(a, b)| (b, a))
+}
+
+pub fn options() -> OptionParser<Options> {
+    let backing = toggle_options("(+|-)backing", "backing", "Set backing status").fallback(false);
+    let xinerama =
+        toggle_options("(+|-)xinerama", "xinerama", "Set Xinerama status").fallback(true);
+    let turbo = short('t')
+        .long("turbo")
+        .help("Engage the turbo mode")
+        .switch();
+    let extensions = extension().many();
+    construct!(Options {
+        turbo,
+        backing,
+        xinerama,
+        extensions,
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:#?}", options().run());
+}
+
+
+
Output +

xorg takes parameters in a few different ways, notably as a long name starting with plus or +minus with different defaults

+
+$ app -xinerama +backing
+Options { turbo: false, backing: true, xinerama: false, extensions: [] } +
+

But also as +ext name and -ext name to enable or disable an extensions

+
+$ app --turbo +ext banana -ext apple
+Options { turbo: true, backing: false, xinerama: true, extensions: [("banana", true), ("apple", false)] } +
+

While bpaf takes some effort to render the help even for custom stuff - you can always +bypass it by hiding options and substituting your own with custom header/footer.

+
+$ app --help
+

Usage: app [-t] [(+|-)backing] [(+|-)xinerama] [(+|-)ext EXT]...

+Available options:
-t, --turbo
+
Engage the turbo mode
+
(+|-)backing
+
Set backing status
+
(+|-)xinerama
+
Set Xinerama status
+
(+|-)ext EXT
EXT
+
Extension to enable or disable, see documentation for the full list
+

-h, --help
+
Prints help information
+
+

+ +
+
+

 

+ + + + +
+

dd(1): dd if=/dev/zero of=/dev/null bs=1000

+
+

↑ Parsing cookbook ↑

+
+

Command chaining →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_02_xorg/sidebar-items.js b/bpaf/_documentation/_3_cookbook/_02_xorg/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_02_xorg/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_03_command_chaining/index.html b/bpaf/_documentation/_3_cookbook/_03_command_chaining/index.html new file mode 100644 index 00000000..3fb19ad9 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_03_command_chaining/index.html @@ -0,0 +1,212 @@ +bpaf::_documentation::_3_cookbook::_03_command_chaining - Rust +
Expand description

 

+ + + + +
+

Xorg(1): Xorg +xinerama +extension name

+
+

↑ Parsing cookbook ↑

+
+

Multi-value arguments: --foo ARG1 ARG2 ARG3

+
+
§Command chaining
+

Lets you do things like setup.py sdist bdist: command chaining

+

With adjacent +bpaf allows you to have several commands side by side instead of being nested.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    premium: bool,
+    commands: Vec<Cmd>,
+}
+
+#[derive(Debug, Clone)]
+// shape of the variants doesn't really matter, let's use all of them :)
+enum Cmd {
+    Eat(String),
+    Drink { coffee: bool },
+    Sleep { time: usize },
+}
+
+fn cmd() -> impl Parser<Cmd> {
+    let eat = positional::<String>("FOOD")
+        .to_options()
+        .descr("Performs eating action")
+        .command("eat")
+        .adjacent()
+        .map(Cmd::Eat);
+
+    let coffee = long("coffee")
+        .help("Are you going to drink coffee?")
+        .switch();
+    let drink = construct!(Cmd::Drink { coffee })
+        .to_options()
+        .descr("Performs drinking action")
+        .command("drink")
+        .adjacent();
+
+    let time = long("time").argument::<usize>("HOURS");
+    let sleep = construct!(Cmd::Sleep { time })
+        .to_options()
+        .descr("Performs taking a nap action")
+        .command("sleep")
+        .adjacent();
+
+    construct!([eat, drink, sleep])
+}
+
+pub fn options() -> OptionParser<Options> {
+    let premium = short('p')
+        .long("premium")
+        .help("Opt in for premium serivces")
+        .switch();
+    let commands = cmd().many();
+    construct!(Options { premium, commands }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long)]
+    /// Opt in for premium serivces
+    pub premium: bool,
+    #[bpaf(external(cmd), many)]
+    pub commands: Vec<Cmd>,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+pub enum Cmd {
+    #[bpaf(command, adjacent)]
+    /// Performs eating action
+    Eat(#[bpaf(positional("FOOD"))] String),
+    #[bpaf(command, adjacent)]
+    /// Performs drinking action
+    Drink {
+        /// Are you going to drink coffee?
+        coffee: bool,
+    },
+    #[bpaf(command, adjacent)]
+    /// Performs taking a nap action
+    Sleep {
+        #[bpaf(argument("HOURS"))]
+        time: usize,
+    },
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Example implements a parser that supports one of three possible commands:

+
+$ app --help
+

Usage: app [-p] [COMMAND ...]...

+Available options:
-p, --premium
+
Opt in for premium serivces
+
-h, --help
+
Prints help information
+
+

+Available commands:
eat
+
Performs eating action
+
drink
+
Performs drinking action
+
sleep
+
Performs taking a nap action
+
+

+ +
+

As usual every command comes with its own help

+
+$ app drink --help
+

Performs drinking action

Usage: app drink [--coffee]

+Available options:
--coffee
+
Are you going to drink coffee?
+
-h, --help
+
Prints help information
+
+

+ +
+

Normally you can use one command at a time, but making commands adjacent lets +parser to succeed after consuming an adjacent block only and leaving leftovers for the rest of +the parser, consuming them as a Vec<Cmd> with many allows to chain multiple +items sequentially

+
+$ app eat Fastfood drink --coffee sleep --time=5
+Options { premium: false, commands: [Eat("Fastfood"), Drink { coffee: true }, Sleep { time: 5 }] } +
+

The way this works is by running parsers for each command. In the first iteration eat succeeds, +it consumes eat fastfood portion and appends its value to the resulting vector. Then second +iteration runs on leftovers, in this case it will be drink --coffee sleep --time=5. +Here drink succeeds and consumes drink --coffee portion, then sleep parser runs, etc.

+

You can mix chained commands with regular arguments that belong to the top level parser

+
+$ app sleep --time 10 --premium eat 'Bak Kut Teh' drink
+Options { premium: true, commands: [Sleep { time: 10 }, Eat("Bak Kut Teh"), Drink { coffee: false }] } +
+

But not inside the command itself since values consumed by the command are not going to be +adjacent

+
+$ app sleep --time 10 eat --premium 'Bak Kut Teh' drink
+Error: expected FOOD, pass --help for usage information + +
+
+

 

+ + + + +
+

Xorg(1): Xorg +xinerama +extension name

+
+

↑ Parsing cookbook ↑

+
+

Multi-value arguments: --foo ARG1 ARG2 ARG3

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_03_command_chaining/sidebar-items.js b/bpaf/_documentation/_3_cookbook/_03_command_chaining/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_03_command_chaining/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_04_multi_value/index.html b/bpaf/_documentation/_3_cookbook/_04_multi_value/index.html new file mode 100644 index 00000000..9d7a8b43 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_04_multi_value/index.html @@ -0,0 +1,164 @@ +bpaf::_documentation::_3_cookbook::_04_multi_value - Rust +
Expand description

 

+ + + + +
+

← Command chaining

+
+

↑ Parsing cookbook ↑

+
+

Structure groups: --foo --foo-1 ARG1 --foo-2 ARG2 --foo-3 ARG3

+
+
§Multi-value arguments: --foo ARG1 ARG2 ARG3
+

By default arguments take at most one value, you can create multi value options by using +adjacent modifier

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    point: Vec<Point>,
+    rotate: bool,
+}
+
+#[derive(Debug, Clone)]
+struct Point {
+    point: (),
+    x: usize,
+    y: usize,
+    z: f64,
+}
+
+fn point() -> impl Parser<Point> {
+    let point = short('p')
+        .long("point")
+        .help("Point coordinates")
+        .req_flag(());
+    let x = positional::<usize>("X").help("X coordinate of a point");
+    let y = positional::<usize>("Y").help("Y coordinate of a point");
+    let z = positional::<f64>("Z").help("Height of a point above the plane");
+    construct!(Point { point, x, y, z }).adjacent()
+}
+
+pub fn options() -> OptionParser<Options> {
+    let rotate = short('r')
+        .long("rotate")
+        .help("Face the camera towards the first point")
+        .switch();
+    let point = point().many();
+    construct!(Options { point, rotate }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(external, many)]
+    point: Vec<Point>,
+    #[bpaf(short, long)]
+    /// Face the camera towards the first point
+    rotate: bool,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(adjacent)]
+struct Point {
+    #[bpaf(short, long)]
+    /// Point coordinates
+    point: (),
+    #[bpaf(positional("X"))]
+    /// X coordinate of a point
+    x: usize,
+    #[bpaf(positional("Y"))]
+    /// Y coordinate of a point
+    y: usize,
+    #[bpaf(positional("Z"))]
+    /// Height of a point above the plane
+    z: f64,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Fields can have different types, including Option or Vec, in this example they are two +usize and one f64.

+
+$ app --help
+

Usage: app [-p X Y Z]... [-r]

+Available options:
-p X Y Z
-p, --point
+
Point coordinates
+
X
+
X coordinate of a point
+
Y
+
Y coordinate of a point
+
Z
+
Height of a point above the plane
+

-r, --rotate
+
Face the camera towards the first point
+
-h, --help
+
Prints help information
+
+

+ +
+

flag --point takes 3 positional arguments: two integers for X and Y coordinates and one floating point for height, order is +important, switch --rotate can go on either side of it

+
+$ app --rotate --point 10 20 3.1415
+Options { point: [Point { point: (), x: 10, y: 20, z: 3.1415 }], rotate: true } +
+

parser accepts multiple points, they must not interleave

+
+$ app --point 10 20 3.1415 --point 1 2 0.0
+Options { point: [Point { point: (), x: 10, y: 20, z: 3.1415 }, Point { point: (), x: 1, y: 2, z: 0.0 }], rotate: false } +
+

--rotate can’t go in the middle of the point definition as the parser expects the second item

+
+$ app --point 10 20 --rotate 3.1415
+Error: expected Z, pass --help for usage information + +
+
+

 

+ + + + +
+

← Command chaining

+
+

↑ Parsing cookbook ↑

+
+

Structure groups: --foo --foo-1 ARG1 --foo-2 ARG2 --foo-3 ARG3

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_04_multi_value/sidebar-items.js b/bpaf/_documentation/_3_cookbook/_04_multi_value/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_04_multi_value/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_05_struct_groups/index.html b/bpaf/_documentation/_3_cookbook/_05_struct_groups/index.html new file mode 100644 index 00000000..b80a5ea1 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_05_struct_groups/index.html @@ -0,0 +1,203 @@ +bpaf::_documentation::_3_cookbook::_05_struct_groups - Rust +
Expand description

 

+ + + + +
+

← Multi-value arguments: --foo ARG1 ARG2 ARG3

+
+

↑ Parsing cookbook ↑

+
+

Multi-value arguments with optional flags: --foo ARG1 --flag --inner ARG2

+
+
§Structure groups: --foo --foo-1 ARG1 --foo-2 ARG2 --foo-3 ARG3
+

Groups of options that can be specified multiple times. All such groups should be kept without +overwriting previous one.

+
 $ prometheus_sensors_exporter \
+     \
+     `# 2 physical sensors located on physycial different i2c bus or address` \
+     --sensor \
+         --sensor-device=tmp102 \
+         --sensor-name="temperature_tmp102_outdoor" \
+         --sensor-i2c-bus=0 \
+         --sensor-i2c-address=0x48 \
+     --sensor \
+         --sensor-device=tmp102 \
+         --sensor-name="temperature_tmp102_indoor" \
+         --sensor-i2c-bus=1 \
+         --sensor-i2c-address=0x49 \
+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    rect: Vec<Rect>,
+    mirror: bool,
+}
+
+#[derive(Debug, Clone)]
+struct Rect {
+    rect: (),
+    width: usize,
+    height: usize,
+    painted: bool,
+}
+
+fn rect() -> impl Parser<Rect> {
+    let rect = long("rect").help("Define a new rectangle").req_flag(());
+    let width = short('w')
+        .long("width")
+        .help("Rectangle width in pixels")
+        .argument::<usize>("PX");
+    let height = short('h')
+        .long("height")
+        .help("Rectangle height in pixels")
+        .argument::<usize>("PX");
+    let painted = short('p')
+        .long("painted")
+        .help("Should rectangle be filled?")
+        .switch();
+    construct!(Rect {
+        rect,
+        width,
+        height,
+        painted,
+    })
+    .adjacent()
+}
+
+pub fn options() -> OptionParser<Options> {
+    let mirror = long("mirror").help("Mirror the image").switch();
+    let rect = rect().many();
+    construct!(Options { rect, mirror }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(external, many)]
+    rect: Vec<Rect>,
+    /// Mirror the image
+    mirror: bool,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(adjacent)]
+struct Rect {
+    /// Define a new rectangle
+    rect: (),
+    #[bpaf(short, long, argument("PX"))]
+    /// Rectangle width in pixels
+    width: usize,
+    #[bpaf(short, long, argument("PX"))]
+    /// Rectangle height in pixels
+    height: usize,
+    #[bpaf(short, long)]
+    /// Should rectangle be filled?
+    painted: bool,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

This example parses multipe rectangles from a command line defined by dimensions and the fact +if its filled or not, to make things more interesting - every group of coordinates must be +prefixed with --rect

+
+$ app --help
+

Usage: app [--rect -w=PX -h=PX [-p]]... [--mirror]

+Available options:
--rect -w=PX -h=PX [-p]
--rect
+
Define a new rectangle
+
-w, --width=PX
+
Rectangle width in pixels
+
-h, --height=PX
+
Rectangle height in pixels
+
-p, --painted
+
Should rectangle be filled?
+

--mirror
+
Mirror the image
+
-h, --help
+
Prints help information
+
+

+ +
+

Order of items within the rectangle is not significant and you can have several of them, +because fields are still regular arguments - order doesn’t matter for as long as they belong +to some rectangle

+
+$ app --rect --width 10 --height 10 --rect --height=10 --width=10
+Options { rect: [Rect { rect: (), width: 10, height: 10, painted: false }, Rect { rect: (), width: 10, height: 10, painted: false }], mirror: false } +
+

You can have optional values that belong to the group inside and outer flags in the middle

+
+$ app --rect --width 10 --painted --height 10 --mirror --rect --height 10 --width 10
+Options { rect: [Rect { rect: (), width: 10, height: 10, painted: true }, Rect { rect: (), width: 10, height: 10, painted: false }], mirror: true } +
+

But with adjacent they cannot interleave

+
+$ app --rect --rect --width 10 --painted --height 10 --height 10 --width 10
+Error: expected --width=PX, pass --help for usage information + +
+

Or have items that don’t belong to the group inside them

+
+$ app --rect --width 10 --mirror --painted --height 10 --rect --height 10 --width 10
+Error: expected --height=PX, pass --help for usage information + +
+
+

 

+ + + + +
+

← Multi-value arguments: --foo ARG1 ARG2 ARG3

+
+

↑ Parsing cookbook ↑

+
+

Multi-value arguments with optional flags: --foo ARG1 --flag --inner ARG2

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_05_struct_groups/sidebar-items.js b/bpaf/_documentation/_3_cookbook/_05_struct_groups/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_05_struct_groups/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_06_multi_flag/index.html b/bpaf/_documentation/_3_cookbook/_06_multi_flag/index.html new file mode 100644 index 00000000..1cc01f1b --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_06_multi_flag/index.html @@ -0,0 +1,148 @@ +bpaf::_documentation::_3_cookbook::_06_multi_flag - Rust +
Expand description

 

+ + + + +
+

← Structure groups: --foo --foo-1 ARG1 --foo-2 ARG2 --foo-3 ARG3

+
+

↑ Parsing cookbook ↑

+
+

Skipping optional positional items if parsing or validation fails →

+
+
§Multi-value arguments with optional flags: --foo ARG1 --flag --inner ARG2
+

So you can parse things while parsing things. Not sure why you might need this, but you can +:)

+ +
#[derive(Debug, Clone)]
+pub struct Options {
+    meal: Vec<Meal>,
+    premium: bool,
+}
+
+#[derive(Debug, Clone)]
+struct Meal {
+    m: (),
+    spicy: Option<usize>,
+    drink: bool,
+    dish: usize,
+}
+
+/// You can mix all sorts of things inside the adjacent group
+fn meal() -> impl Parser<Meal> {
+    let m = short('o')
+        .long("meal")
+        .help("A meal [o]rder consists of a main dish with an optional drink")
+        .req_flag(());
+    let spicy = long("spicy")
+        .help("On a scale from 1 to a lot, how spicy do you want your meal?")
+        .argument::<usize>("SPICY")
+        .optional();
+    let drink = long("drink")
+        .help("Do you want drink with your meal?")
+        .switch();
+    let dish = positional::<usize>("DISH").help("Main dish number");
+    construct!(Meal {
+        m,
+        spicy,
+        drink,
+        dish
+    })
+    .adjacent()
+}
+
+pub fn options() -> OptionParser<Options> {
+    let premium = short('p')
+        .long("premium")
+        .help("Do you want to opt in for premium service?")
+        .switch();
+    let meal = meal().many();
+    construct!(Options { meal, premium }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +
+$ app --help
+

Usage: app [-o [--spicy=SPICY] [--drink] DISH]... [-p]

+Available options:
-o [--spicy=SPICY] [--drink] DISH
-o, --meal
+
A meal [o]rder consists of a main dish with an optional drink
+
--spicy=SPICY
+
On a scale from 1 to a lot, how spicy do you want your meal?
+
--drink
+
Do you want drink with your meal?
+
DISH
+
Main dish number
+

-p, --premium
+
Do you want to opt in for premium service?
+
-h, --help
+
Prints help information
+
+

+ +
+

Let’s start simple - a single flag accepts a bunch of stuff, and eveything is present

+
+$ app --meal 330 --spicy 10 --drink
+Options { meal: [Meal { m: (), spicy: Some(10), drink: true, dish: 330 }], premium: false } +
+

You can omit some parts, but also have multiple groups thank to many

+
+$ app --meal 100 --drink --meal 30 --spicy 10 --meal 50
+Options { meal: [Meal { m: (), spicy: None, drink: true, dish: 100 }, Meal { m: (), spicy: Some(10), drink: false, dish: 30 }, Meal { m: (), spicy: None, drink: false, dish: 50 }], premium: false } +
+

As usual it can be mixed with standalone flags

+
+$ app --premium --meal 42
+Options { meal: [Meal { m: (), spicy: None, drink: false, dish: 42 }], premium: true } +
+

Thanks to many whole meal part is optional

+
+$ app --premium
+Options { meal: [], premium: true } +
+

Error messages should be somewhat descriptive

+
+$ app --meal --drink --spicy 500
+Error: expected DISH, pass --help for usage information + +
+
+

 

+ + + + +
+

← Structure groups: --foo --foo-1 ARG1 --foo-2 ARG2 --foo-3 ARG3

+
+

↑ Parsing cookbook ↑

+
+

Skipping optional positional items if parsing or validation fails →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_06_multi_flag/sidebar-items.js b/bpaf/_documentation/_3_cookbook/_06_multi_flag/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_06_multi_flag/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_07_skip_positional/index.html b/bpaf/_documentation/_3_cookbook/_07_skip_positional/index.html new file mode 100644 index 00000000..f71a5e73 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_07_skip_positional/index.html @@ -0,0 +1,123 @@ +bpaf::_documentation::_3_cookbook::_07_skip_positional - Rust +
Expand description

 

+ + + + +
+

← Multi-value arguments with optional flags: --foo ARG1 --flag --inner ARG2

+
+

↑ Parsing cookbook ↑

+
+

Implementing cargo commands →

+
+
§Skipping optional positional items if parsing or validation fails
+

Combinations like Parser::optional and +ParseOptional::catch allow to try to parse something +and then handle the error as if pase attempt never existed

+
examples/numeric_prefix.rs + +
/// You can parse multiple positional elements with earlier being optional as well
+/// This example takes two - optional numeric prefix and a command name:
+///
+/// > numeric_prefix 8 work
+/// Options { prefix: Some(8), command: "work" }
+///
+/// > numeric_prefix sleep
+/// Options { prefix: None, command: "sleep" }
+///
+/// Generated usage reflects that:
+/// Usage: numeric_prefix [PREFIX] COMMAND
+use bpaf::*;
+
+#[derive(Debug, Clone)]
+#[allow(dead_code)]
+pub struct Options {
+    prefix: Option<usize>,
+    command: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let prefix = positional::<usize>("PREFIX")
+        .help("Optional numeric command prefix")
+        .optional()
+        .catch();
+    let command = positional::<String>("COMMAND").help("Required command name");
+
+    construct!(Options { prefix, command }).to_options()
+}
+
+fn main() {
+    println!("{:#?}", options().run());
+}
+
+
+
Output +

If bpaf can parse first positional argument as number - it becomes a numeric prefix

+
+$ app 10 eat
+Options { prefix: Some(10), command: "eat" } +
+

Otherwise it gets ignored

+
+$ app "just eat"
+Options { prefix: None, command: "just eat" } +
+

If validation passes but second argument is missing - in this example there’s no fallback

+
+$ app 10
+Error: expected COMMAND, pass --help for usage information + +
+

Help should show that the prefix is optional

+
+$ app --help
+

Usage: app [PREFIX] COMMAND

+Available positional items:
PREFIX
+
Optional numeric command prefix
+
COMMAND
+
Required command name
+
+

+Available options:
-h, --help
+
Prints help information
+
+

+ +
+
+

 

+ + + + +
+

← Multi-value arguments with optional flags: --foo ARG1 --flag --inner ARG2

+
+

↑ Parsing cookbook ↑

+
+

Implementing cargo commands →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_07_skip_positional/sidebar-items.js b/bpaf/_documentation/_3_cookbook/_07_skip_positional/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_07_skip_positional/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_08_cargo_helper/index.html b/bpaf/_documentation/_3_cookbook/_08_cargo_helper/index.html new file mode 100644 index 00000000..72c27306 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_08_cargo_helper/index.html @@ -0,0 +1,111 @@ +bpaf::_documentation::_3_cookbook::_08_cargo_helper - Rust +
Expand description

 

+ + + + +
+

← Skipping optional positional items if parsing or validation fails

+
+

↑ Parsing cookbook ↑

+
+

Numeric flags - compression levels like in zip →

+
+
§Implementing cargo commands
+

With cargo_helper you can use your application as a cargo command. +You will need to enable batteries feature while importing bpaf.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    argument: usize,
+    switch: bool,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = long("argument")
+        .help("An argument")
+        .argument::<usize>("ARG");
+    let switch = short('s').help("A switch").switch();
+    let options = construct!(Options { argument, switch });
+
+    // Given the cargo command is `cargo pretty`.
+    cargo_helper("pretty", options).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options("pretty"))] // Given the cargo command is `cargo pretty`.
+pub struct Options {
+    /// An argument
+    argument: usize,
+    /// A switch
+    #[bpaf(short)]
+    switch: bool,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Let’s say the goal is to parse an argument and a switch:

+
+$ app --argument 15
+Options { argument: 15, switch: false } +
+

But when used as a cargo subcommand, cargo will also pass the command name. For example +you can invoke an app with binary name cargo-asm

+
$ cargo asm --lib --everything
+...
+
+

cargo will then spawn the executable and pass it following parameters:

+
$ cargo-asm asm --lib --everything
+...
+
+

If you are not using cargo_helper - parser won’t know what to do with asm part. +cargo-helper allows the parser to strip it from the front and everything works as expected.

+

And it doesn’t show up in --help so not to confuse users

+
+$ app --help
+

Usage: app --argument=ARG [-s]

+Available options:
--argument=ARG
+
An argument
+
-s
+
A switch
+
-h, --help
+
Prints help information
+
+

+ +
+
+

 

+ + + + +
+

← Skipping optional positional items if parsing or validation fails

+
+

↑ Parsing cookbook ↑

+
+

Numeric flags - compression levels like in zip →

+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_08_cargo_helper/sidebar-items.js b/bpaf/_documentation/_3_cookbook/_08_cargo_helper/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_08_cargo_helper/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_09_numeric_flags/index.html b/bpaf/_documentation/_3_cookbook/_09_numeric_flags/index.html new file mode 100644 index 00000000..2da3ae9e --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_09_numeric_flags/index.html @@ -0,0 +1,52 @@ +bpaf::_documentation::_3_cookbook::_09_numeric_flags - Rust +
Expand description

 

+ + + + +
+

← Implementing cargo commands

+
+

↑ Parsing cookbook ↑

+
+
+
§Numeric flags - compression levels like in zip
+

While you can add flags in a usual way for compression levels using short(1), short(2), etc +combined with req_flag, you can also parse all of then using any

+ +
use bpaf::{doc::Style, *};
+ 
+fn compression() -> impl Parser<usize> {
+    any::<isize, _, _>("COMP", |x: isize| {
+        if (-9..=-1).contains(&x) {
+            Some(x.abs().try_into().unwrap())
+        } else {
+            None
+        }
+    })
+    .metavar(&[
+        ("-1", Style::Literal),
+        (" to ", Style::Text),
+        ("-9", Style::Literal),
+    ])
+    .help("Compression level")
+    .anywhere()
+}
+ 
+fn main() {
+    let opts = compression().to_options().run();
+ 
+    println!("{:?}", opts);
+}
+

 

+ + + + +
+

← Implementing cargo commands

+
+

↑ Parsing cookbook ↑

+
+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/_09_numeric_flags/sidebar-items.js b/bpaf/_documentation/_3_cookbook/_09_numeric_flags/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/_09_numeric_flags/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/index.html b/bpaf/_documentation/_3_cookbook/index.html new file mode 100644 index 00000000..749ecbb0 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/index.html @@ -0,0 +1,44 @@ +bpaf::_documentation::_3_cookbook - Rust +
Expand description

Modules§

\ No newline at end of file diff --git a/bpaf/_documentation/_3_cookbook/sidebar-items.js b/bpaf/_documentation/_3_cookbook/sidebar-items.js new file mode 100644 index 00000000..274c1eb1 --- /dev/null +++ b/bpaf/_documentation/_3_cookbook/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["_00_find","_01_dd","_02_xorg","_03_command_chaining","_04_multi_value","_05_struct_groups","_06_multi_flag","_07_skip_positional","_08_cargo_helper","_09_numeric_flags"]}; \ No newline at end of file diff --git a/bpaf/_documentation/_4_explanation/index.html b/bpaf/_documentation/_4_explanation/index.html new file mode 100644 index 00000000..da2c5a59 --- /dev/null +++ b/bpaf/_documentation/_4_explanation/index.html @@ -0,0 +1,228 @@ +bpaf::_documentation::_4_explanation - Rust +
Expand description

 

+ + + + +
+

← Parsing cookbook

+
+

↑ Project documentation ↑

+
+
+
§Theory explanation
+

Theoretical information about abstractions used by the library, oriented for understanding

+

§Applicative functors, Category Theory? What is it about?

+

You don’t need to read/understand this chapter in order to use the library but it might +help to understand what makes it tick.

+

bpaf uses ideas from functional proggramming, specifically Functor, Applicative and +Alternative to create a composable interface. Exposed API and the fact that individual +components obey certain laws ensures that any composition of parsers is valid even if it +doesn’t make any sense.

+

§Category theory

+

Category theory, also called Abstract Nonsense, is a general theory about mathematical +structures and their relations. Category in CT constists of two sorts of abstractions: +objects and morphisms along with some extra rules:

+
    +
  • objects don’t expose any information other than the name and only serve as start and end points for morphisms
  • +
  • morphisms must compose with associative composition
  • +
  • there must be an identity morphism for every object that maps the object to itself
  • +
+

A simple example of a category would be a category where objects are Rust types (here: u8 .. +u64) and morphisms are functions between those types (here: a, b and c):

+ +
fn a(i: u8) -> u16 {
+    3000 + i as u16
+}
+ 
+fn b(i: u16) -> u32 {
+    40000 + i as u32
+}
+ 
+fn c(i: u32) -> u64 {
+    40000 + i as u64
+}
+ 
+/// Identity morphism
+fn id<T>(i: T) -> T {
+    i
+}
+ 
+/// morphism composition:
+/// `comp (a, comp(b, c))` gives the same results as `comp(comp(a, b), c)`
+fn comp<F, G, A, B, C>(f: F, g: G) -> impl Fn(A) -> C
+where
+    F: Fn(A) -> B,
+    G: Fn(B) -> C,
+{
+    move |i| g(f(i))
+}
+

§Composition and decomposition

+

Decomposition is one of the keys to solving big problems - you break down big problem into a +bunch of small problems, solve them separately and compose back a solution. Decomposition is +not required by computers but makes it easier to think about a problem: magical number for +human short term memory is 7 plus minus 2 objects. Category theory, studies relations and +composition can be a valuable tool: after all decomposition only makes sense when you can +combine components back into a solution. Imperative algorithms that operate in terms of +mutating variables are harder decompose - individual pieces need to be aware of the variables, +functional and declarative approaches make it easier: calculating a sum of all the numbers in a +vector can be decomposed into running an iterator over it and applying fold to it: fold +doesn’t need to know about iteration shape, iterator doesn’t need to know about how values are +used.

+

In category theory you are not allowed to look inside the objects at all and can distinguish +between them only by means of the composition so as long as implemented API obeys the +restrictions set by category theory - it should be very composable.

+

§Functors

+

Let’s start by talking about what a Functor is. Wikipedia defines it as a “design pattern +that allows for a generic type to apply a function inside without changing the structure of +the generic type”. Sounds scary, but in Rust terms it’s a trait that takes a value or values +in a container (or more general value in a context ) such as Option<A> and a function +fn(A) -> B and gives you Option<B> back.

+

Closest analogy in a real code you can write in Rust right now would be modifying an Option +using only Option::map:

+ +
fn plus_one(input: Option<u32>) -> Option<u32> {
+    input.map(|i| i + 1)
+}
+ 
+let present = Some(10);
+let absent = None;
+ 
+assert_eq!(plus_one(present), Some(11));
+assert_eq!(plus_one(absent), None);
+

Vec, Result and other types that implement map are Functors as well, but Functor +is not limited just to containers - you don’t have to have a value inside to be able to +manipulate it. In fact a regular rust function is also a Functor if you squint hard enough. +Consider Reader that allows you to perform transformations on a value in a context T +without having any value until it the execution time:

+ +
struct Reader<T>(Box<dyn Fn(T) -> T>);
+impl<T: 'static> Reader<T> {
+    /// Initialize an new value in a context
+    fn new() -> Self {
+        Self(Box::new(|x| x))
+    }
+ 
+    /// Modify a value in a context
+    fn map<F:  Fn(T) -> T + 'static>(self, f: F) -> Self {
+        Self(Box::new(move |x| f((self.0)(x))))
+    }
+ 
+    /// Apply the changes by giving it the initial value
+    fn run(self, input: T) -> T {
+        (self.0)(input)
+    }
+}
+ 
+let val = Reader::<u32>::new();
+let val = val.map(|x| x + 1);
+let res = val.run(10);
+assert_eq!(res, 11);
+

Not all the collections are Functors - by Functor laws mapping the value in context +shouldn’t change the shape so any collections where shape depends on a value, such as HashSet +or BTreeSet are out.

+

§Applicative Functors

+

map in Functor is limited to a single value in a context, Applicative Functor extends it +to operations combining multiple values, closest Rust analogy would be doing computations on +Option or Result using only ?, having Some/Ok around the whole expression and not using return.

+ +
fn add_numbers(input_a: Option<u32>, input_b: Option<u32>) -> Option<u32> {
+    Some(input_a? + input_b?)
+}
+ 
+let present_1 = Some(10);
+let present_2 = Some(20);
+let absent = None;
+ 
+assert_eq!(add_numbers(present_1, present_2), Some(30));
+assert_eq!(add_numbers(present_1, absent), None);
+assert_eq!(add_numbers(absent, absent), None);
+

Similarly to Functors, Applicative Functors are not limited to containers and can +represent a value in an arbitrary context.

+

Try trait (?) for Option and Result short circuits when it finds a missing value, +but Applicative Functors in general don’t have to - in fact to implement dynamic completion +bpaf needs to check items past the first failure point to collect all the possible +completions.

+

§Alternative Functors

+

So far Applicative Functors allow us to create structs containing multiple fields out of +individual parsers for each field. Alternative extends Applicative with two extra +things: one for combining two values in a context into one and and an idenity element +for this operation. In Rust a closest analogy would be Option::or and Option::None:

+ +
fn pick_number(a: Option<u32>, b: Option<u32>) -> Option<u32> {
+    a.or(b)
+}
+ 
+let present_1 = Some(10);
+let present_2 = Some(20);
+let empty = None;
+assert_eq!(pick_number(present_1, present_2), present_1);
+assert_eq!(pick_number(present_1, empty), present_1);
+assert_eq!(pick_number(empty, present_1), present_1);
+assert_eq!(pick_number(empty, empty), empty);
+

§Parser trait and construct! macro

+

Parser trait defines a context for values and gives access to Functor laws and construct! +macro allows to compose several values according to Applicative and Alternative laws.

+

§So why use Applicative Functors then?

+

As a user I want to be able to express requirements using full power of Rust algebraic +datatypes: struct for product types and enum for sum types. To give an example - +cargo-show-asm asks user to specify what to output - Intel or AT&T asm, LLVM or Rust’s MIR +and opts to represent it as one of four flags: --intel, --att, --llvm and --mir. While +each flag can be though of a boolean value - present/absent - consuming it as an enum with four +possible values is much more convenient compared to a struct-like thing that can have any +combination of the flags inside:

+
/// Format selection as enum - program needs to deal with just one format
+enum Format {
+    Intel,
+    Att,
+    Llvm,
+    Mir
+}
+ 
+/// Format selection as struct - can represent any possible combination of formats
+struct Formats {
+    intel: bool,
+    att: bool,
+    llvm: bool,
+    mir: bool,
+}
+
+

Applicative interface gives just enough power to compose simple parsers as an arbitrary tree +ready for consumption.

+

As a library author I need to be able to extract information from the tree constructed by user +to generate --help information and do command line completion. As long as the tree uses only +Applicative powers - it is possible to evaluate it without giving it any input. +Adding Monadic powers (deciding what to parse next depending on the previous input) would +make this impossible.

+

So Applicative Functors sits right in the middle between what users want to express and +library can consume.

+

To recap - all sorts of Functors listed here only define laws to how individual parts are +composed, how values in context can be transformed and how pure values can be turned into a +functor, but not how the values are parsed or how they can be extracted.

+

§Putting the values into a context

+

Similarly to how Reader defined above bpaf’s Parsers don’t actually have values inside +until they are executed. Instead starting points (flag, positional, +argument, etc) define what exactly needs to be consumed, various mapping +functions define transformations, construct! composes them and defines the relative order +values should be consumed. Not everything present inside Parser can be repesented in terms +of plain applicative functors - specifically parse is not and it is best +though of as a function that takes one applicative and gives a different applicative back. +The actual values will show up inside once bpaf starts running the OptionParser with +run.

+

§Taking the results out

+

The rest of the execution is relatively simple: getting console arguments from OS, doing the +initial split into short/long flags and standalone words, disambiguating groups of short +options from short options with attached values and applying all the transformations like +Reader::run above would do.

+

 

+ + + + +
+

← Parsing cookbook

+
+

↑ Project documentation ↑

+
+
+
\ No newline at end of file diff --git a/bpaf/_documentation/_4_explanation/sidebar-items.js b/bpaf/_documentation/_4_explanation/sidebar-items.js new file mode 100644 index 00000000..5244ce01 --- /dev/null +++ b/bpaf/_documentation/_4_explanation/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/bpaf/_documentation/index.html b/bpaf/_documentation/index.html new file mode 100644 index 00000000..0f46ef94 --- /dev/null +++ b/bpaf/_documentation/index.html @@ -0,0 +1,11 @@ +bpaf::_documentation - Rust +

Module bpaf::_documentation

source ·
Expand description
§Project documentation
+

See official website for more up to date version.

+ +

Modules§

\ No newline at end of file diff --git a/bpaf/_documentation/sidebar-items.js b/bpaf/_documentation/sidebar-items.js new file mode 100644 index 00000000..fffeb6f4 --- /dev/null +++ b/bpaf/_documentation/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":["_0_intro","_1_tutorials","_2_howto","_3_cookbook","_4_explanation"]}; \ No newline at end of file diff --git a/bpaf/all.html b/bpaf/all.html new file mode 100644 index 00000000..8c9553f7 --- /dev/null +++ b/bpaf/all.html @@ -0,0 +1,2 @@ +List of all items in this crate +

List of all items

Structs

Enums

Traits

Macros

Derive Macros

Functions

\ No newline at end of file diff --git a/bpaf/args/struct.Args.html b/bpaf/args/struct.Args.html new file mode 100644 index 00000000..b80a000b --- /dev/null +++ b/bpaf/args/struct.Args.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/struct.Args.html...

+ + + \ No newline at end of file diff --git a/bpaf/batteries/fn.cargo_helper.html b/bpaf/batteries/fn.cargo_helper.html new file mode 100644 index 00000000..a6cbcad4 --- /dev/null +++ b/bpaf/batteries/fn.cargo_helper.html @@ -0,0 +1,97 @@ +cargo_helper in bpaf::batteries - Rust +

Function bpaf::batteries::cargo_helper

source ·
pub fn cargo_helper<P, T>(cmd: &'static str, parser: P) -> impl Parser<T>
where + P: Parser<T>,
Expand description

Strip a command name if present at the front when used as a cargo command

+

When implementing a cargo subcommand parser needs to be able to skip the first argument which +is always the same as the executable name without cargo- prefix. For example if executable name is +cargo-cmd so first argument would be cmd. cargo_helper helps to support both invocations: +with name present when used via cargo and without it when used locally.

+

You can read the code of this function as this approximate sequence of statements:

+
    +
  1. Try to parse a string literal that corresponds to a command name
  2. +
  3. It’s okay if it’s missing
  4. +
  5. And don’t show anything to the user in --help or completion
  6. +
  7. Parse this word and then everything else as a tuple, return that second item.
  8. +
+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    argument: usize,
+    switch: bool,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = long("argument")
+        .help("An argument")
+        .argument::<usize>("ARG");
+    let switch = short('s').help("A switch").switch();
+    let options = construct!(Options { argument, switch });
+
+    // Given the cargo command is `cargo pretty`.
+    cargo_helper("pretty", options).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options("pretty"))] // Given the cargo command is `cargo pretty`.
+pub struct Options {
+    /// An argument
+    argument: usize,
+    /// A switch
+    #[bpaf(short)]
+    switch: bool,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Let’s say the goal is to parse an argument and a switch:

+
+$ app --argument 15
+Options { argument: 15, switch: false } +
+

But when used as a cargo subcommand, cargo will also pass the command name. For example +you can invoke an app with binary name cargo-asm

+
$ cargo asm --lib --everything
+...
+
+

cargo will then spawn the executable and pass it following parameters:

+
$ cargo-asm asm --lib --everything
+...
+
+

If you are not using cargo_helper - parser won’t know what to do with asm part. +cargo-helper allows the parser to strip it from the front and everything works as expected.

+

And it doesn’t show up in --help so not to confuse users

+
+$ app --help
+

Usage: app --argument=ARG [-s]

+Available options:
--argument=ARG
+
An argument
+
-s
+
A switch
+
-h, --help
+
Prints help information
+
+

+ +
+
+
\ No newline at end of file diff --git a/bpaf/batteries/fn.get_usage.html b/bpaf/batteries/fn.get_usage.html new file mode 100644 index 00000000..08baf824 --- /dev/null +++ b/bpaf/batteries/fn.get_usage.html @@ -0,0 +1,15 @@ +get_usage in bpaf::batteries - Rust +

Function bpaf::batteries::get_usage

source ·
pub fn get_usage<T>(parser: OptionParser<T>) -> String
where + T: Debug,
Expand description

Get usage for a parser

+

In some cases you might want to print usage if user gave no command line options, in this case +you should add an enum variant to a top level enum, make it hidden with #[bpaf(hide)], make +it default for the top level parser with something like #[bpaf(fallback(Arg::Help))].

+

When handling cases you can do something like this for Help variant:

+ +
    ...
+    Arg::Help => {
+        println!("{}", get_usage(parser()));
+        std::process::exit(0);
+    }
+    ...
+
\ No newline at end of file diff --git a/bpaf/batteries/fn.toggle_flag.html b/bpaf/batteries/fn.toggle_flag.html new file mode 100644 index 00000000..c2369429 --- /dev/null +++ b/bpaf/batteries/fn.toggle_flag.html @@ -0,0 +1,32 @@ +toggle_flag in bpaf::batteries - Rust +

Function bpaf::batteries::toggle_flag

source ·
pub fn toggle_flag<T: Copy + 'static>(
+    a: NamedArg,
+    val_a: T,
+    b: NamedArg,
+    val_b: T
+) -> impl Parser<Option<T>>
Expand description

Pick last passed value between two different flags

+

Usually bpaf only allows to parse a single instance for every invocation unless +you specify many or some. toggle_flag would consume +multiple instances of two different flags and returns last specified value.

+

This function relies on a fact that selection between two different parsers prefers left most +value. This helps to preserve relative order of parsrs. +You can use similar approach to combine multiple flags accounting for their relative order.

+

Parser returns Optional<T> value, you can add a fallback with map or turn +missing value info failure with a custom error message with parse.

+

§Example

$ app --banana --no-banana --banana --banana
+Some(Banana)
+$ app
+None
+

§Usage

+
use bpaf::batteries::toggle_flag;
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum Select {
+    Banana,
+    NoBanana,
+}
+
+fn pick() -> impl Parser<Option<Select>> {
+    toggle_flag(long("banana"), Select::Banana, long("no-banana"), Select::NoBanana)
+}
+
\ No newline at end of file diff --git a/bpaf/batteries/fn.verbose_and_quiet_by_number.html b/bpaf/batteries/fn.verbose_and_quiet_by_number.html new file mode 100644 index 00000000..f9e604c0 --- /dev/null +++ b/bpaf/batteries/fn.verbose_and_quiet_by_number.html @@ -0,0 +1,14 @@ +verbose_and_quiet_by_number in bpaf::batteries - Rust +
pub fn verbose_and_quiet_by_number(
+    offset: isize,
+    min: isize,
+    max: isize
+) -> impl Parser<isize>
Expand description

--verbose and --quiet flags with results encoded as number

+

Parameters specify the offset and minimal/maximal values. Parser accepts many -v | --verbose and +-q | --quiet to increase and decrease verbosity respectively

+

§Usage

+
use bpaf::batteries::*;
+fn verbose() -> impl Parser<usize> {
+    verbose_and_quiet_by_number(2, 0, 5).map(|v| v as usize)
+}
+
\ No newline at end of file diff --git a/bpaf/batteries/fn.verbose_by_slice.html b/bpaf/batteries/fn.verbose_by_slice.html new file mode 100644 index 00000000..5d6d95db --- /dev/null +++ b/bpaf/batteries/fn.verbose_by_slice.html @@ -0,0 +1,23 @@ +verbose_by_slice in bpaf::batteries - Rust +
pub fn verbose_by_slice<T: Copy + 'static, const N: usize>(
+    offset: usize,
+    items: [T; N]
+) -> impl Parser<T>
Expand description

--verbose and --quiet flags with results choosen from a slice of values

+

Parameters specify an array of possible values and a default index

+

§Usage

+
use bpaf::batteries::*;
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+enum Level {
+   Error,
+   Warning,
+   Info,
+   Debug,
+   Trace,
+}
+
+fn verbose() -> impl Parser<Level> {
+    use Level::*;
+    verbose_by_slice(2, [Error, Warning, Info, Debug, Trace])
+}
+
\ No newline at end of file diff --git a/bpaf/batteries/index.html b/bpaf/batteries/index.html new file mode 100644 index 00000000..b6cbf8ac --- /dev/null +++ b/bpaf/batteries/index.html @@ -0,0 +1,8 @@ +bpaf::batteries - Rust +

Module bpaf::batteries

source ·
Expand description

§Batteries included - helpful parsers that use only public API

+

bpaf comes with a few extra functions that use only public API in their implementation. You +might find them useful either for your code or as an inspiration source

+

To use anything in this module you need to enable batteries cargo feature.

+

Examples contain combinatoric usage, for derive usage you should create a parser function and +use external annotation.

+

Functions§

\ No newline at end of file diff --git a/bpaf/batteries/sidebar-items.js b/bpaf/batteries/sidebar-items.js new file mode 100644 index 00000000..23c74498 --- /dev/null +++ b/bpaf/batteries/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["cargo_helper","get_usage","toggle_flag","verbose_and_quiet_by_number","verbose_by_slice"]}; \ No newline at end of file diff --git a/bpaf/buffer/enum.Style.html b/bpaf/buffer/enum.Style.html new file mode 100644 index 00000000..e7775e45 --- /dev/null +++ b/bpaf/buffer/enum.Style.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/doc/enum.Style.html...

+ + + \ No newline at end of file diff --git a/bpaf/buffer/manpage/enum.Section.html b/bpaf/buffer/manpage/enum.Section.html new file mode 100644 index 00000000..80efcdec --- /dev/null +++ b/bpaf/buffer/manpage/enum.Section.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../bpaf/doc/enum.Section.html...

+ + + \ No newline at end of file diff --git a/bpaf/buffer/struct.Doc.html b/bpaf/buffer/struct.Doc.html new file mode 100644 index 00000000..e659f0f4 --- /dev/null +++ b/bpaf/buffer/struct.Doc.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/doc/struct.Doc.html...

+ + + \ No newline at end of file diff --git a/bpaf/buffer/struct.MetaInfo.html b/bpaf/buffer/struct.MetaInfo.html new file mode 100644 index 00000000..f73752d5 --- /dev/null +++ b/bpaf/buffer/struct.MetaInfo.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/doc/struct.MetaInfo.html...

+ + + \ No newline at end of file diff --git a/bpaf/complete_shell/enum.ShellComp.html b/bpaf/complete_shell/enum.ShellComp.html new file mode 100644 index 00000000..84d24e7b --- /dev/null +++ b/bpaf/complete_shell/enum.ShellComp.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/enum.ShellComp.html...

+ + + \ No newline at end of file diff --git a/bpaf/complete_shell/struct.ParseCompShell.html b/bpaf/complete_shell/struct.ParseCompShell.html new file mode 100644 index 00000000..2e57fdda --- /dev/null +++ b/bpaf/complete_shell/struct.ParseCompShell.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/parsers/struct.ParseCompShell.html...

+ + + \ No newline at end of file diff --git a/bpaf/derive.Bpaf.html b/bpaf/derive.Bpaf.html new file mode 100644 index 00000000..1735f4a6 --- /dev/null +++ b/bpaf/derive.Bpaf.html @@ -0,0 +1,9 @@ +Bpaf in bpaf - Rust +

Derive Macro bpaf::Bpaf

#[derive(Bpaf)]
+{
+    // Attributes available to this derive:
+    #[bpaf]
+}
+
Expand description

Derive macro for bpaf command line parser

+

For documentation refer to bpaf library: https://docs.rs/bpaf/latest/bpaf/

+
\ No newline at end of file diff --git a/bpaf/doc/enum.Section.html b/bpaf/doc/enum.Section.html new file mode 100644 index 00000000..8adda28f --- /dev/null +++ b/bpaf/doc/enum.Section.html @@ -0,0 +1,45 @@ +Section in bpaf::doc - Rust +

Enum bpaf::doc::Section

source ·
pub enum Section<'a> {
+    General,
+    SystemCall,
+    LibraryFunction,
+    SpecialFile,
+    FileFormat,
+    Game,
+    Misc,
+    Sysadmin,
+    Custom(&'a str),
+}
Expand description

Manual page section

+

Variants§

§

General

General commands

+
§

SystemCall

System calls

+
§

LibraryFunction

Library functions such as C standard library functions

+
§

SpecialFile

Special files (usually devices in /dev) and drivers

+
§

FileFormat

File formats and conventions

+
§

Game

Games and screensavers

+
§

Misc

Miscellaneous

+
§

Sysadmin

System administration commands and daemons

+
§

Custom(&'a str)

Custom section

+

Trait Implementations§

source§

impl<'a> Clone for Section<'a>

source§

fn clone(&self) -> Section<'a>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<'a> Debug for Section<'a>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'a> Copy for Section<'a>

Auto Trait Implementations§

§

impl<'a> RefUnwindSafe for Section<'a>

§

impl<'a> Send for Section<'a>

§

impl<'a> Sync for Section<'a>

§

impl<'a> Unpin for Section<'a>

§

impl<'a> UnwindSafe for Section<'a>

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/doc/enum.Style.html b/bpaf/doc/enum.Style.html new file mode 100644 index 00000000..08f354a9 --- /dev/null +++ b/bpaf/doc/enum.Style.html @@ -0,0 +1,39 @@ +Style in bpaf::doc - Rust +

Enum bpaf::doc::Style

source ·
#[non_exhaustive]
pub enum Style { + Text, + Emphasis, + Literal, + Metavar, + Invalid, +}
Expand description

Style of a text fragment inside of Doc

+

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Text

Plain text, no decorations

+
§

Emphasis

Word with emphasis - things like “Usage”, “Available options”, etc

+
§

Literal

Something user needs to type literally - command names, etc

+
§

Metavar

Metavavar placeholder - something user needs to replace with own input

+
§

Invalid

Invalid input given by user - used to display invalid parts of the input

+

Trait Implementations§

source§

impl Clone for Style

source§

fn clone(&self) -> Style

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Style

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl PartialEq for Style

source§

fn eq(&self, other: &Style) -> bool

This method tests for self and other values to be equal, and is used +by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason.
source§

impl Copy for Style

source§

impl Eq for Style

source§

impl StructuralPartialEq for Style

Auto Trait Implementations§

§

impl RefUnwindSafe for Style

§

impl Send for Style

§

impl Sync for Style

§

impl Unpin for Style

§

impl UnwindSafe for Style

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/doc/index.html b/bpaf/doc/index.html new file mode 100644 index 00000000..cf0c3b88 --- /dev/null +++ b/bpaf/doc/index.html @@ -0,0 +1,111 @@ +bpaf::doc - Rust +

Module bpaf::doc

source ·
Expand description

Documentation generation system

+

§Command line parser documentation generation

+

OptionParser implements two methods: render_html and +render_manpage that create a documentation in a mix of +html/markdown and ROFF formats respectively.

+

To use it you should do something like this

+ +
#[test]
+fn update_doc() {
+    let options = options();
+    let md = options.render_markdown("app_name");
+    let roff = options.render_manpage("app_name", Section::General, None, None, None);
+    // then save those docs into a files
+    // If you commit those docs into your repo and optionally fail a test if there
+    // are changes - CI will ensure that documentation is always up to date
+}
+

§Documentation fragments to use inside --help messages

+

bpaf tries to use semantic approach to documentation generation, instead of describing what +color specific string slice should be you need to specify what this string slice supposed to +mean.

+

Most of the help related functions take Into<Doc> parameters, normally you would pass one of +following things:

+
    +
  1. Ready made Doc - usually with combinatoric API
  2. +
+ +
let mut doc = Doc::default();
+doc.emphasis("Usage: ");
+doc.literal("my_program");
+// do something with it
+drop(doc)
+
    +
  1. +

    A string slice - &str can be converted into a fully plain text Doc which is enough +for most applications

    +
  2. +
  3. +

    A slice of style value pairs

    +
  4. +
+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    number: u32,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let number = long("number")
+        .help(
+            &[
+                ("Very", Style::Emphasis),
+                (" important argument", Style::Text),
+            ][..],
+        )
+        .argument::<u32>("N");
+    construct!(Options { number }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +

+const ARG: &[(&str, Style)] = &[
+    ("Very", Style::Emphasis),
+    (" important argument", Style::Text),
+];
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(argument("N"), help(ARG))]
+    number: u32,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +
+$ app --help
+

Usage: app --number=N

+Available options:
--number=N
+
Very important argument
+
-h, --help
+
Prints help information
+
+

+ +
+
+
    +
  1. A structure from your own crate that can be converted into Doc
  2. +
+

Structs§

  • String with styled segments.
  • Parser metainformation

Enums§

\ No newline at end of file diff --git a/bpaf/doc/sidebar-items.js b/bpaf/doc/sidebar-items.js new file mode 100644 index 00000000..e4d3e5be --- /dev/null +++ b/bpaf/doc/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["Section","Style"],"struct":["Doc","MetaInfo"]}; \ No newline at end of file diff --git a/bpaf/doc/struct.Doc.html b/bpaf/doc/struct.Doc.html new file mode 100644 index 00000000..5b088dc7 --- /dev/null +++ b/bpaf/doc/struct.Doc.html @@ -0,0 +1,48 @@ +Doc in bpaf::doc - Rust +

Struct bpaf::doc::Doc

source ·
pub struct Doc { /* private fields */ }
Expand description

String with styled segments.

+

You can add style information to generated documentation and help messages +For simpliest possible results you can also pass a string slice in all the places +that require impl Into<Doc>

+

Implementations§

source§

impl Doc

source

pub fn monochrome(&self, full: bool) -> String

Render a monochrome version of the document

+

full indicates if full message should be rendered, this makes +difference for rendered help message, otherwise you can pass true.

+
source§

impl Doc

source

pub fn render_markdown(&self, full: bool) -> String

Render doc into markdown document, used by documentation sample generator

+
source§

impl Doc

source

pub fn text(&mut self, text: &str)

Append a fragment of plain text to Doc

+

See Doc for usage examples

+
source

pub fn literal(&mut self, text: &str)

Append a fragment of literal text to Doc

+

See Doc for usage examples

+
source

pub fn emphasis(&mut self, text: &str)

Append a fragment of text with emphasis to Doc

+

See Doc for usage examples

+
source

pub fn invalid(&mut self, text: &str)

Append a fragment of unexpected user input to Doc

+

See Doc for usage examples

+
source

pub fn meta(&mut self, meta: MetaInfo<'_>, for_usage: bool)

Append a fragment of parser metadata to Doc

+

See Doc for usage examples

+
source

pub fn doc(&mut self, buf: &Doc)

Append a Doc to Doc

+

See Doc for usage examples

+
source

pub fn em_doc(&mut self, buf: &Doc)

Append a Doc to Doc for plaintext documents try to format +first line as a help section header

+

Trait Implementations§

source§

impl Clone for Doc

source§

fn clone(&self) -> Doc

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Doc

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for Doc

source§

fn default() -> Doc

Returns the “default value” for a type. Read more
source§

impl Display for Doc

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<&[(&str, Style)]> for Doc

source§

fn from(val: &[(&str, Style)]) -> Self

Converts to this type from the input type.
source§

impl<const N: usize> From<&'static [(&'static str, Style); N]> for Doc

source§

fn from(val: &'static [(&'static str, Style); N]) -> Self

Converts to this type from the input type.
source§

impl From<&str> for Doc

source§

fn from(value: &str) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl RefUnwindSafe for Doc

§

impl Send for Doc

§

impl Sync for Doc

§

impl Unpin for Doc

§

impl UnwindSafe for Doc

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/doc/struct.MetaInfo.html b/bpaf/doc/struct.MetaInfo.html new file mode 100644 index 00000000..80b3833e --- /dev/null +++ b/bpaf/doc/struct.MetaInfo.html @@ -0,0 +1,29 @@ +MetaInfo in bpaf::doc - Rust +

Struct bpaf::doc::MetaInfo

source ·
pub struct MetaInfo<'a>(/* private fields */);
Expand description

Parser metainformation

+

This is a newtype around internal parser metainfo representation, generated +with Parser::with_group_help and consumed by +Doc::meta

+

Trait Implementations§

source§

impl<'a> Clone for MetaInfo<'a>

source§

fn clone(&self) -> MetaInfo<'a>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<'a> Copy for MetaInfo<'a>

Auto Trait Implementations§

§

impl<'a> RefUnwindSafe for MetaInfo<'a>

§

impl<'a> Send for MetaInfo<'a>

§

impl<'a> Sync for MetaInfo<'a>

§

impl<'a> Unpin for MetaInfo<'a>

§

impl<'a> UnwindSafe for MetaInfo<'a>

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/enum.ParseFailure.html b/bpaf/enum.ParseFailure.html new file mode 100644 index 00000000..641f9359 --- /dev/null +++ b/bpaf/enum.ParseFailure.html @@ -0,0 +1,56 @@ +ParseFailure in bpaf - Rust +

Enum bpaf::ParseFailure

source ·
pub enum ParseFailure {
+    Stdout(Doc, bool),
+    Completion(String),
+    Stderr(Doc),
+}
Expand description

Unsuccessful command line parsing outcome, use it for unit tests

+

When OptionParser::run_inner produces Err(ParseFailure) +it means that the parser couldn’t produce the value it supposed to produce and the program +should terminate.

+

If you are handling variants manually - Stdout contains formatted output and you can use any +logging framework to produce the output, Completion should be printed to stdout unchanged - +shell completion mechanism relies on that. In both cases application should exit with error +code of 0. Stderr variant indicates a genuinly parsing error which should be printed to +stderr or a logging framework of your choice as an error and the app should exit with error +code of 1. ParseFailure::exit_code is a helper method that performs printing and produces +the exit code to use.

+

For purposes of for unit testing for user parsers, you can consume it with +ParseFailure::unwrap_stdout and ParseFailure::unwrap_stdout - both of which produce a +an unformatted String that parser might produce if failure type is correct or panics +otherwise.

+

Variants§

§

Stdout(Doc, bool)

Print this to stdout and exit with success code

+
§

Completion(String)

This also goes to stdout with exit code of 0, +this cannot be Doc because completion needs more control about rendering

+
§

Stderr(Doc)

Print this to stderr and exit with failure code

+

Implementations§

source§

impl ParseFailure

source

pub fn unwrap_stderr(self) -> String

Returns the contained stderr values - for unit tests

+
§Panics
+

Panics if failure contains stdout

+
source

pub fn unwrap_stdout(self) -> String

Returns the contained stdout values - for unit tests

+
§Panics
+

Panics if failure contains stderr

+
source

pub fn exit_code(self) -> i32

Returns the exit code for the failure

+
source

pub fn print_mesage(&self, max_width: usize)

Prints a message to stdout or stderr appropriate to the failure.

+

Trait Implementations§

source§

impl Clone for ParseFailure

source§

fn clone(&self) -> ParseFailure

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for ParseFailure

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/enum.ShellComp.html b/bpaf/enum.ShellComp.html new file mode 100644 index 00000000..10ce2fc8 --- /dev/null +++ b/bpaf/enum.ShellComp.html @@ -0,0 +1,61 @@ +ShellComp in bpaf - Rust +

Enum bpaf::ShellComp

source ·
#[non_exhaustive]
pub enum ShellComp { + File { + mask: Option<&'static str>, + }, + Dir { + mask: Option<&'static str>, + }, + Raw { + bash: &'static str, + zsh: &'static str, + fish: &'static str, + elvish: &'static str, + }, + Nothing, +}
Expand description

Shell specific completion

+

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

File

Fields

§mask: Option<&'static str>

Optional filemask to use, no spaces, no tabs

+

A file or directory name with an optional file mask.

+

For bash filemask should start with *. or contain only the +extension

+
§

Dir

Fields

§mask: Option<&'static str>

Optional filemask to use, no spaces, no tabs

+

Similar to File but limited to directories only +For bash filemask should start with *. or contain only the +extension

+
§

Raw

Fields

§bash: &'static str
§zsh: &'static str

This raw string will be used for zsh shell +https://zsh.sourceforge.io/Doc/Release/Completion-System.html

+
§fish: &'static str

This raw string will be used for fish shell +https://fishshell.com/docs/current/completions.html

+
§elvish: &'static str

This raw string will be used for elvish shell +https://elv.sh/ref/edit.html#completion-api

+

You can also specify a raw value to use for each supported shell

+

It is possible to fill in values for shells you don’t want to support +with empty strings but the code is not going to work for those shells

+
§

Nothing

Don’t produce anything at all from this parser - can be useful if you want to compose +bpaf completion with shell completion

+

Trait Implementations§

source§

impl Clone for ShellComp

source§

fn clone(&self) -> ShellComp

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for ShellComp

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Copy for ShellComp

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/error/enum.ParseFailure.html b/bpaf/error/enum.ParseFailure.html new file mode 100644 index 00000000..bb8ef3ae --- /dev/null +++ b/bpaf/error/enum.ParseFailure.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/enum.ParseFailure.html...

+ + + \ No newline at end of file diff --git a/bpaf/fn.any.html b/bpaf/fn.any.html new file mode 100644 index 00000000..3a7fb039 --- /dev/null +++ b/bpaf/fn.any.html @@ -0,0 +1,495 @@ +any in bpaf - Rust +

Function bpaf::any

source ·
pub fn any<I, T, F>(metavar: &str, check: F) -> ParseAny<T>
where + I: FromStr + 'static, + F: Fn(I) -> Option<T> + 'static, + <I as FromStr>::Err: Display,
Expand description

Parse a single arbitrary item from a command line

+

any is designed to consume items that don’t fit into the usual flag +/switch/argument/positional/ +command classification, in most cases you don’t need to use it

+

By default, any behaves similarly to positional so you should be using it near the +rightmost end of the consumer struct and it will only try to parse the first unconsumed item +on the command line. It is possible to lift this restriction by calling +anywhere on the parser.

+

check argument is a function from any type I that implements FromStr to T. +Usually this should be String or OsString, but feel free to experiment. When +running any tries to parse an item on a command line into that I and applies the check +function. If the check succeeds - parser any succeeds and produces T, otherwise it behaves +as if it hasn’t seen it. If any works in anywhere mode - it will try to parse all other +unconsumed items, otherwise, any fails.

+

§Use any to capture the remaining arguments

+

Normally you would use positional with strict annotation for +that, but using any allows you to blur the boundary between arguments for child process and self +process a bit more.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    turbo: bool,
+    rest: Vec<OsString>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let turbo = short('t')
+        .long("turbo")
+        .help("Engage the turbo mode")
+        .switch();
+    let rest = any::<OsString, _, _>("REST", |x| (x != "--help").then_some(x))
+        .help("app will pass anything unused to a child process")
+        .many();
+    construct!(Options { turbo, rest }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long)]
+    /// Engage the turbo mode
+    turbo: bool,
+    #[bpaf(any("REST", not_help), many)]
+    /// app will pass anything unused to a child process
+    rest: Vec<OsString>,
+}
+
+fn not_help(s: OsString) -> Option<OsString> {
+    if s == "--help" {
+        None
+    } else {
+        Some(s)
+    }
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

--help keeps working for as long as any captures only intended values - that is it ignores +--help flag specifically

+
+$ app --help
+

Usage: app [-t] [REST]...

+Available positional items:
REST
+
app will pass anything unused to a child process
+
+

+Available options:
-t, --turbo
+
Engage the turbo mode
+
-h, --help
+
Prints help information
+
+

+ +
+

You can mix any with regular options, here switch turbo works because it goes +before rest in the parser declaration

+
+$ app --turbo git commit -m "hello world"
+Options { turbo: true, rest: ["git", "commit", "-m", "hello world"] } +
+

“before” in the previous line means in the parser definition, not on the user input, here +--turbo gets consumed by turbo parser even the argument goes

+
+$ app git commit -m="hello world" --turbo
+Options { turbo: true, rest: ["git", "commit", "-m=hello world"] } +
+
+$ app -- git commit -m="hello world" --turbo
+Options { turbo: false, rest: ["git", "commit", "-m=hello world", "--turbo"] } +
+
+$ app git commit -m="hello world" -- --turbo
+Options { turbo: false, rest: ["git", "commit", "-m=hello world", "--turbo"] } +
+
+

§Use any to parse a non standard flag

Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    turbo: bool,
+    backing: bool,
+    xinerama: bool,
+}
+
+fn toggle_option(name: &'static str, help: &'static str) -> impl Parser<bool> {
+    // parse +name and -name into a bool
+    any::<String, _, _>(name, move |s: String| {
+        if let Some(rest) = s.strip_prefix('+') {
+            (rest == name).then_some(true)
+        } else if let Some(rest) = s.strip_prefix('-') {
+            (rest == name).then_some(false)
+        } else {
+            None
+        }
+    })
+    // set a custom usage and help metavariable
+    .metavar(
+        &[
+            ("+", Style::Literal),
+            (name, Style::Literal),
+            (" | ", Style::Text),
+            ("-", Style::Literal),
+            (name, Style::Literal),
+        ][..],
+    )
+    // set a custom help description
+    .help(help)
+    // apply this parser to all unconsumed items
+    .anywhere()
+}
+
+pub fn options() -> OptionParser<Options> {
+    let backing = toggle_option("backing", "Enable or disable backing")
+        .fallback(false)
+        .debug_fallback();
+    let xinerama = toggle_option("xinerama", "enable or disable Xinerama")
+        .fallback(true)
+        .debug_fallback();
+    let turbo = short('t')
+        .long("turbo")
+        .help("Engage the turbo mode")
+        .switch();
+    construct!(Options {
+        turbo,
+        backing,
+        xinerama,
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Engage the turbo mode
+    #[bpaf(short, long)]
+    turbo: bool,
+    #[bpaf(external(backing), fallback(false), debug_fallback)]
+    backing: bool,
+    #[bpaf(external(xinerama), fallback(true), debug_fallback)]
+    xinerama: bool,
+}
+
+fn toggle_option(name: &'static str, help: &'static str) -> impl Parser<bool> {
+    // parse +name and -name into a bool
+    any::<String, _, _>(name, move |s: String| {
+        if let Some(rest) = s.strip_prefix('+') {
+            (rest == name).then_some(true)
+        } else if let Some(rest) = s.strip_prefix('-') {
+            (rest == name).then_some(false)
+        } else {
+            None
+        }
+    })
+    // set a custom usage and help metavariable
+    .metavar(
+        &[
+            ("+", Style::Literal),
+            (name, Style::Literal),
+            (" | ", Style::Text),
+            ("-", Style::Literal),
+            (name, Style::Literal),
+        ][..],
+    )
+    // set a custom help description
+    .help(help)
+    // apply this parser to all unconsumed items
+    .anywhere()
+}
+
+fn backing() -> impl Parser<bool> {
+    toggle_option("backing", "Enable or disable backing")
+}
+
+fn xinerama() -> impl Parser<bool> {
+    toggle_option("xinerama", "enable or disable Xinerama")
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

--help message describes all the flags as expected

+
+$ app --help
+

Usage: app [-t] [+backing | -backing] [+xinerama | -xinerama]

+Available options:
-t, --turbo
+
Engage the turbo mode
+
+backing | -backing
+
Enable or disable backing
+
+
[default: false]
+
+xinerama | -xinerama
+
enable or disable Xinerama
+
+
[default: true]
+
-h, --help
+
Prints help information
+
+

+ +
+

Parser obeys the defaults

+
+$ app
+Options { turbo: false, backing: false, xinerama: true } +
+

And can handle custom values

+
+$ app --turbo -xinerama +backing
+Options { turbo: true, backing: true, xinerama: false } +
+

bpaf won’t be able to generate good error messages or suggest to fix typos to users since it +doesn’t really knows what the function inside any is going to consume

+
+$ app --turbo -xinerama +backin
+Error: +backin is not expected in this context + +
+
+

§Use any to parse a non standard argument

+

Normally any would try to display itself as a usual metavariable in the usage line and +generated help, you can customize that with metavar method:

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    block_size: usize,
+    count: usize,
+    output_file: String,
+    turbo: bool,
+}
+
+/// Parses a string that starts with `name`, returns the suffix parsed in a usual way
+fn tag<T>(name: &'static str, meta: &str, help: impl Into<Doc>) -> impl Parser<T>
+where
+    T: FromStr,
+    <T as FromStr>::Err: std::fmt::Display,
+{
+    // closure inside checks if command line argument starts with a given name
+    // and if it is - it accepts it, otherwise it behaves like it never saw it
+    // it is possible to parse OsString here and strip the prefix with
+    // `os_str_bytes` or a similar crate
+    any("", move |s: String| Some(s.strip_prefix(name)?.to_owned()))
+        // this defines custom metavar for the help message
+        // so it looks like something it designed to parse
+        .metavar(&[(name, Style::Literal), (meta, Style::Metavar)][..])
+        .help(help)
+        // this makes it so tag parser tries to read all (unconsumed by earlier parsers)
+        // item on a command line instead of trying and failing on the first one
+        .anywhere()
+        // At this point parser produces `String` while consumer might expect some other
+        // type. [`parse`](Parser::parse) handles that
+        .parse(|s| s.parse())
+}
+
+pub fn options() -> OptionParser<Options> {
+    let block_size = tag("bs=", "BLOCK", "How many bytes to read at once")
+        .fallback(1024)
+        .display_fallback();
+    let count = tag("count=", "NUM", "How many blocks to read").fallback(1);
+    let output_file = tag("of=", "FILE", "Save results into this file");
+
+    // this consumes literal value of "+turbo" locate and produces `bool`
+    let turbo = literal("+turbo")
+        .help("Engage turbo mode!")
+        .anywhere()
+        .map(|_| true)
+        .fallback(false);
+
+    construct!(Options {
+        block_size,
+        count,
+        output_file,
+        turbo
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
// This example is still technically derive API, but derive is limited to gluing
+// things together and keeping macro complexity under control.
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    // `external` here and below derives name from the field name, looking for
+    // functions called `block_size`, `count`, etc that produce parsers of
+    // the right type.
+    // A different way would be to write down the name explicitly:
+    // #[bpaf(external(block_size), fallback(1024), display_fallback)]
+    #[bpaf(external, fallback(1024), display_fallback)]
+    block_size: usize,
+    #[bpaf(external, fallback(1))]
+    count: usize,
+    #[bpaf(external)]
+    output_file: String,
+    #[bpaf(external)]
+    turbo: bool,
+}
+
+fn block_size() -> impl Parser<usize> {
+    tag("bs=", "BLOCK", "How many bytes to read at once")
+}
+
+fn count() -> impl Parser<usize> {
+    tag("count=", "NUM", "How many blocks to read")
+}
+
+fn output_file() -> impl Parser<String> {
+    tag("of=", "FILE", "Save results into this file")
+}
+
+fn turbo() -> impl Parser<bool> {
+    literal("+turbo")
+        .help("Engage turbo mode!")
+        .anywhere()
+        .map(|_| true)
+        .fallback(false)
+}
+
+/// Parses a string that starts with `name`, returns the suffix parsed in a usual way
+fn tag<T>(name: &'static str, meta: &str, help: impl Into<Doc>) -> impl Parser<T>
+where
+    T: FromStr,
+    <T as FromStr>::Err: std::fmt::Display,
+{
+    // closure inside checks if command line argument starts with a given name
+    // and if it is - it accepts it, otherwise it behaves like it never saw it
+    // it is possible to parse OsString here and strip the prefix with
+    // `os_str_bytes` or a similar crate
+    any("", move |s: String| Some(s.strip_prefix(name)?.to_owned()))
+        // this defines custom metavar for the help message
+        // so it looks like something it designed to parse
+        .metavar(&[(name, Style::Literal), (meta, Style::Metavar)][..])
+        .help(help)
+        // this makes it so tag parser tries to read all (unconsumed by earlier parsers)
+        // item on a command line instead of trying and failing on the first one
+        .anywhere()
+        // At this point parser produces `String` while consumer might expect some other
+        // type. [`parse`](Parser::parse) handles that
+        .parse(|s| s.parse())
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Instead of usual metavariable any parsers take something that can represent any value

+
+$ app --help
+

Usage: app [bs=BLOCK] [count=NUM] of=FILE [+turbo]

+Available options:
bs=BLOCK
+
How many bytes to read at once
+
+
[default: 1024]
+
count=NUM
+
How many blocks to read
+
of=FILE
+
Save results into this file
+
+turbo
+
Engage turbo mode!
+
-h, --help
+
Prints help information
+
+

+ +
+

Output file is required in this parser, other values are optional

+
+$ app
+Error: expected of=FILE, pass --help for usage information + +
+
+$ app of=simple.txt
+Options { block_size: 1024, count: 1, output_file: "simple.txt", turbo: false } +
+

Since options are defined with anywhere - order doesn’t matter

+
+$ app bs=10 of=output.rs +turbo
+Options { block_size: 10, count: 1, output_file: "output.rs", turbo: true } +
+
+$ app +turbo bs=10 of=output.rs
+Options { block_size: 10, count: 1, output_file: "output.rs", turbo: true } +
+
+$ app bs=65536 count=12 of=hello_world.rs
+Options { block_size: 65536, count: 12, output_file: "hello_world.rs", turbo: false } +
+
+

§See also

+

literal - a specialized version of any that tries to parse a fixed literal

+
\ No newline at end of file diff --git a/bpaf/fn.choice.html b/bpaf/fn.choice.html new file mode 100644 index 00000000..4e70cd47 --- /dev/null +++ b/bpaf/fn.choice.html @@ -0,0 +1,90 @@ +choice in bpaf - Rust +

Function bpaf::choice

source ·
pub fn choice<T: 'static>(
+    parsers: impl IntoIterator<Item = Box<dyn Parser<T>>>
+) -> impl Parser<T>
Expand description

Choose between several parsers specified at runtime

+

You can use this function to create multiple parsers that produce the same type of value at a runtime +and let bpaf to pick one that best fits best. This function is designed to work in Combinatoric +API, but you can use it in Derive API with extern.

+ +

+#[derive(Debug, Clone)]
+pub struct Options {
+    desert: Option<&'static str>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let desert = ["apple", "banana", "orange", "grape", "strawberry"]
+        .iter()
+        .map(|name| {
+            long(name)
+                .help("Pick one of the options")
+                .req_flag(*name)
+                .boxed()
+        });
+    let desert = choice(desert).optional();
+    construct!(Options { desert }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

Here choice function is used to create an option for each possible desert item

+
+$ app --help
+

Usage: app [--apple | --banana | --orange | --grape | --strawberry]

+Available options:
--apple
+
Pick one of the options
+
--banana
+
Pick one of the options
+
--orange
+
Pick one of the options
+
--grape
+
Pick one of the options
+
--strawberry
+
Pick one of the options
+
-h, --help
+
Prints help information
+
+

+ +
+

User can pick any item

+
+$ app --apple
+Options { desert: Some("apple") } +
+

Since parser consumes only one value you can’t specify multiple flags of the same type

+
+$ app --orange --grape
+Error: --grape cannot be used at the same time as --orange + +
+

And Parser::optional makes it so when value is not specified - None is produced instead

+
+$ app
+Options { desert: None } +
+
\ No newline at end of file diff --git a/bpaf/fn.env.html b/bpaf/fn.env.html new file mode 100644 index 00000000..8a97d0c8 --- /dev/null +++ b/bpaf/fn.env.html @@ -0,0 +1,152 @@ +env in bpaf - Rust +

Function bpaf::env

source ·
pub fn env(variable: &'static str) -> NamedArg
Expand description

Parse an environment variable

+

You can chain multiple short, long and +env for multiple names. You can specify multiple names of the same type, +bpaf would use items past the first one as hidden aliases.

+

For flag and switch environment variable being present +gives the same result as the flag being present, allowing to implement things like NO_COLOR +variables:

+
$ NO_COLOR=1 app --do-something
+
+

If you don’t specify a short or a long name - whole argument is going to be absent from the +help message. Use it combined with a named or positional argument to have a hidden fallback +that wouldn’t leak sensitive info.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    switch: bool,
+    arg: usize,
+    username: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let switch = short('s') // first `short` creates a builder
+        .short('S') // second switch is a hidden alias
+        .long("switch") // visible long name
+        .long("also-switch") // hidden alias
+        .help("Switch with many names")
+        .switch(); // `switch` finalizes the builder
+
+    let arg = long("argument") // long is also a builder
+        .short('a')
+        .short('A')
+        .long("also-arg")
+        .help("Argument with names")
+        .argument::<usize>("ARG");
+
+    let username = long("user")
+        .short('u')
+        .env("USER1")
+        .help("Custom user name")
+        .argument::<String>("USER");
+
+    construct!(Options {
+        switch,
+        arg,
+        username
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, short('S'), long("also-switch"))]
+    /// Switch with many names
+    switch: bool,
+    #[bpaf(short, long("argument"), short('A'), long("also-arg"))]
+    /// Argument with names
+    arg: usize,
+    #[bpaf(short, long("user"), env("USER1"), argument("USER"))]
+    /// Custom user name
+    username: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

As usual switch is optional, arguments are required

+
+$ app -a 42 -u Bobert
+Options { switch: false, arg: 42, username: "Bobert" } +
+

Help displays only visible aliases (and a current value for env arguments)

+
+$ app --help
+

Usage: app [-s] -a=ARG -u=USER

+Available options:
-s, --switch
+
Switch with many names
+
-a, --argument=ARG
+
Argument with names
+
-u, --user=USER
+
Custom user name
+
+
[env:USER1: N/A]
+
-h, --help
+
Prints help information
+
+

+ +
+

But you can still use hidden aliases, both short and long

+
+$ app --also-switch --also-arg 330 --user Bobert
+Options { switch: true, arg: 330, username: "Bobert" } +
+

And unless there’s many or similar modifiers having multiple aliases doesn’t mean +you can specify them multiple times:

+
+$ app -A 42 -a 330 -u Bobert
+Error: -a is not expected in this context + +
+

Also hidden aliases are really hidden and only meant to do backward compatibility stuff, they +won’t show up anywhere else in completions or error messages

+
+$ app -a 42 -A 330 -u Bobert
+Error: -A is not expected in this context + +
+
\ No newline at end of file diff --git a/bpaf/fn.fail.html b/bpaf/fn.fail.html new file mode 100644 index 00000000..edbc874e --- /dev/null +++ b/bpaf/fn.fail.html @@ -0,0 +1,15 @@ +fail in bpaf - Rust +

Function bpaf::fail

source ·
pub fn fail<T>(msg: &'static str) -> ParseFail<T>
Expand description

Fail with a fixed error message

+

This parser produces T of any type but instead of producing it when asked - it fails +with a custom error message. Can be useful for creating custom logic

+

§Combinatoric usage

+
fn must_agree() -> impl Parser<()> {
+    let a = long("accept").req_flag(());
+    let no_a = fail("You must accept the license agreement with --agree before proceeding");
+    construct!([a, no_a])
+}
+

§Example

$ app
+// exits with "You must accept the license agreement with --agree before proceeding"
+$ app --agree
+// succeeds
+
\ No newline at end of file diff --git a/bpaf/fn.literal.html b/bpaf/fn.literal.html new file mode 100644 index 00000000..c8e4b8d3 --- /dev/null +++ b/bpaf/fn.literal.html @@ -0,0 +1,206 @@ +literal in bpaf - Rust +

Function bpaf::literal

source ·
pub fn literal(val: &'static str) -> ParseAny<()>
Expand description

A specialized version of any that consumes an arbitrary string

+

By default literal behaves similarly to positional so you should be using it near the +rightmost end of the consumer struct and it will only try to parse the first unconsumed +item on the command line. It is possible to lift this restriction by calling +anywhere on the parser.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    block_size: usize,
+    count: usize,
+    output_file: String,
+    turbo: bool,
+}
+
+/// Parses a string that starts with `name`, returns the suffix parsed in a usual way
+fn tag<T>(name: &'static str, meta: &str, help: impl Into<Doc>) -> impl Parser<T>
+where
+    T: FromStr,
+    <T as FromStr>::Err: std::fmt::Display,
+{
+    // closure inside checks if command line argument starts with a given name
+    // and if it is - it accepts it, otherwise it behaves like it never saw it
+    // it is possible to parse OsString here and strip the prefix with
+    // `os_str_bytes` or a similar crate
+    any("", move |s: String| Some(s.strip_prefix(name)?.to_owned()))
+        // this defines custom metavar for the help message
+        // so it looks like something it designed to parse
+        .metavar(&[(name, Style::Literal), (meta, Style::Metavar)][..])
+        .help(help)
+        // this makes it so tag parser tries to read all (unconsumed by earlier parsers)
+        // item on a command line instead of trying and failing on the first one
+        .anywhere()
+        // At this point parser produces `String` while consumer might expect some other
+        // type. [`parse`](Parser::parse) handles that
+        .parse(|s| s.parse())
+}
+
+pub fn options() -> OptionParser<Options> {
+    let block_size = tag("bs=", "BLOCK", "How many bytes to read at once")
+        .fallback(1024)
+        .display_fallback();
+    let count = tag("count=", "NUM", "How many blocks to read").fallback(1);
+    let output_file = tag("of=", "FILE", "Save results into this file");
+
+    // this consumes literal value of "+turbo" locate and produces `bool`
+    let turbo = literal("+turbo")
+        .help("Engage turbo mode!")
+        .anywhere()
+        .map(|_| true)
+        .fallback(false);
+
+    construct!(Options {
+        block_size,
+        count,
+        output_file,
+        turbo
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
// This example is still technically derive API, but derive is limited to gluing
+// things together and keeping macro complexity under control.
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    // `external` here and below derives name from the field name, looking for
+    // functions called `block_size`, `count`, etc that produce parsers of
+    // the right type.
+    // A different way would be to write down the name explicitly:
+    // #[bpaf(external(block_size), fallback(1024), display_fallback)]
+    #[bpaf(external, fallback(1024), display_fallback)]
+    block_size: usize,
+    #[bpaf(external, fallback(1))]
+    count: usize,
+    #[bpaf(external)]
+    output_file: String,
+    #[bpaf(external)]
+    turbo: bool,
+}
+
+fn block_size() -> impl Parser<usize> {
+    tag("bs=", "BLOCK", "How many bytes to read at once")
+}
+
+fn count() -> impl Parser<usize> {
+    tag("count=", "NUM", "How many blocks to read")
+}
+
+fn output_file() -> impl Parser<String> {
+    tag("of=", "FILE", "Save results into this file")
+}
+
+fn turbo() -> impl Parser<bool> {
+    literal("+turbo")
+        .help("Engage turbo mode!")
+        .anywhere()
+        .map(|_| true)
+        .fallback(false)
+}
+
+/// Parses a string that starts with `name`, returns the suffix parsed in a usual way
+fn tag<T>(name: &'static str, meta: &str, help: impl Into<Doc>) -> impl Parser<T>
+where
+    T: FromStr,
+    <T as FromStr>::Err: std::fmt::Display,
+{
+    // closure inside checks if command line argument starts with a given name
+    // and if it is - it accepts it, otherwise it behaves like it never saw it
+    // it is possible to parse OsString here and strip the prefix with
+    // `os_str_bytes` or a similar crate
+    any("", move |s: String| Some(s.strip_prefix(name)?.to_owned()))
+        // this defines custom metavar for the help message
+        // so it looks like something it designed to parse
+        .metavar(&[(name, Style::Literal), (meta, Style::Metavar)][..])
+        .help(help)
+        // this makes it so tag parser tries to read all (unconsumed by earlier parsers)
+        // item on a command line instead of trying and failing on the first one
+        .anywhere()
+        // At this point parser produces `String` while consumer might expect some other
+        // type. [`parse`](Parser::parse) handles that
+        .parse(|s| s.parse())
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Instead of usual metavariable any parsers take something that can represent any value

+
+$ app --help
+

Usage: app [bs=BLOCK] [count=NUM] of=FILE [+turbo]

+Available options:
bs=BLOCK
+
How many bytes to read at once
+
+
[default: 1024]
+
count=NUM
+
How many blocks to read
+
of=FILE
+
Save results into this file
+
+turbo
+
Engage turbo mode!
+
-h, --help
+
Prints help information
+
+

+ +
+

Output file is required in this parser, other values are optional

+
+$ app
+Error: expected of=FILE, pass --help for usage information + +
+
+$ app of=simple.txt
+Options { block_size: 1024, count: 1, output_file: "simple.txt", turbo: false } +
+

Since options are defined with anywhere - order doesn’t matter

+
+$ app bs=10 of=output.rs +turbo
+Options { block_size: 10, count: 1, output_file: "output.rs", turbo: true } +
+
+$ app +turbo bs=10 of=output.rs
+Options { block_size: 10, count: 1, output_file: "output.rs", turbo: true } +
+
+$ app bs=65536 count=12 of=hello_world.rs
+Options { block_size: 65536, count: 12, output_file: "hello_world.rs", turbo: false } +
+
+

§See also

+

any - a generic version of literal that uses function to decide if value is to be parsed +or not.

+
\ No newline at end of file diff --git a/bpaf/fn.long.html b/bpaf/fn.long.html new file mode 100644 index 00000000..5b132206 --- /dev/null +++ b/bpaf/fn.long.html @@ -0,0 +1,144 @@ +long in bpaf - Rust +

Function bpaf::long

source ·
pub fn long(long: &'static str) -> NamedArg
Expand description

Parse a flag/switch/argument that has a long name

+

You can chain multiple short, long and +env for multiple names. You can specify multiple names of the same type, +bpaf would use items past the first one as hidden aliases.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    switch: bool,
+    arg: usize,
+    username: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let switch = short('s') // first `short` creates a builder
+        .short('S') // second switch is a hidden alias
+        .long("switch") // visible long name
+        .long("also-switch") // hidden alias
+        .help("Switch with many names")
+        .switch(); // `switch` finalizes the builder
+
+    let arg = long("argument") // long is also a builder
+        .short('a')
+        .short('A')
+        .long("also-arg")
+        .help("Argument with names")
+        .argument::<usize>("ARG");
+
+    let username = long("user")
+        .short('u')
+        .env("USER1")
+        .help("Custom user name")
+        .argument::<String>("USER");
+
+    construct!(Options {
+        switch,
+        arg,
+        username
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, short('S'), long("also-switch"))]
+    /// Switch with many names
+    switch: bool,
+    #[bpaf(short, long("argument"), short('A'), long("also-arg"))]
+    /// Argument with names
+    arg: usize,
+    #[bpaf(short, long("user"), env("USER1"), argument("USER"))]
+    /// Custom user name
+    username: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

As usual switch is optional, arguments are required

+
+$ app -a 42 -u Bobert
+Options { switch: false, arg: 42, username: "Bobert" } +
+

Help displays only visible aliases (and a current value for env arguments)

+
+$ app --help
+

Usage: app [-s] -a=ARG -u=USER

+Available options:
-s, --switch
+
Switch with many names
+
-a, --argument=ARG
+
Argument with names
+
-u, --user=USER
+
Custom user name
+
+
[env:USER1: N/A]
+
-h, --help
+
Prints help information
+
+

+ +
+

But you can still use hidden aliases, both short and long

+
+$ app --also-switch --also-arg 330 --user Bobert
+Options { switch: true, arg: 330, username: "Bobert" } +
+

And unless there’s many or similar modifiers having multiple aliases doesn’t mean +you can specify them multiple times:

+
+$ app -A 42 -a 330 -u Bobert
+Error: -a is not expected in this context + +
+

Also hidden aliases are really hidden and only meant to do backward compatibility stuff, they +won’t show up anywhere else in completions or error messages

+
+$ app -a 42 -A 330 -u Bobert
+Error: -A is not expected in this context + +
+
\ No newline at end of file diff --git a/bpaf/fn.positional.html b/bpaf/fn.positional.html new file mode 100644 index 00000000..fc52ee3c --- /dev/null +++ b/bpaf/fn.positional.html @@ -0,0 +1,181 @@ +positional in bpaf - Rust +

Function bpaf::positional

source ·
pub fn positional<T>(metavar: &'static str) -> ParsePositional<T>
Expand description

Parse a positional argument

+

For named flags and arguments ordering generally doesn’t matter: most programs would +understand -O2 -v the same way as -v -O2, but for positional items order matters: in *nix +cat hello world and cat world hello would display contents of the same two files but in +a different order.

+

When using combinatoric API you can specify the type with turbofish, for parsing types +that don’t implement FromStr you can use consume a String/OsString first and parse +it by hand.

+ +
fn parse_pos() -> impl Parser<usize> {
+    positional::<usize>("POS")
+}
+

§Important restriction

+

To parse positional arguments from a command line you should place parsers for all your +named values before parsers for positional items and commands. In derive API fields parsed as +positional items or commands should be at the end of your struct/enum. The same rule applies +to parsers with positional fields or commands inside: such parsers should go to the end as well.

+

Use check_invariants in your test to ensure correctness.

+

For example for non-positional non_pos and positional pos parsers

+ +
let valid = construct!(non_pos(), pos());
+let invalid = construct!(pos(), non_pos());
+

bpaf panics during help generation unless this restriction holds

+

Without using -- bpaf would only accept items that don’t start with - as positional, you +can use any to work around this restriction.

+

By default bpaf accepts positional items with or without -- where values permit, you can +further restrict the parser to accept positional items only on the right side of -- using +strict.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    crate_name: String,
+    feature_name: Option<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help("Display detailed information")
+        .switch();
+
+    let crate_name = positional("CRATE").help("Crate name to use");
+
+    let feature_name = positional("FEATURE")
+        .help("Display information about this feature")
+        .optional();
+
+    construct!(Options {
+        verbose,
+        // You must place positional items and commands after
+        // all other parsers
+        crate_name,
+        feature_name
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Display detailed information
+    #[bpaf(short, long)]
+    verbose: bool,
+
+    // You must place positional items and commands after
+    // all other parsers
+    #[bpaf(positional("CRATE"))]
+    /// Crate name to use
+    crate_name: String,
+
+    #[bpaf(positional("FEATURE"))]
+    /// Display information about this feature
+    feature_name: Option<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Positional items show up in a separate group of arguments if they contain a help message, +otherwise they will show up only in Usage part.

+
+$ app --help
+

Usage: app [-v] CRATE [FEATURE]

+Available positional items:
CRATE
+
Crate name to use
+
FEATURE
+
Display information about this feature
+
+

+Available options:
-v, --verbose
+
Display detailed information
+
-h, --help
+
Prints help information
+
+

+ +
+

You can mix positional items with regular items

+
+$ app --verbose bpaf
+Options { verbose: true, crate_name: "bpaf", feature_name: None } +
+

And since bpaf API expects to have non positional items consumed before positional ones - you +can use them in a different order. In this example bpaf corresponds to a crate_name field and +--verbose – to verbose.

+
+$ app bpaf --verbose
+Options { verbose: true, crate_name: "bpaf", feature_name: None } +
+

In previous examples optional field feature was missing, this one contains it.

+
+$ app bpaf autocomplete
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("autocomplete") } +
+

Users can use -- to tell bpaf to treat remaining items as positionals - this might be +required to handle unusual items.

+
+$ app bpaf -- --verbose
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("--verbose") } +
+
+$ app -- bpaf --verbose
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("--verbose") } +
+

Without using -- bpaf would only accept items that don’t start with - as positional.

+
+$ app --detailed
+Error: expected CRATE, got --detailed. Pass --help for usage information + +
+
+$ app --verbose
+Error: expected CRATE, pass --help for usage information + +
+

You can use any to work around this restriction.

+
\ No newline at end of file diff --git a/bpaf/fn.pure.html b/bpaf/fn.pure.html new file mode 100644 index 00000000..32965ec4 --- /dev/null +++ b/bpaf/fn.pure.html @@ -0,0 +1,90 @@ +pure in bpaf - Rust +

Function bpaf::pure

source ·
pub fn pure<T>(val: T) -> ParsePure<T>
Expand description

Parser that produces a fixed value

+

This parser produces T without consuming anything from the command line, which can be useful +with construct!. As with any parsers, T should be Clone and Debug.

+

Both pure and pure_with are designed to put values into structures, to generate fallback +you should be using fallback and fallback_with.

+

See also pure_with for a pure computation that can fail.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    name: String,
+    money: u32,
+}
+
+pub fn options() -> OptionParser<Options> {
+    // User can customise a name
+    let name = long("name").help("Use a custom user name").argument("NAME");
+    // but not starting amount of money
+    let money = pure(330);
+    construct!(Options { name, money }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(argument("NAME"))]
+    /// Use a custom user name
+    name: String,
+    #[bpaf(pure(330))]
+    money: u32,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

pure does not show up in --help message

+
+$ app --help
+

Usage: app --name=NAME

+Available options:
--name=NAME
+
Use a custom user name
+
-h, --help
+
Prints help information
+
+

+ +
+

And there’s no way to alter the value from the command line

+
+$ app --name Bob
+Options { name: "Bob", money: 330 } +
+

Any attempts to do so would result in an error :)

+
+$ app --money 100000 --name Hackerman
+Error: --money is not expected in this context + +
+
\ No newline at end of file diff --git a/bpaf/fn.pure_with.html b/bpaf/fn.pure_with.html new file mode 100644 index 00000000..40312572 --- /dev/null +++ b/bpaf/fn.pure_with.html @@ -0,0 +1,102 @@ +pure_with in bpaf - Rust +

Function bpaf::pure_with

source ·
pub fn pure_with<T, F, E>(val: F) -> ParsePureWith<T, F, E>
where + F: Fn() -> Result<T, E>, + E: ToString,
Expand description

Wrap a calculated value into a Parser

+

This parser represents a possibly failing equivalent to pure. +It produces T by invoking the provided callback without consuming anything from the command +line, which can be useful with construct!. As with any parsers, T should be Clone +and Debug.

+

Both pure and pure_with are designed to put values into structures, to generate fallback +you should be using fallback and fallback_with.

+

See also pure for a pure computation that can’t fail.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    name: String,
+    money: u32,
+}
+
+fn starting_money() -> Result<u32, &'static str> {
+    Ok(330)
+}
+
+pub fn options() -> OptionParser<Options> {
+    // User can customise a name
+    let name = long("name").help("Use a custom user name").argument("NAME");
+    // but not starting amount of money
+    let money = pure_with(starting_money);
+    construct!(Options { name, money }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(argument("NAME"))]
+    /// Use a custom user name
+    name: String,
+    #[bpaf(pure_with(starting_money))]
+    money: u32,
+}
+
+fn starting_money() -> Result<u32, &'static str> {
+    Ok(330)
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

pure does not show up in --help message

+
+$ app --help
+

Usage: app --name=NAME

+Available options:
--name=NAME
+
Use a custom user name
+
-h, --help
+
Prints help information
+
+

+ +
+

And there’s no way to alter the value from the command line

+
+$ app --name Bob
+Options { name: "Bob", money: 330 } +
+

Any attempts to do so would result in an error :)

+
+$ app --money 100000 --name Hackerman
+Error: --money is not expected in this context + +
+
\ No newline at end of file diff --git a/bpaf/fn.short.html b/bpaf/fn.short.html new file mode 100644 index 00000000..229afcbe --- /dev/null +++ b/bpaf/fn.short.html @@ -0,0 +1,144 @@ +short in bpaf - Rust +

Function bpaf::short

source ·
pub fn short(short: char) -> NamedArg
Expand description

Parse a flag/switch/argument that has a short name

+

You can chain multiple short, long and +env for multiple names. You can specify multiple names of the same type, +bpaf would use items past the first one as hidden aliases.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    switch: bool,
+    arg: usize,
+    username: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let switch = short('s') // first `short` creates a builder
+        .short('S') // second switch is a hidden alias
+        .long("switch") // visible long name
+        .long("also-switch") // hidden alias
+        .help("Switch with many names")
+        .switch(); // `switch` finalizes the builder
+
+    let arg = long("argument") // long is also a builder
+        .short('a')
+        .short('A')
+        .long("also-arg")
+        .help("Argument with names")
+        .argument::<usize>("ARG");
+
+    let username = long("user")
+        .short('u')
+        .env("USER1")
+        .help("Custom user name")
+        .argument::<String>("USER");
+
+    construct!(Options {
+        switch,
+        arg,
+        username
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, short('S'), long("also-switch"))]
+    /// Switch with many names
+    switch: bool,
+    #[bpaf(short, long("argument"), short('A'), long("also-arg"))]
+    /// Argument with names
+    arg: usize,
+    #[bpaf(short, long("user"), env("USER1"), argument("USER"))]
+    /// Custom user name
+    username: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

As usual switch is optional, arguments are required

+
+$ app -a 42 -u Bobert
+Options { switch: false, arg: 42, username: "Bobert" } +
+

Help displays only visible aliases (and a current value for env arguments)

+
+$ app --help
+

Usage: app [-s] -a=ARG -u=USER

+Available options:
-s, --switch
+
Switch with many names
+
-a, --argument=ARG
+
Argument with names
+
-u, --user=USER
+
Custom user name
+
+
[env:USER1: N/A]
+
-h, --help
+
Prints help information
+
+

+ +
+

But you can still use hidden aliases, both short and long

+
+$ app --also-switch --also-arg 330 --user Bobert
+Options { switch: true, arg: 330, username: "Bobert" } +
+

And unless there’s many or similar modifiers having multiple aliases doesn’t mean +you can specify them multiple times:

+
+$ app -A 42 -a 330 -u Bobert
+Error: -a is not expected in this context + +
+

Also hidden aliases are really hidden and only meant to do backward compatibility stuff, they +won’t show up anywhere else in completions or error messages

+
+$ app -a 42 -A 330 -u Bobert
+Error: -A is not expected in this context + +
+
\ No newline at end of file diff --git a/bpaf/index.html b/bpaf/index.html new file mode 100644 index 00000000..c21b25cd --- /dev/null +++ b/bpaf/index.html @@ -0,0 +1,212 @@ +bpaf - Rust +

Crate bpaf

source ·
Expand description

Lightweight and flexible command line argument parser with derive and combinatoric style API

+ +
    +
  • Introduction - features, design goals, restrictions
  • +
  • Tutorials - practical learning oriented information and +examples to get you started + +
  • +
  • How-to and guides - assumes familiarity with the basics and +explains how to concrete tasks
  • +
  • Explanations - theoretical information about abstractions +used by the library, oriented for understanding
  • +
  • FAQ - questions from library users
  • +
+

§A quick start

+

Add bpaf, optionally with derive enabled

+
$ cargo add bpaf -F derive,dull_color
+
+

Use either derive or combinatoric API and try running it

+
Combinatoric example + +
use bpaf::*;
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    message: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let message = positional("MESSAGE").help("Message to print in a big friendly letters");
+    construct!(Options { message }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
use bpaf::*;
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Message to print in a big friendly letters
+    #[bpaf(positional("MESSAGE"))]
+    message: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

With everything in place users should be able to pass their arguments

+
+$ app "Hello world"
+Options { message: "Hello world" } +
+

As well as read the help message generated by the library

+
+$ app --help
+

Usage: app MESSAGE

+Available positional items:
MESSAGE
+
Message to print in a big friendly letters
+
+

+Available options:
-h, --help
+
Prints help information
+
+

+ +
+
+

§Consuming items - making Parser

+

bpaf allows you to describe the parsers using a mix of two APIs: combinatoric and derive. +Both APIs can achieve the same results, you can use one that better suits your needs. You can +find documentation with more examples following those links.

+
    +
  • For an argument with a name you define NamedArg using a combination of short, +long and env. At the same time you can attach +help.
  • +
  • NamedArg::switch - simple switch that returns true if it’s present on a command +line and false otherwise.
  • +
  • NamedArg::flag - a variant of switch that lets you return one of two custom +values, for example Color::On and Color::Off.
  • +
  • NamedArg::req_flag - a variant of switch that only only succeeds when it’s name +is present on a command line
  • +
  • NamedArg::argument - named argument containing a value, you can further +customize it with adjacent
  • +
  • positional - positional argument, you can further customize it with +strict
  • +
  • OptionParser::command - subcommand parser.
  • +
  • any and its specialized version literal are escape hatches that can parse anything +not fitting into usual classification.
  • +
  • pure and pure_with - a way to generate a value that can be composed without parsing +it from the command line.
  • +
+

§Transforming and changing parsers

+

By default primitive parsers gives you back a single bool, a single PathBuf or a single +value produced by FromStr trait, etc. You can further transform it by chaining methods from +Parser trait, some of those methods are applied automagically if you are using derive API.

+

bpaf distinguishes two types of parse failures - “value is absent” and +“value is present but invalid”, most parsers listed in this section only handle the first +type of failure by default, but you can use their respective catch method to handle the later +one.

+ +

§Combining multiple parsers together

+

Once you have parsers for all the primitive fields figured out you can start combining them +together to produce a parser for a final result - data type you designed in the step one. +For derive API you apply annotations to data types with #[derive(Bpaf)] and #[bpaf(..)], +with combinatoric API you use construct! macro.

+

All fields in a struct needs to be successfully parsed in order for the parser to succeed +and only one variant from enum will consume its values at a time.

+

You can use adjacent annotation to parse multiple flags as an adjacent +group allowing for more unusual scenarios such as multiple value arguments or chained commands.

+

§Improving user experience

+

bpaf would use doc comments on fields and structures in derive mode and and values passed +in various help methods to generate --help documentation, you can further improve it +using those methods:

+
    +
  • hide_usage and hide - hide the parser from +generated Usage line or whole generated help
  • +
  • group_help and with_group_help - +add a common description shared by several parsers
  • +
  • custom_usage - customize usage for a primitive or composite parser
  • +
  • usage and with_usage lets you to +customize whole usage line as a whole either by completely overriding it or by building around it.
  • +
+

By default with completion enabled bpaf would complete names for flags, arguments and +commands. You can also generate completion for argument values, possible positionals, etc. +This requires enabling autocomplete cargo feature.

+ +

And finally you can generate documentation for command line in markdown, html and manpage +formats using render_markdown, +render_html and render_manpage, +for more detailed info see doc module

+

§Testing your parsers and running them

+ +

§Cargo features

+
    +
  • +

    derive: adds a dependency on bpaf_derive crate and reexport Bpaf derive macro. You +need to enable it to use derive API. Disabled by default.

    +
  • +
  • +

    batteries: helpers implemented with public bpaf API. Disabled by default.

    +
  • +
  • +

    autocomplete: enables support for shell autocompletion. Disabled by default.

    +
  • +
  • +

    bright-color, dull-color: use more colors when printing --help and such. Enabling +either color feature adds some extra dependencies and might raise MRSV. If you are planning +to use this feature in a published app - it’s best to expose them as feature flags:

    +
    [features]
    +bright-color = ["bpaf/bright-color"]
    +dull-color = ["bpaf/dull-color"]
    +
    +

    Disabled by default.

    +
  • +
  • +

    docgen: generate documentation from help declaration, see OptionParser::render_markdown and doc. Disabled by default.

    +
  • +
+

Modules§

  • Project documentation
  • Batteries included - helpful parsers that use only public API
  • Documentation generation system
  • Tools to define primitive parsers
  • This module exposes parsers that accept further configuration with builder pattern

Macros§

  • Compose several parsers to produce a single result

Structs§

  • All currently present command line parameters with some extra metainfo
  • String with styled segments.
  • Ready to run Parser with additional information attached

Enums§

  • Unsuccessful command line parsing outcome, use it for unit tests
  • Shell specific completion

Traits§

  • Simple or composed argument parser

Functions§

  • Parse a single arbitrary item from a command line
  • Choose between several parsers specified at runtime
  • Parse an environment variable
  • Fail with a fixed error message
  • A specialized version of any that consumes an arbitrary string
  • Parse a flag/switch/argument that has a long name
  • Parse a positional argument
  • Parser that produces a fixed value
  • Wrap a calculated value into a Parser
  • Parse a flag/switch/argument that has a short name

Derive Macros§

  • Derive macro for bpaf command line parser
\ No newline at end of file diff --git a/bpaf/info/struct.OptionParser.html b/bpaf/info/struct.OptionParser.html new file mode 100644 index 00000000..2a32826f --- /dev/null +++ b/bpaf/info/struct.OptionParser.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/struct.OptionParser.html...

+ + + \ No newline at end of file diff --git a/bpaf/macro.construct!.html b/bpaf/macro.construct!.html new file mode 100644 index 00000000..10395db9 --- /dev/null +++ b/bpaf/macro.construct!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.construct.html...

+ + + \ No newline at end of file diff --git a/bpaf/macro.construct.html b/bpaf/macro.construct.html new file mode 100644 index 00000000..c573a499 --- /dev/null +++ b/bpaf/macro.construct.html @@ -0,0 +1,143 @@ +construct in bpaf - Rust +

Macro bpaf::construct

source ·
macro_rules! construct {
+    ($(::)? $ns:ident $(:: $con:ident)* { $($tokens:tt)* }) => { ... };
+    ($(::)? $ns:ident $(:: $con:ident)* ( $($tokens:tt)* )) => { ... };
+    ($first:ident $($tokens:tt)*) => { ... };
+    ([$first:ident $($tokens:tt)*]) => { ... };
+    (@prepare $ty:tt [$($fields:tt)*] $field:ident () $(, $($rest:tt)*)? ) => { ... };
+    (@prepare $ty:tt [$($fields:tt)*] $field:ident ($expr:expr) $(, $($rest:tt)*)?) => { ... };
+    (@prepare $ty:tt [$($fields:tt)*] $field:ident $(, $($rest:tt)*)? ) => { ... };
+    (@prepare [alt] [$first:ident $($fields:ident)*]) => { ... };
+    (@prepare $ty:tt [$($fields:tt)*]) => { ... };
+    (@make [named [$($con:tt)+]] [$($fields:ident)*]) => { ... };
+    (@make [pos   [$($con:tt)+]] [$($fields:ident)*]) => { ... };
+    (@make [pos] [$($fields:ident)*]) => { ... };
+    (@fin [named [$($con:tt)+]] []) => { ... };
+    (@fin [pos   [$($con:tt)+]] []) => { ... };
+    (@fin [pos] [$field:ident]) => { ... };
+    (@fin $ty:tt [$front:ident $($fields:ident)*]) => { ... };
+}
Expand description

Compose several parsers to produce a single result

+

§Usage reference

+
// structs with unnamed fields:
+construct!(Res(a, b, c));
+
+// structs with named fields:
+construct!(Res {a, b, c});
+
+// enums with unnamed fields:
+construct!(Ty::Res(a, b, c));
+
+// enums with named fields:
+construct!(Ty::Res {a, b, c});
+
+// tuples:
+construct!(a, b, c);
+
+// parallel composition, tries all parsers, picks one that consumes the left most value,
+// or if they consume the same (or not at all) - the left most in a list
+construct!([a, b, c]);
+
+// defining primitive parsers inside construct macro :)
+construct!(a(short('a').switch()), b(long("arg").argument::<usize>("ARG")));
+
+// defining a boxed parser
+construct!(a);
+

§Combinatoric usage

+

construct! can compose parsers sequentially or in parallel.

+

Sequential composition runs each parser and if all of them succeed you get a parser object of a +new type back. Placeholder names for values inside construct! macro must correspond to both +struct/enum names and parser names present in scope. In examples below a corresponds to a +function and b corresponds to a variable name. Note parens in a(), you must to use them to +indicate function parsers.

+

Inside the parens you can put a whole expression to use instead of +having to define them in advance: a(positional::<String>("POS")). Probably a good idea to use this +approach only for simple parsers.

+ +
struct Res (u32, u32);
+enum Ul { T { a: u32, b: u32 } }
+
+// You can share parameters across multiple construct invocations
+// if defined as functions
+fn a() -> impl Parser<u32> {
+    short('a').argument::<u32>("N")
+}
+
+// You can construct structs or enums with unnamed fields
+fn res() -> impl Parser<Res> {
+    let b = short('b').argument::<u32>("n");
+    construct!(Res ( a(), b ))
+}
+
+// You can construct structs or enums with named fields
+fn ult() -> impl Parser<Ul> {
+    let b = short('b').argument::<u32>("n");
+    construct!(Ul::T { a(), b })
+}
+
+// You can also construct simple tuples
+fn tuple() -> impl Parser<(u32, u32)> {
+    let b = short('b').argument::<u32>("n");
+    construct!(a(), b)
+}
+
+// You can create boxed version of parsers so the type matches as long
+// as return type is the same - can be useful for all sort of dynamic parsers
+fn boxed() -> Box<dyn Parser<u32>> {
+    let a = short('a').argument::<u32>("n");
+    construct!(a)
+}
+
+// In addition to having primitives defined before using them - you can also define
+// them directly inside construct macro. Probably only a good idea if you have only simple
+// components
+struct Options {
+    arg: u32,
+    switch: bool,
+}
+
+fn coyoda() -> impl Parser<Options> {
+    construct!(Options {
+        arg(short('a').argument::<u32>("ARG")),
+        switch(short('s').switch())
+    })
+}
+

Parallel composition picks one of several available parsers (result types must match) and returns a +parser object of the same type. Similar to sequential composition you can use parsers from variables +or functions:

+ +
fn b() -> impl Parser<u32> {
+    short('b').argument::<u32>("NUM")
+}
+
+fn a_or_b() -> impl Parser<u32> {
+    let a = short('a').argument::<u32>("NUM");
+    // equivalent way of writing this would be `a.or_else(b())`
+    construct!([a, b()])
+}
+

§Derive usage

+

bpaf would combine fields of struct or enum constructors sequentially and enum +variants in parallel.

+ +
// to satisfy this parser user needs to pass both -a and -b
+#[derive(Debug, Clone, Bpaf)]
+struct Res {
+    a: u32,
+    b: u32,
+}
+
+// to satisfy this parser user needs to pass one (and only one) of -a, -b, -c or -d
+#[derive(Debug, Clone, Bpaf)]
+enum Enumeraton {
+    A { a: u32 },
+    B { b: u32 },
+    C { c: u32 },
+    D { d: u32 },
+}
+
+// here user needs to pass either both -a AND -b or both -c AND -d
+#[derive(Debug, Clone, Bpaf)]
+enum Ult {
+    AB { a: u32, b: u32 },
+    CD { c: u32, d: u32 }
+}
+
\ No newline at end of file diff --git a/bpaf/params/index.html b/bpaf/params/index.html new file mode 100644 index 00000000..5af520af --- /dev/null +++ b/bpaf/params/index.html @@ -0,0 +1,1174 @@ +bpaf::params - Rust +

Module bpaf::params

source ·
Expand description

Tools to define primitive parsers

+

§Ways to consume data

§Flag

+
    +
  • flag - a string that consists of two dashes (--flag) and a name and a single +dash and a single character (-f) created with long and short +respectively. Depending if this name is present or absent on the command line +primitive flag parser produces one of two values. User can combine several short flags in a single +invocation: -a -b -c is the same as -abc.
  • +
+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    decision: Decision,
+}
+
+#[derive(Debug, Clone)]
+pub enum Decision {
+    Yes,
+    No,
+}
+
+fn parse_decision() -> impl Parser<Decision> {
+    long("decision")
+        .help("Positive decision")
+        .flag(Decision::Yes, Decision::No)
+}
+
+pub fn options() -> OptionParser<Options> {
+    let decision = parse_decision();
+    construct!(Options { decision }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Positive decision
+    #[bpaf(flag(Decision::Yes, Decision::No))]
+    decision: Decision,
+}
+
+#[derive(Debug, Clone)]
+pub enum Decision {
+    Yes,
+    No,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help output bpaf shows flags with no meta variable attached

+
+$ app --help
+

Usage: app [--decision]

+Available options:
--decision
+
Positive decision
+
-h, --help
+
Prints help information
+
+

+ +
+

Presense of a long name is decoded into Yes

+
+$ app --decision
+Options { decision: Yes } +
+

Absense is No

+
+$ app
+Options { decision: No } +
+
+

§Required flag

+

Similar to flag, but instead of falling back to the second value required flag parser would +fail. Mostly useful in combination with other parsers, created with NamedArg::req_flag.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub enum Style {
+    Intel,
+    Att,
+    Llvm,
+}
+
+#[derive(Debug, Clone)]
+pub enum Report {
+    /// Include defailed report
+    Detailed,
+    /// Include minimal report
+    Minimal,
+    /// No preferences
+    Undecided,
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    agree: (),
+    style: Style,
+    report: Report,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let agree = long("agree")
+        .help("You must agree to perform the action")
+        .req_flag(());
+
+    let intel = long("intel")
+        .help("Show assembly using Intel style")
+        .req_flag(Style::Intel);
+    let att = long("att")
+        .help("Show assembly using AT&T style")
+        .req_flag(Style::Att);
+    let llvm = long("llvm").help("Show llvm-ir").req_flag(Style::Llvm);
+    let style = construct!([intel, att, llvm]);
+
+    let detailed = long("detailed")
+        .help("Include detailed report")
+        .req_flag(Report::Detailed);
+    let minimal = long("minimal")
+        .help("Include minimal report")
+        .req_flag(Report::Minimal);
+    let report = construct!([detailed, minimal]).fallback(Report::Undecided);
+
+    construct!(Options {
+        agree,
+        style,
+        report
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+pub enum Style {
+    /// Show assembly using Intel style
+    Intel,
+    /// Show assembly using AT&T style
+    Att,
+    /// Show llvm-ir
+    Llvm,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(fallback(Report::Undecided))]
+pub enum Report {
+    /// Include detailed report
+    Detailed,
+    /// Include minimal report
+    Minimal,
+    #[bpaf(skip)]
+    /// No preferences
+    Undecided,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// You must agree to perform the action
+    agree: (),
+    // external here uses explicit reference to function `style`
+    // generated above
+    #[bpaf(external(style))]
+    style: Style,
+    // here reference is implicit and derived from field name: `report`
+    #[bpaf(external)]
+    report: Report,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help message req_flag look similarly to switch and +flag

+
+$ app --help
+

Usage: app --agree (--intel | --att | --llvm) [--detailed | --minimal]

+Available options:
--agree
+
You must agree to perform the action
+
--intel
+
Show assembly using Intel style
+
--att
+
Show assembly using AT&T style
+
--llvm
+
Show llvm-ir
+
--detailed
+
Include detailed report
+
--minimal
+
Include minimal report
+
-h, --help
+
Prints help information
+
+

+ +
+

Example contains two parsers that fails without any input: agree requires passing --agree

+
+$ app
+Error: expected --agree, pass --help for usage information + +
+

While style takes one of several possible values

+
+$ app --agree
+Error: expected --intel, --att, or more, pass --help for usage information + +
+

It is possible to alter the behavior using fallback or +hide.

+
+$ app --agree --intel
+Options { agree: (), style: Intel, report: Undecided } +
+

While parser for style takes any posted output - it won’t take multiple of them at once +(unless other combinators such as many permit it) or last.

+
+$ app --agree --att --llvm
+Error: --llvm cannot be used at the same time as --att + +
+
+

§Switch

+

A special case of a flag that gets decoded into a bool, mostly serves as a convenient +shortcut to .flag(true, false). Created with NamedArg::switch.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    release: bool,
+    default_features: bool,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help("Produce verbose output")
+        .switch();
+    let release = long("release")
+        .help("Build artifacts in release mode")
+        .flag(true, false);
+    let default_features = long("no-default-features")
+        .help("Do not activate default features")
+        // default_features uses opposite values,
+        // producing `true` when value is absent
+        .flag(false, true);
+
+    construct!(Options {
+        verbose,
+        release,
+        default_features,
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Produce verbose output
+    // bpaf uses `switch` for `bool` fields in named
+    // structs unless consumer attribute is present.
+    // But it is also possible to give it explicit
+    // consumer annotation to serve as a reminder:
+    // #[bpaf(short, long, switch)]
+    #[bpaf(short, long)]
+    verbose: bool,
+
+    #[bpaf(flag(true, false))]
+    /// Build artifacts in release mode
+    release: bool,
+
+    /// Do not activate default features
+    // default_features uses opposite values,
+    // producing `true` when value is absent
+    #[bpaf(long("no-default-features"), flag(false, true))]
+    default_features: bool,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help output bpaf shows switches as usual flags with no meta variable attached

+
+$ app --help
+

Usage: app [-v] [--release] [--no-default-features]

+Available options:
-v, --verbose
+
Produce verbose output
+
--release
+
Build artifacts in release mode
+
--no-default-features
+
Do not activate default features
+
-h, --help
+
Prints help information
+
+

+ +
+

Both switch and flag succeed if value is not present, switch returns true, flag returns +second value.

+
+$ app
+Options { verbose: false, release: false, default_features: true } +
+

When value is present - switch returns true, flag returns first value.

+
+$ app --verbose --no-default-features --detailed
+Error: --detailed is not expected in this context + +
+

Like with most parsrs unless specified switch and flag consume at most one item from the +command line:

+
+$ app --no-default-features --no-default-features
+Error: argument --no-default-features cannot be used multiple times in this context + +
+
+

§Argument

+

A short or long flag followed by either a space or = and +then by a string literal. -f foo, --flag bar or -o=- are all valid argument examples. Note, string +literal can’t start with - unless separated from the flag with =. For short flags value +can follow immediately: -fbar.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    name: String,
+    age: usize,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let name = short('n')
+        .long("name")
+        .help("Specify user name")
+        // you can specify exact type argument should produce
+        // for as long as it implements `FromStr`
+        .argument::<String>("NAME");
+
+    let age = long("age")
+        .help("Specify user age")
+        // but often rust can figure it out from the context,
+        // here age is going to be `usize`
+        .argument("AGE")
+        .fallback(18)
+        .display_fallback();
+
+    construct!(Options { name, age }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    // you can specify exact type argument should produce
+    // for as long as it implements `FromStr`
+    #[bpaf(short, long, argument::<String>("NAME"))]
+    /// Specify user name
+    name: String,
+    // but often rust can figure it out from the context,
+    // here age is going to be `usize`
+    #[bpaf(argument("AGE"), fallback(18), display_fallback)]
+    /// Specify user age
+    age: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +
+$ app --help
+

Usage: app -n=NAME [--age=AGE]

+Available options:
-n, --name=NAME
+
Specify user name
+
--age=AGE
+
Specify user age
+
+
[default: 18]
+
-h, --help
+
Prints help information
+
+

+ +
+

--help shows arguments as a short name with attached metavariable

+

Value can be separated from flag by space, = sign

+
+$ app --name Bob --age 12
+Options { name: "Bob", age: 12 } +
+
+$ app --name "Bob" --age=12
+Options { name: "Bob", age: 12 } +
+
+$ app --name=Bob
+Options { name: "Bob", age: 18 } +
+
+$ app --name="Bob"
+Options { name: "Bob", age: 18 } +
+

Or in case of short name - be directly adjacent to it

+
+$ app -nBob
+Options { name: "Bob", age: 18 } +
+

For long names - this doesn’t work since parser can’t tell where name +stops and argument begins:

+
+$ app --age12
+Error: no such flag: --age12, did you mean --age? + +
+

Either way - value is required, passing just the argument name results in parse failure

+
+$ app --name
+Error: --name requires an argument NAME + +
+
+

§Positional

+

A positional argument with no additonal name, for example in vim main.rs main.rs +is a positional argument. Can’t start with -, created with positional.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    crate_name: String,
+    feature_name: Option<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help("Display detailed information")
+        .switch();
+
+    let crate_name = positional("CRATE").help("Crate name to use");
+
+    let feature_name = positional("FEATURE")
+        .help("Display information about this feature")
+        .optional();
+
+    construct!(Options {
+        verbose,
+        // You must place positional items and commands after
+        // all other parsers
+        crate_name,
+        feature_name
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Display detailed information
+    #[bpaf(short, long)]
+    verbose: bool,
+
+    // You must place positional items and commands after
+    // all other parsers
+    #[bpaf(positional("CRATE"))]
+    /// Crate name to use
+    crate_name: String,
+
+    #[bpaf(positional("FEATURE"))]
+    /// Display information about this feature
+    feature_name: Option<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Positional items show up in a separate group of arguments if they contain a help message, +otherwise they will show up only in Usage part.

+
+$ app --help
+

Usage: app [-v] CRATE [FEATURE]

+Available positional items:
CRATE
+
Crate name to use
+
FEATURE
+
Display information about this feature
+
+

+Available options:
-v, --verbose
+
Display detailed information
+
-h, --help
+
Prints help information
+
+

+ +
+

You can mix positional items with regular items

+
+$ app --verbose bpaf
+Options { verbose: true, crate_name: "bpaf", feature_name: None } +
+

And since bpaf API expects to have non positional items consumed before positional ones - you +can use them in a different order. In this example bpaf corresponds to a crate_name field and +--verbose – to verbose.

+
+$ app bpaf --verbose
+Options { verbose: true, crate_name: "bpaf", feature_name: None } +
+

In previous examples optional field feature was missing, this one contains it.

+
+$ app bpaf autocomplete
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("autocomplete") } +
+

Users can use -- to tell bpaf to treat remaining items as positionals - this might be +required to handle unusual items.

+
+$ app bpaf -- --verbose
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("--verbose") } +
+
+$ app -- bpaf --verbose
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("--verbose") } +
+

Without using -- bpaf would only accept items that don’t start with - as positional.

+
+$ app --detailed
+Error: expected CRATE, got --detailed. Pass --help for usage information + +
+
+$ app --verbose
+Error: expected CRATE, pass --help for usage information + +
+

You can use any to work around this restriction.

+
+

§Any

+

Also a positional argument with no additional name, but unlike positional itself, any +isn’t restricted to positional looking structure and would consume any items as they appear on +a command line. Can be useful to collect anything unused to pass to other applications.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    turbo: bool,
+    rest: Vec<OsString>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let turbo = short('t')
+        .long("turbo")
+        .help("Engage the turbo mode")
+        .switch();
+    let rest = any::<OsString, _, _>("REST", |x| (x != "--help").then_some(x))
+        .help("app will pass anything unused to a child process")
+        .many();
+    construct!(Options { turbo, rest }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long)]
+    /// Engage the turbo mode
+    turbo: bool,
+    #[bpaf(any("REST", not_help), many)]
+    /// app will pass anything unused to a child process
+    rest: Vec<OsString>,
+}
+
+fn not_help(s: OsString) -> Option<OsString> {
+    if s == "--help" {
+        None
+    } else {
+        Some(s)
+    }
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

--help keeps working for as long as any captures only intended values - that is it ignores +--help flag specifically

+
+$ app --help
+

Usage: app [-t] [REST]...

+Available positional items:
REST
+
app will pass anything unused to a child process
+
+

+Available options:
-t, --turbo
+
Engage the turbo mode
+
-h, --help
+
Prints help information
+
+

+ +
+

You can mix any with regular options, here switch turbo works because it goes +before rest in the parser declaration

+
+$ app --turbo git commit -m "hello world"
+Options { turbo: true, rest: ["git", "commit", "-m", "hello world"] } +
+

“before” in the previous line means in the parser definition, not on the user input, here +--turbo gets consumed by turbo parser even the argument goes

+
+$ app git commit -m="hello world" --turbo
+Options { turbo: true, rest: ["git", "commit", "-m=hello world"] } +
+
+$ app -- git commit -m="hello world" --turbo
+Options { turbo: false, rest: ["git", "commit", "-m=hello world", "--turbo"] } +
+
+$ app git commit -m="hello world" -- --turbo
+Options { turbo: false, rest: ["git", "commit", "-m=hello world", "--turbo"] } +
+
+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    block_size: usize,
+    count: usize,
+    output_file: String,
+    turbo: bool,
+}
+
+/// Parses a string that starts with `name`, returns the suffix parsed in a usual way
+fn tag<T>(name: &'static str, meta: &str, help: impl Into<Doc>) -> impl Parser<T>
+where
+    T: FromStr,
+    <T as FromStr>::Err: std::fmt::Display,
+{
+    // closure inside checks if command line argument starts with a given name
+    // and if it is - it accepts it, otherwise it behaves like it never saw it
+    // it is possible to parse OsString here and strip the prefix with
+    // `os_str_bytes` or a similar crate
+    any("", move |s: String| Some(s.strip_prefix(name)?.to_owned()))
+        // this defines custom metavar for the help message
+        // so it looks like something it designed to parse
+        .metavar(&[(name, Style::Literal), (meta, Style::Metavar)][..])
+        .help(help)
+        // this makes it so tag parser tries to read all (unconsumed by earlier parsers)
+        // item on a command line instead of trying and failing on the first one
+        .anywhere()
+        // At this point parser produces `String` while consumer might expect some other
+        // type. [`parse`](Parser::parse) handles that
+        .parse(|s| s.parse())
+}
+
+pub fn options() -> OptionParser<Options> {
+    let block_size = tag("bs=", "BLOCK", "How many bytes to read at once")
+        .fallback(1024)
+        .display_fallback();
+    let count = tag("count=", "NUM", "How many blocks to read").fallback(1);
+    let output_file = tag("of=", "FILE", "Save results into this file");
+
+    // this consumes literal value of "+turbo" locate and produces `bool`
+    let turbo = literal("+turbo")
+        .help("Engage turbo mode!")
+        .anywhere()
+        .map(|_| true)
+        .fallback(false);
+
+    construct!(Options {
+        block_size,
+        count,
+        output_file,
+        turbo
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
// This example is still technically derive API, but derive is limited to gluing
+// things together and keeping macro complexity under control.
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    // `external` here and below derives name from the field name, looking for
+    // functions called `block_size`, `count`, etc that produce parsers of
+    // the right type.
+    // A different way would be to write down the name explicitly:
+    // #[bpaf(external(block_size), fallback(1024), display_fallback)]
+    #[bpaf(external, fallback(1024), display_fallback)]
+    block_size: usize,
+    #[bpaf(external, fallback(1))]
+    count: usize,
+    #[bpaf(external)]
+    output_file: String,
+    #[bpaf(external)]
+    turbo: bool,
+}
+
+fn block_size() -> impl Parser<usize> {
+    tag("bs=", "BLOCK", "How many bytes to read at once")
+}
+
+fn count() -> impl Parser<usize> {
+    tag("count=", "NUM", "How many blocks to read")
+}
+
+fn output_file() -> impl Parser<String> {
+    tag("of=", "FILE", "Save results into this file")
+}
+
+fn turbo() -> impl Parser<bool> {
+    literal("+turbo")
+        .help("Engage turbo mode!")
+        .anywhere()
+        .map(|_| true)
+        .fallback(false)
+}
+
+/// Parses a string that starts with `name`, returns the suffix parsed in a usual way
+fn tag<T>(name: &'static str, meta: &str, help: impl Into<Doc>) -> impl Parser<T>
+where
+    T: FromStr,
+    <T as FromStr>::Err: std::fmt::Display,
+{
+    // closure inside checks if command line argument starts with a given name
+    // and if it is - it accepts it, otherwise it behaves like it never saw it
+    // it is possible to parse OsString here and strip the prefix with
+    // `os_str_bytes` or a similar crate
+    any("", move |s: String| Some(s.strip_prefix(name)?.to_owned()))
+        // this defines custom metavar for the help message
+        // so it looks like something it designed to parse
+        .metavar(&[(name, Style::Literal), (meta, Style::Metavar)][..])
+        .help(help)
+        // this makes it so tag parser tries to read all (unconsumed by earlier parsers)
+        // item on a command line instead of trying and failing on the first one
+        .anywhere()
+        // At this point parser produces `String` while consumer might expect some other
+        // type. [`parse`](Parser::parse) handles that
+        .parse(|s| s.parse())
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Instead of usual metavariable any parsers take something that can represent any value

+
+$ app --help
+

Usage: app [bs=BLOCK] [count=NUM] of=FILE [+turbo]

+Available options:
bs=BLOCK
+
How many bytes to read at once
+
+
[default: 1024]
+
count=NUM
+
How many blocks to read
+
of=FILE
+
Save results into this file
+
+turbo
+
Engage turbo mode!
+
-h, --help
+
Prints help information
+
+

+ +
+

Output file is required in this parser, other values are optional

+
+$ app
+Error: expected of=FILE, pass --help for usage information + +
+
+$ app of=simple.txt
+Options { block_size: 1024, count: 1, output_file: "simple.txt", turbo: false } +
+

Since options are defined with anywhere - order doesn’t matter

+
+$ app bs=10 of=output.rs +turbo
+Options { block_size: 10, count: 1, output_file: "output.rs", turbo: true } +
+
+$ app +turbo bs=10 of=output.rs
+Options { block_size: 10, count: 1, output_file: "output.rs", turbo: true } +
+
+$ app bs=65536 count=12 of=hello_world.rs
+Options { block_size: 65536, count: 12, output_file: "hello_world.rs", turbo: false } +
+
+

§Command

+

A command defines a starting point for an independent subparser. Name must be a valid utf8 +string. For example cargo build invokes command "build" and after "build" cargo +starts accepting values it won’t accept otherwise

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Cmd {
+    flag: bool,
+    arg: usize,
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    flag: bool,
+    cmd: Cmd,
+}
+
+fn cmd() -> impl Parser<Cmd> {
+    let flag = long("flag")
+        .help("This flag is specific to command")
+        .switch();
+    let arg = long("arg").argument::<usize>("ARG");
+    construct!(Cmd { flag, arg })
+        .to_options()
+        .descr("Command to do something")
+        .command("cmd")
+        // you can chain add extra short and long names
+        .short('c')
+}
+
+pub fn options() -> OptionParser<Options> {
+    let flag = long("flag")
+        .help("This flag is specific to the outer layer")
+        .switch();
+    construct!(Options { flag, cmd() }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+// `command` annotation with no name gets the name from the object it is attached to,
+// but you can override it using something like #[bpaf(command("my_command"))]
+// you can chain more short and long names here to serve as aliases
+#[bpaf(command("cmd"), short('c'))]
+/// Command to do something
+pub struct Cmd {
+    /// This flag is specific to command
+    flag: bool,
+    arg: usize,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// This flag is specific to the outer layer
+    flag: bool,
+    #[bpaf(external)]
+    cmd: Cmd,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Commands show up on both outer level help

+
+$ app --help
+

Usage: app [--flag] COMMAND ...

+Available options:
--flag
+
This flag is specific to the outer layer
+
-h, --help
+
Prints help information
+
+

+Available commands:
cmd, c
+
Command to do something
+
+

+ +
+

As well as showing their own help

+
+$ app cmd --help
+

Command to do something

Usage: app cmd [--flag] --arg=ARG

+Available options:
--flag
+
This flag is specific to command
+
--arg=ARG
+
-h, --help
+
Prints help information
+
+

+ +
+

In this example there’s only one command and it is required, so is the argument inside of it

+
+$ app cmd --arg 42
+Options { flag: false, cmd: Cmd { flag: false, arg: 42 } } +
+

If you don’t specify this command - parsing will fail

+

You can have the same flag names inside and outside of the command, but it might be confusing +for the end user. This example enables the outer flag

+
+$ app --flag cmd --arg 42
+Options { flag: true, cmd: Cmd { flag: false, arg: 42 } } +
+

And this one - both inside and outside

+
+$ app --flag cmd --arg 42 --flag
+Options { flag: true, cmd: Cmd { flag: true, arg: 42 } } +
+

And that’s the confusing part - unless you add context restrictions with +adjacent and parse command first - outer flag wins. +So it’s best not to mix names on different levels

+
+$ app cmd --arg 42 --flag
+Options { flag: true, cmd: Cmd { flag: false, arg: 42 } } +
+
+

Structs§

\ No newline at end of file diff --git a/bpaf/params/sidebar-items.js b/bpaf/params/sidebar-items.js new file mode 100644 index 00000000..5ecd25da --- /dev/null +++ b/bpaf/params/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["NamedArg","ParseAny","ParseArgument","ParseCommand","ParseFlag","ParsePositional"]}; \ No newline at end of file diff --git a/bpaf/params/struct.NamedArg.html b/bpaf/params/struct.NamedArg.html new file mode 100644 index 00000000..3a2e143c --- /dev/null +++ b/bpaf/params/struct.NamedArg.html @@ -0,0 +1,1481 @@ +NamedArg in bpaf::params - Rust +

Struct bpaf::params::NamedArg

source ·
pub struct NamedArg { /* private fields */ }
Expand description

A named thing used to create flag, switch or +argument

+

§Combinatoric usage

+

Named items (argument, flag and switch) can have up to 2 visible names (one short and one long) +and multiple hidden short and long aliases if needed. It’s also possible to consume items from +environment variables using env. You usually start with short or long +function, then apply short / long / env / +help repeatedly to build a desired set of names then transform it into +a parser using flag, switch or positional.

+ +
#[derive(Debug, Clone)]
+pub enum Output {
+    ToFile(PathBuf),
+    ToConsole,
+}
+pub fn options() -> OptionParser<(usize, Output, bool)> {
+    // In most cases you don't keep `NamedArg` around long enough
+    // to assign it a name
+    let size = short('s')
+        .long("size")
+        .help("Maximum size to process")
+        .argument("SIZE");
+
+    // but it can be useful if you want to have several arguments
+    // sharing exact set of names - for example a switch (req_flag)
+    // and an argument;
+    let output = short('o').long("output");
+
+    let to_file = output
+        .clone()
+        .help("Save output to file")
+        .argument("PATH")
+        .map(Output::ToFile);
+    let to_console = output
+        .help("Print output to console")
+        .req_flag(Output::ToConsole);
+
+    // when combining multiple parsers that can conflict with each other
+    // it's a good idea to put more general first:
+    let output = construct!([to_file, to_console]);
+
+    let verbose = short('v')
+        .long("verbose")
+        .long("detailed")
+        .help("Produce a detailed report")
+        .switch();
+
+    construct!(size, output, verbose).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

--help output will contain first short and first long names that are present and won’t have +anything about hidden aliases.

+
+$ app --help
+

Usage: app -s=SIZE (-o=PATH | -o) [-v]

+Available options:
-s, --size=SIZE
+
Maximum size to process
+
-o, --output=PATH
+
Save output to file
+
-o, --output
+
Print output to console
+
-v, --verbose
+
Produce a detailed report
+
-h, --help
+
Prints help information
+
+

+ +
+

--detailed is a hidden alias and still works despite not being present in --help output +above

+
+$ app -o -s 2 --detailed
+(2, ToConsole, true) +
+

And hidden means actually hidden. While error message can suggest to fix a typo to make it a +valid visible argument

+
+$ app -o best.txt -s 10 --verbos
+Error: no such flag: --verbos, did you mean --verbose? + +
+

It will not do so for hidden aliases

+
+$ app -o best.txt -s 10 --detaile
+Error: --detaile is not expected in this context + +
+

In this example names -o and --output can be parsed by two parsers - to_file and +to_console, first one succeeds only if -o is followed by a non option name, best.txt.

+
+$ app -o best.txt --size 10
+(10, ToFile("best.txt"), false) +
+

If such name is not present - parser will try to consume one without, producing ToConsole +variant.

+
+$ app -o -s 42
+(42, ToConsole, false) +
+

If neither is present - it fails - parser for output expects one of its branches to succeed

+
+$ app -s 330
+Error: expected --output=PATH or --output, pass --help for usage information + +
+

But this can be fixed with optional (not included in this example).

+
+

§Derive usage

+

When using derive API it is possible to omit some or all the details:

+
    +
  1. If no naming information is present at all - bpaf would use field name as a long name +(or a short name if field name consists of a single character)
  2. +
  3. If short or long annotation is present without an argument - bpaf would use first character +or a full name as long and short name respectively. It won’t try to add implicit long or +short name from the previous item.
  4. +
  5. If short or long annotation is present with an argument - those are values bpaf would +use instead of the original field name
  6. +
  7. You can specify many short and long names, any past the first one of each type will +become hidden aliases
  8. +
  9. If env(arg) annotation is present - in addition to long/short names derived according to +rules 1..3 bpaf would also parse environment variable arg which can be a string literal +or an expression.
  10. +
+ +
const DB: &str = "DATABASE_VAR";
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Use verbose output
+    // No name annotation and name is not a single character:
+    // `bpaf` uses it as a long name - `--verbose`
+    pub verbose: bool,
+
+    /// Compile in a release mode
+    #[bpaf(short)]
+    // Name is long, but explicit annotation for a short name
+    // `bpaf` makes a short name from the first symbol: `-r`
+    pub release: bool,
+
+    /// Number of parallel jobs, defaults to # of CPUs
+    // Explicit annotation with a short name: `-j`
+    #[bpaf(short('j'))]
+    pub threads: Option<usize>,
+
+    /// Upload artifacts to the storage
+    // Explicit annotation for a single suppresses the oher one,
+    // but you can specify both of them. `-u` and `--upload`
+    #[bpaf(short, long)]
+    pub upload: bool,
+
+    /// List of features to activate
+    // you can mix explicit annotations with and without names
+    // when convenient, here it's `-F` and `--features`
+    #[bpaf(short('F'), long)]
+    pub features: Vec<String>,
+
+    /// Read information from the database
+    #[bpaf(env(DB))]
+    // Annotation for `env` does not affect annotation for names
+    // so `bpaf` makes `--database` flag too
+    pub database: String,
+
+    /// Only print essential information
+    #[bpaf(short, long, long("essential"))]
+    // `--essential` is a hidden ailias, `-q` and `--quiet` are visible
+    pub quiet: bool,
+
+    /// implicit long + env variable "USER"
+    #[bpaf(env("USER"))]
+    pub user: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

--help output will contain first short and first long names that are present and won’t have +anything about hidden aliases.

+
+$ app --help
+

Usage: app [--verbose] [-r] [-j=ARG] [-u] [-F=ARG]... --database=ARG [-q] --user=ARG

+Available options:
--verbose
+
Use verbose output
+
-r
+
Compile in a release mode
+
-j=ARG
+
Number of parallel jobs, defaults to # of CPUs
+
-u, --upload
+
Upload artifacts to the storage
+
-F, --features=ARG
+
List of features to activate
+
--database=ARG
+
Read information from the database
+
+
[env:DATABASE_VAR: N/A]
+
-q, --quiet
+
Only print essential information
+
--user=ARG
+
implicit long + env variable "USER"
+
+
[env:USER = "pacak"]
+
-h, --help
+
Prints help information
+
+

+ +
+

--essential is a hidden alias and still works despite not being present in --help output +above

+
+$ app --database default --essential
+Options { verbose: false, release: false, threads: None, upload: false, features: [], database: "default", quiet: true, user: "pacak" } +
+

And hidden means actually hidden. While error message can suggest to fix a typo to make it a +valid visible argument

+
+$ app --database default --quie
+Error: no such flag: --quie, did you mean --quiet? + +
+

It will not do so for hidden aliases

+
+$ app --database default --essentia
+Error: --essentia is not expected in this context + +
+

Implementations§

source§

impl NamedArg

source

pub fn short(self, short: char) -> Self

Add a short name to a flag/switch/argument

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    switch: bool,
+    arg: usize,
+    username: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let switch = short('s') // first `short` creates a builder
+        .short('S') // second switch is a hidden alias
+        .long("switch") // visible long name
+        .long("also-switch") // hidden alias
+        .help("Switch with many names")
+        .switch(); // `switch` finalizes the builder
+
+    let arg = long("argument") // long is also a builder
+        .short('a')
+        .short('A')
+        .long("also-arg")
+        .help("Argument with names")
+        .argument::<usize>("ARG");
+
+    let username = long("user")
+        .short('u')
+        .env("USER1")
+        .help("Custom user name")
+        .argument::<String>("USER");
+
+    construct!(Options {
+        switch,
+        arg,
+        username
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, short('S'), long("also-switch"))]
+    /// Switch with many names
+    switch: bool,
+    #[bpaf(short, long("argument"), short('A'), long("also-arg"))]
+    /// Argument with names
+    arg: usize,
+    #[bpaf(short, long("user"), env("USER1"), argument("USER"))]
+    /// Custom user name
+    username: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

As usual switch is optional, arguments are required

+
+$ app -a 42 -u Bobert
+Options { switch: false, arg: 42, username: "Bobert" } +
+

Help displays only visible aliases (and a current value for env arguments)

+
+$ app --help
+

Usage: app [-s] -a=ARG -u=USER

+Available options:
-s, --switch
+
Switch with many names
+
-a, --argument=ARG
+
Argument with names
+
-u, --user=USER
+
Custom user name
+
+
[env:USER1: N/A]
+
-h, --help
+
Prints help information
+
+

+ +
+

But you can still use hidden aliases, both short and long

+
+$ app --also-switch --also-arg 330 --user Bobert
+Options { switch: true, arg: 330, username: "Bobert" } +
+

And unless there’s many or similar modifiers having multiple aliases doesn’t mean +you can specify them multiple times:

+
+$ app -A 42 -a 330 -u Bobert
+Error: -a is not expected in this context + +
+

Also hidden aliases are really hidden and only meant to do backward compatibility stuff, they +won’t show up anywhere else in completions or error messages

+
+$ app -a 42 -A 330 -u Bobert
+Error: -A is not expected in this context + +
+
source

pub fn long(self, long: &'static str) -> Self

Add a long name to a flag/switch/argument

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    switch: bool,
+    arg: usize,
+    username: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let switch = short('s') // first `short` creates a builder
+        .short('S') // second switch is a hidden alias
+        .long("switch") // visible long name
+        .long("also-switch") // hidden alias
+        .help("Switch with many names")
+        .switch(); // `switch` finalizes the builder
+
+    let arg = long("argument") // long is also a builder
+        .short('a')
+        .short('A')
+        .long("also-arg")
+        .help("Argument with names")
+        .argument::<usize>("ARG");
+
+    let username = long("user")
+        .short('u')
+        .env("USER1")
+        .help("Custom user name")
+        .argument::<String>("USER");
+
+    construct!(Options {
+        switch,
+        arg,
+        username
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, short('S'), long("also-switch"))]
+    /// Switch with many names
+    switch: bool,
+    #[bpaf(short, long("argument"), short('A'), long("also-arg"))]
+    /// Argument with names
+    arg: usize,
+    #[bpaf(short, long("user"), env("USER1"), argument("USER"))]
+    /// Custom user name
+    username: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

As usual switch is optional, arguments are required

+
+$ app -a 42 -u Bobert
+Options { switch: false, arg: 42, username: "Bobert" } +
+

Help displays only visible aliases (and a current value for env arguments)

+
+$ app --help
+

Usage: app [-s] -a=ARG -u=USER

+Available options:
-s, --switch
+
Switch with many names
+
-a, --argument=ARG
+
Argument with names
+
-u, --user=USER
+
Custom user name
+
+
[env:USER1: N/A]
+
-h, --help
+
Prints help information
+
+

+ +
+

But you can still use hidden aliases, both short and long

+
+$ app --also-switch --also-arg 330 --user Bobert
+Options { switch: true, arg: 330, username: "Bobert" } +
+

And unless there’s many or similar modifiers having multiple aliases doesn’t mean +you can specify them multiple times:

+
+$ app -A 42 -a 330 -u Bobert
+Error: -a is not expected in this context + +
+

Also hidden aliases are really hidden and only meant to do backward compatibility stuff, they +won’t show up anywhere else in completions or error messages

+
+$ app -a 42 -A 330 -u Bobert
+Error: -A is not expected in this context + +
+
source

pub fn env(self, variable: &'static str) -> Self

Environment variable fallback

+

If named value isn’t present - try to fallback to this environment variable.

+

You can specify it multiple times, bpaf would use items past the first one as hidden aliases.

+

For flag and switch environment variable being present +gives the same result as the flag being present, allowing to implement things like NO_COLOR +variables:

+
$ NO_COLOR=1 app --do-something
+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    switch: bool,
+    arg: usize,
+    username: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let switch = short('s') // first `short` creates a builder
+        .short('S') // second switch is a hidden alias
+        .long("switch") // visible long name
+        .long("also-switch") // hidden alias
+        .help("Switch with many names")
+        .switch(); // `switch` finalizes the builder
+
+    let arg = long("argument") // long is also a builder
+        .short('a')
+        .short('A')
+        .long("also-arg")
+        .help("Argument with names")
+        .argument::<usize>("ARG");
+
+    let username = long("user")
+        .short('u')
+        .env("USER1")
+        .help("Custom user name")
+        .argument::<String>("USER");
+
+    construct!(Options {
+        switch,
+        arg,
+        username
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, short('S'), long("also-switch"))]
+    /// Switch with many names
+    switch: bool,
+    #[bpaf(short, long("argument"), short('A'), long("also-arg"))]
+    /// Argument with names
+    arg: usize,
+    #[bpaf(short, long("user"), env("USER1"), argument("USER"))]
+    /// Custom user name
+    username: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

As usual switch is optional, arguments are required

+
+$ app -a 42 -u Bobert
+Options { switch: false, arg: 42, username: "Bobert" } +
+

Help displays only visible aliases (and a current value for env arguments)

+
+$ app --help
+

Usage: app [-s] -a=ARG -u=USER

+Available options:
-s, --switch
+
Switch with many names
+
-a, --argument=ARG
+
Argument with names
+
-u, --user=USER
+
Custom user name
+
+
[env:USER1: N/A]
+
-h, --help
+
Prints help information
+
+

+ +
+

But you can still use hidden aliases, both short and long

+
+$ app --also-switch --also-arg 330 --user Bobert
+Options { switch: true, arg: 330, username: "Bobert" } +
+

And unless there’s many or similar modifiers having multiple aliases doesn’t mean +you can specify them multiple times:

+
+$ app -A 42 -a 330 -u Bobert
+Error: -a is not expected in this context + +
+

Also hidden aliases are really hidden and only meant to do backward compatibility stuff, they +won’t show up anywhere else in completions or error messages

+
+$ app -a 42 -A 330 -u Bobert
+Error: -A is not expected in this context + +
+
source

pub fn help<M>(self, help: M) -> Self
where + M: Into<Doc>,

Add a help message to a flag/switch/argument

+

bpaf converts doc comments and string into help by following those rules:

+
    +
  1. Everything up to the first blank line is included into a “short” help message
  2. +
  3. Everything is included into a “long” help message
  4. +
  5. bpaf preserves linebreaks followed by a line that starts with a space
  6. +
  7. Linebreaks are removed otherwise
  8. +
+

You can pass anything that can be converted into Doc, if you are not using +documentation generation functionality (doc) this can be &str.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    name: String,
+    output: Option<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help(
+            "\
+Output detailed help information, you can specify it multiple times
+
+ when used once it outputs basic diagnostic info,
+ when used twice or three times - it includes extra debugging.",
+            // ^ note extra spaces before "when" that preserve the linebreaks
+        )
+        .switch();
+    let name = long("name")
+        .help("Use this as a task name")
+        .argument("NAME");
+
+    let output = positional("OUTPUT")
+        .help("Save output to a file")
+        .optional();
+
+    construct!(Options {
+        verbose,
+        name,
+        output
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long)]
+    /// Output detailed help information, you can specify it multiple times
+    ///
+    ///  when used once it outputs basic diagnostic info,
+    ///  when used twice or three times - it includes extra debugging.
+    //  ^ note extra spaces before when that preserve the linebreaks
+    verbose: bool,
+
+    #[bpaf(argument("NAME"))]
+    /// Use this as a task name
+    name: String,
+
+    #[bpaf(positional("OUTPUT"))]
+    /// Save output to a file
+    output: Option<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

When --help used once it renders shoter version of the help information

+
+$ app --help
+

Usage: app [-v] --name=NAME [OUTPUT]

+Available positional items:
OUTPUT
+
Save output to a file
+
+

+Available options:
-v, --verbose
+
Output detailed help information, you can specify it multiple times
+
--name=NAME
+
Use this as a task name
+
-h, --help
+
Prints help information
+
+

+ +
+

When used twice - it renders full version. Documentation generator uses full +version as well

+
+$ app --help --help
+

Usage: app [-v] --name=NAME [OUTPUT]

+Available positional items:
OUTPUT
+
Save output to a file
+
+

+Available options:
-v, --verbose
+
Output detailed help information, you can specify it multiple times
+ when used once it outputs basic diagnostic info,
+when used twice or three times - it includes extra debugging.
+
--name=NAME
+
Use this as a task name
+
-h, --help
+
Prints help information
+
+

+ +
+

Presence or absense of a help message should not affect the parser’s output

+
+$ app --name Bob output.txt
+Options { verbose: false, name: "Bob", output: Some("output.txt") } +
+
source

pub fn switch(self) -> ParseFlag<bool>

Simple boolean flag

+

A special case of a flag that gets decoded into a bool, mostly serves as a convenient +shortcut to .flag(true, false).

+

In Derive API bpaf would use switch for bool fields inside named structs that don’t +have other consumer annotations (flag, +argument, etc).

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    release: bool,
+    default_features: bool,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help("Produce verbose output")
+        .switch();
+    let release = long("release")
+        .help("Build artifacts in release mode")
+        .flag(true, false);
+    let default_features = long("no-default-features")
+        .help("Do not activate default features")
+        // default_features uses opposite values,
+        // producing `true` when value is absent
+        .flag(false, true);
+
+    construct!(Options {
+        verbose,
+        release,
+        default_features,
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Produce verbose output
+    // bpaf uses `switch` for `bool` fields in named
+    // structs unless consumer attribute is present.
+    // But it is also possible to give it explicit
+    // consumer annotation to serve as a reminder:
+    // #[bpaf(short, long, switch)]
+    #[bpaf(short, long)]
+    verbose: bool,
+
+    #[bpaf(flag(true, false))]
+    /// Build artifacts in release mode
+    release: bool,
+
+    /// Do not activate default features
+    // default_features uses opposite values,
+    // producing `true` when value is absent
+    #[bpaf(long("no-default-features"), flag(false, true))]
+    default_features: bool,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help output bpaf shows switches as usual flags with no meta variable attached

+
+$ app --help
+

Usage: app [-v] [--release] [--no-default-features]

+Available options:
-v, --verbose
+
Produce verbose output
+
--release
+
Build artifacts in release mode
+
--no-default-features
+
Do not activate default features
+
-h, --help
+
Prints help information
+
+

+ +
+

Both switch and flag succeed if value is not present, switch returns true, flag returns +second value.

+
+$ app
+Options { verbose: false, release: false, default_features: true } +
+

When value is present - switch returns true, flag returns first value.

+
+$ app --verbose --no-default-features --detailed
+Error: --detailed is not expected in this context + +
+

Like with most parsrs unless specified switch and flag consume at most one item from the +command line:

+
+$ app --no-default-features --no-default-features
+Error: argument --no-default-features cannot be used multiple times in this context + +
+
source

pub fn flag<T>(self, present: T, absent: T) -> ParseFlag<T>
where + T: Clone + 'static,

Flag with custom present/absent values

+

More generic version of switch that can use arbitrary type instead of +bool.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    decision: Decision,
+}
+
+#[derive(Debug, Clone)]
+pub enum Decision {
+    Yes,
+    No,
+}
+
+fn parse_decision() -> impl Parser<Decision> {
+    long("decision")
+        .help("Positive decision")
+        .flag(Decision::Yes, Decision::No)
+}
+
+pub fn options() -> OptionParser<Options> {
+    let decision = parse_decision();
+    construct!(Options { decision }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Positive decision
+    #[bpaf(flag(Decision::Yes, Decision::No))]
+    decision: Decision,
+}
+
+#[derive(Debug, Clone)]
+pub enum Decision {
+    Yes,
+    No,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help output bpaf shows flags with no meta variable attached

+
+$ app --help
+

Usage: app [--decision]

+Available options:
--decision
+
Positive decision
+
-h, --help
+
Prints help information
+
+

+ +
+

Presense of a long name is decoded into Yes

+
+$ app --decision
+Options { decision: Yes } +
+

Absense is No

+
+$ app
+Options { decision: No } +
+
source

pub fn req_flag<T>(self, present: T) -> impl Parser<T>
where + T: Clone + 'static,

Required flag with custom value

+

Similar to flag takes no option arguments, but would only +succeed if user specifies its name on a command line. +Works best in combination with other parsers.

+

In derive style API bpaf would transform field-less enum variants into a parser +that accepts one of it’s variant names as req_flag. Additionally bpaf handles () +fields as req_flag.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub enum Style {
+    Intel,
+    Att,
+    Llvm,
+}
+
+#[derive(Debug, Clone)]
+pub enum Report {
+    /// Include defailed report
+    Detailed,
+    /// Include minimal report
+    Minimal,
+    /// No preferences
+    Undecided,
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    agree: (),
+    style: Style,
+    report: Report,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let agree = long("agree")
+        .help("You must agree to perform the action")
+        .req_flag(());
+
+    let intel = long("intel")
+        .help("Show assembly using Intel style")
+        .req_flag(Style::Intel);
+    let att = long("att")
+        .help("Show assembly using AT&T style")
+        .req_flag(Style::Att);
+    let llvm = long("llvm").help("Show llvm-ir").req_flag(Style::Llvm);
+    let style = construct!([intel, att, llvm]);
+
+    let detailed = long("detailed")
+        .help("Include detailed report")
+        .req_flag(Report::Detailed);
+    let minimal = long("minimal")
+        .help("Include minimal report")
+        .req_flag(Report::Minimal);
+    let report = construct!([detailed, minimal]).fallback(Report::Undecided);
+
+    construct!(Options {
+        agree,
+        style,
+        report
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+pub enum Style {
+    /// Show assembly using Intel style
+    Intel,
+    /// Show assembly using AT&T style
+    Att,
+    /// Show llvm-ir
+    Llvm,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(fallback(Report::Undecided))]
+pub enum Report {
+    /// Include detailed report
+    Detailed,
+    /// Include minimal report
+    Minimal,
+    #[bpaf(skip)]
+    /// No preferences
+    Undecided,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// You must agree to perform the action
+    agree: (),
+    // external here uses explicit reference to function `style`
+    // generated above
+    #[bpaf(external(style))]
+    style: Style,
+    // here reference is implicit and derived from field name: `report`
+    #[bpaf(external)]
+    report: Report,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help message req_flag look similarly to switch and +flag

+
+$ app --help
+

Usage: app --agree (--intel | --att | --llvm) [--detailed | --minimal]

+Available options:
--agree
+
You must agree to perform the action
+
--intel
+
Show assembly using Intel style
+
--att
+
Show assembly using AT&T style
+
--llvm
+
Show llvm-ir
+
--detailed
+
Include detailed report
+
--minimal
+
Include minimal report
+
-h, --help
+
Prints help information
+
+

+ +
+

Example contains two parsers that fails without any input: agree requires passing --agree

+
+$ app
+Error: expected --agree, pass --help for usage information + +
+

While style takes one of several possible values

+
+$ app --agree
+Error: expected --intel, --att, or more, pass --help for usage information + +
+

It is possible to alter the behavior using fallback or +hide.

+
+$ app --agree --intel
+Options { agree: (), style: Intel, report: Undecided } +
+

While parser for style takes any posted output - it won’t take multiple of them at once +(unless other combinators such as many permit it) or last.

+
+$ app --agree --att --llvm
+Error: --llvm cannot be used at the same time as --att + +
+
source

pub fn argument<T>(self, metavar: &'static str) -> ParseArgument<T>
where + T: FromStr + 'static,

Argument

+

A short (-a) or long (--name) name followed by either a space or = and +then by a string literal. -f foo, --flag bar or -o=- are all valid argument examples. Note, string +literal can’t start with - unless separated from the flag with =. For short flags value +can follow immediately: -fbar.

+

When using combinatoring API you can specify the type with turbofish, for parsing types +that don’t implement FromStr you can use consume a String/OsString first and parse +it by hands.

+

For metavar value you should pick something short and descriptive about the parameter, +usually in capital letters. For example for an abstract file parameter it could be +"FILE", for a username - "USER", etc.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    name: String,
+    age: usize,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let name = short('n')
+        .long("name")
+        .help("Specify user name")
+        // you can specify exact type argument should produce
+        // for as long as it implements `FromStr`
+        .argument::<String>("NAME");
+
+    let age = long("age")
+        .help("Specify user age")
+        // but often rust can figure it out from the context,
+        // here age is going to be `usize`
+        .argument("AGE")
+        .fallback(18)
+        .display_fallback();
+
+    construct!(Options { name, age }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    // you can specify exact type argument should produce
+    // for as long as it implements `FromStr`
+    #[bpaf(short, long, argument::<String>("NAME"))]
+    /// Specify user name
+    name: String,
+    // but often rust can figure it out from the context,
+    // here age is going to be `usize`
+    #[bpaf(argument("AGE"), fallback(18), display_fallback)]
+    /// Specify user age
+    age: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +
+$ app --help
+

Usage: app -n=NAME [--age=AGE]

+Available options:
-n, --name=NAME
+
Specify user name
+
--age=AGE
+
Specify user age
+
+
[default: 18]
+
-h, --help
+
Prints help information
+
+

+ +
+

--help shows arguments as a short name with attached metavariable

+

Value can be separated from flag by space, = sign

+
+$ app --name Bob --age 12
+Options { name: "Bob", age: 12 } +
+
+$ app --name "Bob" --age=12
+Options { name: "Bob", age: 12 } +
+
+$ app --name=Bob
+Options { name: "Bob", age: 18 } +
+
+$ app --name="Bob"
+Options { name: "Bob", age: 18 } +
+

Or in case of short name - be directly adjacent to it

+
+$ app -nBob
+Options { name: "Bob", age: 18 } +
+

For long names - this doesn’t work since parser can’t tell where name +stops and argument begins:

+
+$ app --age12
+Error: no such flag: --age12, did you mean --age? + +
+

Either way - value is required, passing just the argument name results in parse failure

+
+$ app --name
+Error: --name requires an argument NAME + +
+
+

You can further restrict it using adjacent

+

Trait Implementations§

source§

impl Clone for NamedArg

source§

fn clone(&self) -> NamedArg

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for NamedArg

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/params/struct.ParseAny.html b/bpaf/params/struct.ParseAny.html new file mode 100644 index 00000000..cfb6da29 --- /dev/null +++ b/bpaf/params/struct.ParseAny.html @@ -0,0 +1,67 @@ +ParseAny in bpaf::params - Rust +

Struct bpaf::params::ParseAny

source ·
pub struct ParseAny<T> { /* private fields */ }
Expand description

Consume an arbitrary value that satisfies a condition, created with any, implements +anywhere.

+

Implementations§

source§

impl<T> ParseAny<T>

source

pub fn help<M: Into<Doc>>(self, help: M) -> Self

Add a help message to any parser. +See examples in any

+
source

pub fn metavar<M: Into<Doc>>(self, metavar: M) -> Self

Replace metavar with a custom value +See examples in any

+
source

pub fn anywhere(self) -> Self

Try to apply the parser to each unconsumed element instead of just the front one

+

By default any tries to parse just the front unconsumed item behaving similar to +positional parser, anywhere changes it so it applies to every unconsumed item, +similar to argument parser.

+

See examples in any

+

Trait Implementations§

source§

impl<T> Parser<T> for ParseAny<T>

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<T> !RefUnwindSafe for ParseAny<T>

§

impl<T> !Send for ParseAny<T>

§

impl<T> !Sync for ParseAny<T>

§

impl<T> Unpin for ParseAny<T>

§

impl<T> !UnwindSafe for ParseAny<T>

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/params/struct.ParseArgument.html b/bpaf/params/struct.ParseArgument.html new file mode 100644 index 00000000..b0fbdcc3 --- /dev/null +++ b/bpaf/params/struct.ParseArgument.html @@ -0,0 +1,208 @@ +ParseArgument in bpaf::params - Rust +

Struct bpaf::params::ParseArgument

source ·
pub struct ParseArgument<T> { /* private fields */ }
Expand description

Parser for a named argument, created with argument.

+

Implementations§

source§

impl<T> ParseArgument<T>

source

pub fn help<M>(self, help: M) -> Self
where + M: Into<Doc>,

Add a help message to an argument

+

See NamedArg::help

+
source§

impl<T> ParseArgument<T>

source

pub fn adjacent(self) -> Self

Restrict parsed arguments to have both flag and a value in the same word:

+

In other words adjacent restricted ParseArgument would accept --flag=value or +-fbar but not --flag value. Note, this is different from adjacent, +just plays a similar role.

+

Should allow to parse some of the more unusual things

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    package: String,
+}
+
+fn package() -> impl Parser<String> {
+    long("package")
+        .short('p')
+        .help("Package to use")
+        .argument("SPEC")
+        .adjacent()
+}
+
+pub fn options() -> OptionParser<Options> {
+    construct!(Options { package() }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, argument("SPEC"), adjacent)]
+    /// Package to use
+    package: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +
+$ app --help
+

Usage: app -p=SPEC

+Available options:
-p, --package=SPEC
+
Package to use
+
-h, --help
+
Prints help information
+
+

+ +
+

As with regular argument its adjacent variant is required by default

+
+$ app
+Error: expected --package=SPEC, pass --help for usage information + +
+

But unlike regular variant adjacent requires name and value to be separated by = only

+
+$ app -p=htb
+Options { package: "htb" } +
+
+$ app --package=bpaf
+Options { package: "bpaf" } +
+

Separating them by space results in parse failure

+
+$ app --package htb
+Error: expected --package=SPEC, got --package. Pass --help for usage information + +
+
+$ app -p htb
+Error: expected --package=SPEC, got -p. Pass --help for usage information + +
+
+$ app --package
+Error: expected --package=SPEC, got --package. Pass --help for usage information + +
+

Trait Implementations§

source§

impl<T: Clone> Clone for ParseArgument<T>

source§

fn clone(&self) -> ParseArgument<T>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T> Parser<T> for ParseArgument<T>
where + T: FromStr + 'static, + <T as FromStr>::Err: Display,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<T> RefUnwindSafe for ParseArgument<T>
where + T: RefUnwindSafe,

§

impl<T> Send for ParseArgument<T>
where + T: Send,

§

impl<T> Sync for ParseArgument<T>
where + T: Sync,

§

impl<T> Unpin for ParseArgument<T>
where + T: Unpin,

§

impl<T> UnwindSafe for ParseArgument<T>
where + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/params/struct.ParseCommand.html b/bpaf/params/struct.ParseCommand.html new file mode 100644 index 00000000..c8b63cf4 --- /dev/null +++ b/bpaf/params/struct.ParseCommand.html @@ -0,0 +1,291 @@ +ParseCommand in bpaf::params - Rust +

Struct bpaf::params::ParseCommand

source ·
pub struct ParseCommand<T> { /* private fields */ }
Expand description

Builder structure for the [command]

+

Created with [command], implements parser for the inner structure, gives access to help.

+

Implementations§

source§

impl<P> ParseCommand<P>

source

pub fn help<M>(self, help: M) -> Self
where + M: Into<Doc>,

Add a brief description to a command

+

bpaf uses this description along with the command name +in help output so it shouldn’t exceed one or two lines. If help isn’t specified +bpaf falls back to descr from the inner parser.

+
§Combinatoric usage
+
fn inner() -> OptionParser<bool> {
+    short('i')
+        .help("Mysterious inner switch")
+        .switch()
+        .to_options()
+        .descr("performs an operation")
+}
+
+fn mysterious_parser() -> impl Parser<bool> {
+    inner().command("mystery")
+        .help("This command performs a mystery operation")
+}
+
§Derive usage
+

bpaf_derive uses doc comments for inner parser, no specific options are available. +See descr for more details

+ +
/// This command performs a mystery operation
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(command)]
+struct Mystery {
+    #[bpaf(short)]
+    /// Mysterious inner switch
+    inner: bool,
+}
+
§Example
$ app --help
+    <skip>
+Available commands:
+    mystery  This command performs a mystery operation
+
source

pub fn short(self, short: char) -> Self

Add a custom short alias for a command

+

Behavior is similar to short, only first short name is visible.

+
source

pub fn long(self, long: &'static str) -> Self

Add a custom hidden long alias for a command

+

Behavior is similar to long, but since you had to specify the first long +name when making the command - this one becomes a hidden alias.

+
source

pub fn adjacent(self) -> Self

Allow for the command to succeed even if there are non consumed items present

+

Normally a subcommand parser should handle the rest of the unconsumed elements thus +allowing only “vertical” chaining of commands. adjacent modifier lets command parser to +succeed if there are leftovers for as long as all comsumed items form a single adjacent +block. This opens possibilities to chain commands sequentially.

+

Let’s consider two examples with consumed items marked in bold :

+
    +
  • cmd -a -b -c -d
  • +
  • cmd -a -c -b -d
  • +
+

In the first example -b breaks the adjacency for all the consumed items so parsing will fail, +while here in the second one the name and all the consumed items are adjacent to each other so +parsing will succeed.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    premium: bool,
+    commands: Vec<Cmd>,
+}
+
+#[derive(Debug, Clone)]
+// shape of the variants doesn't really matter, let's use all of them :)
+enum Cmd {
+    Eat(String),
+    Drink { coffee: bool },
+    Sleep { time: usize },
+}
+
+fn cmd() -> impl Parser<Cmd> {
+    let eat = positional::<String>("FOOD")
+        .to_options()
+        .descr("Performs eating action")
+        .command("eat")
+        .adjacent()
+        .map(Cmd::Eat);
+
+    let coffee = long("coffee")
+        .help("Are you going to drink coffee?")
+        .switch();
+    let drink = construct!(Cmd::Drink { coffee })
+        .to_options()
+        .descr("Performs drinking action")
+        .command("drink")
+        .adjacent();
+
+    let time = long("time").argument::<usize>("HOURS");
+    let sleep = construct!(Cmd::Sleep { time })
+        .to_options()
+        .descr("Performs taking a nap action")
+        .command("sleep")
+        .adjacent();
+
+    construct!([eat, drink, sleep])
+}
+
+pub fn options() -> OptionParser<Options> {
+    let premium = short('p')
+        .long("premium")
+        .help("Opt in for premium serivces")
+        .switch();
+    let commands = cmd().many();
+    construct!(Options { premium, commands }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long)]
+    /// Opt in for premium serivces
+    pub premium: bool,
+    #[bpaf(external(cmd), many)]
+    pub commands: Vec<Cmd>,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+pub enum Cmd {
+    #[bpaf(command, adjacent)]
+    /// Performs eating action
+    Eat(#[bpaf(positional("FOOD"))] String),
+    #[bpaf(command, adjacent)]
+    /// Performs drinking action
+    Drink {
+        /// Are you going to drink coffee?
+        coffee: bool,
+    },
+    #[bpaf(command, adjacent)]
+    /// Performs taking a nap action
+    Sleep {
+        #[bpaf(argument("HOURS"))]
+        time: usize,
+    },
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Example implements a parser that supports one of three possible commands:

+
+$ app --help
+

Usage: app [-p] [COMMAND ...]...

+Available options:
-p, --premium
+
Opt in for premium serivces
+
-h, --help
+
Prints help information
+
+

+Available commands:
eat
+
Performs eating action
+
drink
+
Performs drinking action
+
sleep
+
Performs taking a nap action
+
+

+ +
+

As usual every command comes with its own help

+
+$ app drink --help
+

Performs drinking action

Usage: app drink [--coffee]

+Available options:
--coffee
+
Are you going to drink coffee?
+
-h, --help
+
Prints help information
+
+

+ +
+

Normally you can use one command at a time, but making commands adjacent lets +parser to succeed after consuming an adjacent block only and leaving leftovers for the rest of +the parser, consuming them as a Vec<Cmd> with many allows to chain multiple +items sequentially

+
+$ app eat Fastfood drink --coffee sleep --time=5
+Options { premium: false, commands: [Eat("Fastfood"), Drink { coffee: true }, Sleep { time: 5 }] } +
+

The way this works is by running parsers for each command. In the first iteration eat succeeds, +it consumes eat fastfood portion and appends its value to the resulting vector. Then second +iteration runs on leftovers, in this case it will be drink --coffee sleep --time=5. +Here drink succeeds and consumes drink --coffee portion, then sleep parser runs, etc.

+

You can mix chained commands with regular arguments that belong to the top level parser

+
+$ app sleep --time 10 --premium eat 'Bak Kut Teh' drink
+Options { premium: true, commands: [Sleep { time: 10 }, Eat("Bak Kut Teh"), Drink { coffee: false }] } +
+

But not inside the command itself since values consumed by the command are not going to be +adjacent

+
+$ app sleep --time 10 eat --premium 'Bak Kut Teh' drink
+Error: expected FOOD, pass --help for usage information + +
+

Trait Implementations§

source§

impl<T> Parser<T> for ParseCommand<T>

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<T> !RefUnwindSafe for ParseCommand<T>

§

impl<T> !Send for ParseCommand<T>

§

impl<T> !Sync for ParseCommand<T>

§

impl<T> Unpin for ParseCommand<T>

§

impl<T> !UnwindSafe for ParseCommand<T>

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/params/struct.ParseFlag.html b/bpaf/params/struct.ParseFlag.html new file mode 100644 index 00000000..65082abc --- /dev/null +++ b/bpaf/params/struct.ParseFlag.html @@ -0,0 +1,66 @@ +ParseFlag in bpaf::params - Rust +

Struct bpaf::params::ParseFlag

source ·
pub struct ParseFlag<T> { /* private fields */ }
Expand description

Parser for a named switch, created with NamedArg::flag or NamedArg::switch

+

Implementations§

source§

impl<T> ParseFlag<T>

source

pub fn help<M>(self, help: M) -> Self
where + M: Into<Doc>,

Add a help message to flag

+

See NamedArg::help

+

Trait Implementations§

source§

impl<T: Clone> Clone for ParseFlag<T>

source§

fn clone(&self) -> ParseFlag<T>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T: Clone + 'static> Parser<T> for ParseFlag<T>

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<T> RefUnwindSafe for ParseFlag<T>
where + T: RefUnwindSafe,

§

impl<T> Send for ParseFlag<T>
where + T: Send,

§

impl<T> Sync for ParseFlag<T>
where + T: Sync,

§

impl<T> Unpin for ParseFlag<T>
where + T: Unpin,

§

impl<T> UnwindSafe for ParseFlag<T>
where + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/params/struct.ParsePositional.html b/bpaf/params/struct.ParsePositional.html new file mode 100644 index 00000000..205cbbfb --- /dev/null +++ b/bpaf/params/struct.ParsePositional.html @@ -0,0 +1,334 @@ +ParsePositional in bpaf::params - Rust +
pub struct ParsePositional<T> { /* private fields */ }
Expand description

Parse a positional item, created with positional

+

You can add extra information to positional parsers with help +and strict on this struct.

+

Implementations§

source§

impl<T> ParsePositional<T>

source

pub fn help<M>(self, help: M) -> Self
where + M: Into<Doc>,

Add a help message to a positional parser

+

bpaf converts doc comments and string into help by following those rules:

+
    +
  1. Everything up to the first blank line is included into a “short” help message
  2. +
  3. Everything is included into a “long” help message
  4. +
  5. bpaf preserves linebreaks followed by a line that starts with a space
  6. +
  7. Linebreaks are removed otherwise
  8. +
+

You can pass anything that can be converted into Doc, if you are not using +documentation generation functionality (doc) this can be &str.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    crate_name: String,
+    feature_name: Option<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help("Display detailed information")
+        .switch();
+
+    let crate_name = positional("CRATE").help("Crate name to use");
+
+    let feature_name = positional("FEATURE")
+        .help("Display information about this feature")
+        .optional();
+
+    construct!(Options {
+        verbose,
+        // You must place positional items and commands after
+        // all other parsers
+        crate_name,
+        feature_name
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Display detailed information
+    #[bpaf(short, long)]
+    verbose: bool,
+
+    // You must place positional items and commands after
+    // all other parsers
+    #[bpaf(positional("CRATE"))]
+    /// Crate name to use
+    crate_name: String,
+
+    #[bpaf(positional("FEATURE"))]
+    /// Display information about this feature
+    feature_name: Option<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Positional items show up in a separate group of arguments if they contain a help message, +otherwise they will show up only in Usage part.

+
+$ app --help
+

Usage: app [-v] CRATE [FEATURE]

+Available positional items:
CRATE
+
Crate name to use
+
FEATURE
+
Display information about this feature
+
+

+Available options:
-v, --verbose
+
Display detailed information
+
-h, --help
+
Prints help information
+
+

+ +
+

You can mix positional items with regular items

+
+$ app --verbose bpaf
+Options { verbose: true, crate_name: "bpaf", feature_name: None } +
+

And since bpaf API expects to have non positional items consumed before positional ones - you +can use them in a different order. In this example bpaf corresponds to a crate_name field and +--verbose – to verbose.

+
+$ app bpaf --verbose
+Options { verbose: true, crate_name: "bpaf", feature_name: None } +
+

In previous examples optional field feature was missing, this one contains it.

+
+$ app bpaf autocomplete
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("autocomplete") } +
+

Users can use -- to tell bpaf to treat remaining items as positionals - this might be +required to handle unusual items.

+
+$ app bpaf -- --verbose
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("--verbose") } +
+
+$ app -- bpaf --verbose
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("--verbose") } +
+

Without using -- bpaf would only accept items that don’t start with - as positional.

+
+$ app --detailed
+Error: expected CRATE, got --detailed. Pass --help for usage information + +
+
+$ app --verbose
+Error: expected CRATE, pass --help for usage information + +
+

You can use any to work around this restriction.

+
source

pub fn strict(self) -> Self

Changes positional parser to be a “strict” positional

+

Usually positional items can appear anywhere on a command line:

+
$ ls -d bpaf
+$ ls bpaf -d
+
+

here ls takes a positional item bpaf and a flag -d

+

But in some cases it might be useful to have a stricter separation between +positonal items and flags, such as passing arguments to a subprocess:

+
$ cargo run --example basic -- --help
+
+

here cargo takes a --help as a positional item and passes it to the example

+

bpaf allows to require user to pass -- for positional items with strict annotation. +bpaf would display such positional elements differently in usage line as well.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    binary: String,
+    args: Vec<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help("Produce detailed report")
+        .switch();
+    let binary = long("bin").help("Binary to execute").argument("BIN");
+    let args = positional("ARG")
+        .help("Arguments for the binary")
+        .strict()
+        .many();
+    construct!(Options {
+        verbose,
+        binary,
+        args
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long)]
+    /// Produce detailed report
+    verbose: bool,
+    #[bpaf(long("bin"), argument("BIN"))]
+    /// Binary to execute
+    binary: String,
+    #[bpaf(positional("ARG"), strict, many)]
+    /// Arguments for the binary
+    args: Vec<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Usage line for a cargo-run like app that takes an app name and possibly many strictly +positional child arguments can look like this:

+
+$ app --help
+

Usage: app [-v] --bin=BIN -- [ARG]...

+Available positional items:
ARG
+
Arguments for the binary
+
+

+Available options:
-v, --verbose
+
Produce detailed report
+
--bin=BIN
+
Binary to execute
+
-h, --help
+
Prints help information
+
+

+ +
+

Here any argument passed before double dash goes to the parser itself

+
+$ app --bin dd --verbose
+Options { verbose: true, binary: "dd", args: [] } +
+

Anything after it - collected into strict arguments

+
+$ app --bin dd -- --verbose
+Options { verbose: false, binary: "dd", args: ["--verbose"] } +
+

Trait Implementations§

source§

impl<T: Clone> Clone for ParsePositional<T>

source§

fn clone(&self) -> ParsePositional<T>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T> Parser<T> for ParsePositional<T>
where + T: FromStr + 'static, + <T as FromStr>::Err: Display,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<T> RefUnwindSafe for ParsePositional<T>
where + T: RefUnwindSafe,

§

impl<T> Send for ParsePositional<T>
where + T: Send,

§

impl<T> Sync for ParsePositional<T>
where + T: Sync,

§

impl<T> Unpin for ParsePositional<T>
where + T: Unpin,

§

impl<T> UnwindSafe for ParsePositional<T>
where + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/index.html b/bpaf/parsers/index.html new file mode 100644 index 00000000..c3d65dc9 --- /dev/null +++ b/bpaf/parsers/index.html @@ -0,0 +1,18 @@ +bpaf::parsers - Rust +

Module bpaf::parsers

source ·
Expand description

This module exposes parsers that accept further configuration with builder pattern

+

In most cases you won’t be using those names directly, they’re only listed here to provide +access to documentation

+

Structs§

\ No newline at end of file diff --git a/bpaf/parsers/sidebar-items.js b/bpaf/parsers/sidebar-items.js new file mode 100644 index 00000000..905a1dd8 --- /dev/null +++ b/bpaf/parsers/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":["NamedArg","ParseAny","ParseArgument","ParseCollect","ParseCommand","ParseCompShell","ParseCon","ParseCount","ParseFallback","ParseFallbackWith","ParseFlag","ParseLast","ParseMany","ParseOptional","ParsePositional","ParseSome"]}; \ No newline at end of file diff --git a/bpaf/parsers/struct.NamedArg.html b/bpaf/parsers/struct.NamedArg.html new file mode 100644 index 00000000..92609a95 --- /dev/null +++ b/bpaf/parsers/struct.NamedArg.html @@ -0,0 +1,1481 @@ +NamedArg in bpaf::parsers - Rust +

Struct bpaf::parsers::NamedArg

source ·
pub struct NamedArg { /* private fields */ }
Expand description

A named thing used to create flag, switch or +argument

+

§Combinatoric usage

+

Named items (argument, flag and switch) can have up to 2 visible names (one short and one long) +and multiple hidden short and long aliases if needed. It’s also possible to consume items from +environment variables using env. You usually start with short or long +function, then apply short / long / env / +help repeatedly to build a desired set of names then transform it into +a parser using flag, switch or positional.

+ +
#[derive(Debug, Clone)]
+pub enum Output {
+    ToFile(PathBuf),
+    ToConsole,
+}
+pub fn options() -> OptionParser<(usize, Output, bool)> {
+    // In most cases you don't keep `NamedArg` around long enough
+    // to assign it a name
+    let size = short('s')
+        .long("size")
+        .help("Maximum size to process")
+        .argument("SIZE");
+
+    // but it can be useful if you want to have several arguments
+    // sharing exact set of names - for example a switch (req_flag)
+    // and an argument;
+    let output = short('o').long("output");
+
+    let to_file = output
+        .clone()
+        .help("Save output to file")
+        .argument("PATH")
+        .map(Output::ToFile);
+    let to_console = output
+        .help("Print output to console")
+        .req_flag(Output::ToConsole);
+
+    // when combining multiple parsers that can conflict with each other
+    // it's a good idea to put more general first:
+    let output = construct!([to_file, to_console]);
+
+    let verbose = short('v')
+        .long("verbose")
+        .long("detailed")
+        .help("Produce a detailed report")
+        .switch();
+
+    construct!(size, output, verbose).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

--help output will contain first short and first long names that are present and won’t have +anything about hidden aliases.

+
+$ app --help
+

Usage: app -s=SIZE (-o=PATH | -o) [-v]

+Available options:
-s, --size=SIZE
+
Maximum size to process
+
-o, --output=PATH
+
Save output to file
+
-o, --output
+
Print output to console
+
-v, --verbose
+
Produce a detailed report
+
-h, --help
+
Prints help information
+
+

+ +
+

--detailed is a hidden alias and still works despite not being present in --help output +above

+
+$ app -o -s 2 --detailed
+(2, ToConsole, true) +
+

And hidden means actually hidden. While error message can suggest to fix a typo to make it a +valid visible argument

+
+$ app -o best.txt -s 10 --verbos
+Error: no such flag: --verbos, did you mean --verbose? + +
+

It will not do so for hidden aliases

+
+$ app -o best.txt -s 10 --detaile
+Error: --detaile is not expected in this context + +
+

In this example names -o and --output can be parsed by two parsers - to_file and +to_console, first one succeeds only if -o is followed by a non option name, best.txt.

+
+$ app -o best.txt --size 10
+(10, ToFile("best.txt"), false) +
+

If such name is not present - parser will try to consume one without, producing ToConsole +variant.

+
+$ app -o -s 42
+(42, ToConsole, false) +
+

If neither is present - it fails - parser for output expects one of its branches to succeed

+
+$ app -s 330
+Error: expected --output=PATH or --output, pass --help for usage information + +
+

But this can be fixed with optional (not included in this example).

+
+

§Derive usage

+

When using derive API it is possible to omit some or all the details:

+
    +
  1. If no naming information is present at all - bpaf would use field name as a long name +(or a short name if field name consists of a single character)
  2. +
  3. If short or long annotation is present without an argument - bpaf would use first character +or a full name as long and short name respectively. It won’t try to add implicit long or +short name from the previous item.
  4. +
  5. If short or long annotation is present with an argument - those are values bpaf would +use instead of the original field name
  6. +
  7. You can specify many short and long names, any past the first one of each type will +become hidden aliases
  8. +
  9. If env(arg) annotation is present - in addition to long/short names derived according to +rules 1..3 bpaf would also parse environment variable arg which can be a string literal +or an expression.
  10. +
+ +
const DB: &str = "DATABASE_VAR";
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Use verbose output
+    // No name annotation and name is not a single character:
+    // `bpaf` uses it as a long name - `--verbose`
+    pub verbose: bool,
+
+    /// Compile in a release mode
+    #[bpaf(short)]
+    // Name is long, but explicit annotation for a short name
+    // `bpaf` makes a short name from the first symbol: `-r`
+    pub release: bool,
+
+    /// Number of parallel jobs, defaults to # of CPUs
+    // Explicit annotation with a short name: `-j`
+    #[bpaf(short('j'))]
+    pub threads: Option<usize>,
+
+    /// Upload artifacts to the storage
+    // Explicit annotation for a single suppresses the oher one,
+    // but you can specify both of them. `-u` and `--upload`
+    #[bpaf(short, long)]
+    pub upload: bool,
+
+    /// List of features to activate
+    // you can mix explicit annotations with and without names
+    // when convenient, here it's `-F` and `--features`
+    #[bpaf(short('F'), long)]
+    pub features: Vec<String>,
+
+    /// Read information from the database
+    #[bpaf(env(DB))]
+    // Annotation for `env` does not affect annotation for names
+    // so `bpaf` makes `--database` flag too
+    pub database: String,
+
+    /// Only print essential information
+    #[bpaf(short, long, long("essential"))]
+    // `--essential` is a hidden ailias, `-q` and `--quiet` are visible
+    pub quiet: bool,
+
+    /// implicit long + env variable "USER"
+    #[bpaf(env("USER"))]
+    pub user: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

--help output will contain first short and first long names that are present and won’t have +anything about hidden aliases.

+
+$ app --help
+

Usage: app [--verbose] [-r] [-j=ARG] [-u] [-F=ARG]... --database=ARG [-q] --user=ARG

+Available options:
--verbose
+
Use verbose output
+
-r
+
Compile in a release mode
+
-j=ARG
+
Number of parallel jobs, defaults to # of CPUs
+
-u, --upload
+
Upload artifacts to the storage
+
-F, --features=ARG
+
List of features to activate
+
--database=ARG
+
Read information from the database
+
+
[env:DATABASE_VAR: N/A]
+
-q, --quiet
+
Only print essential information
+
--user=ARG
+
implicit long + env variable "USER"
+
+
[env:USER = "pacak"]
+
-h, --help
+
Prints help information
+
+

+ +
+

--essential is a hidden alias and still works despite not being present in --help output +above

+
+$ app --database default --essential
+Options { verbose: false, release: false, threads: None, upload: false, features: [], database: "default", quiet: true, user: "pacak" } +
+

And hidden means actually hidden. While error message can suggest to fix a typo to make it a +valid visible argument

+
+$ app --database default --quie
+Error: no such flag: --quie, did you mean --quiet? + +
+

It will not do so for hidden aliases

+
+$ app --database default --essentia
+Error: --essentia is not expected in this context + +
+

Implementations§

source§

impl NamedArg

source

pub fn short(self, short: char) -> Self

Add a short name to a flag/switch/argument

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    switch: bool,
+    arg: usize,
+    username: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let switch = short('s') // first `short` creates a builder
+        .short('S') // second switch is a hidden alias
+        .long("switch") // visible long name
+        .long("also-switch") // hidden alias
+        .help("Switch with many names")
+        .switch(); // `switch` finalizes the builder
+
+    let arg = long("argument") // long is also a builder
+        .short('a')
+        .short('A')
+        .long("also-arg")
+        .help("Argument with names")
+        .argument::<usize>("ARG");
+
+    let username = long("user")
+        .short('u')
+        .env("USER1")
+        .help("Custom user name")
+        .argument::<String>("USER");
+
+    construct!(Options {
+        switch,
+        arg,
+        username
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, short('S'), long("also-switch"))]
+    /// Switch with many names
+    switch: bool,
+    #[bpaf(short, long("argument"), short('A'), long("also-arg"))]
+    /// Argument with names
+    arg: usize,
+    #[bpaf(short, long("user"), env("USER1"), argument("USER"))]
+    /// Custom user name
+    username: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

As usual switch is optional, arguments are required

+
+$ app -a 42 -u Bobert
+Options { switch: false, arg: 42, username: "Bobert" } +
+

Help displays only visible aliases (and a current value for env arguments)

+
+$ app --help
+

Usage: app [-s] -a=ARG -u=USER

+Available options:
-s, --switch
+
Switch with many names
+
-a, --argument=ARG
+
Argument with names
+
-u, --user=USER
+
Custom user name
+
+
[env:USER1: N/A]
+
-h, --help
+
Prints help information
+
+

+ +
+

But you can still use hidden aliases, both short and long

+
+$ app --also-switch --also-arg 330 --user Bobert
+Options { switch: true, arg: 330, username: "Bobert" } +
+

And unless there’s many or similar modifiers having multiple aliases doesn’t mean +you can specify them multiple times:

+
+$ app -A 42 -a 330 -u Bobert
+Error: -a is not expected in this context + +
+

Also hidden aliases are really hidden and only meant to do backward compatibility stuff, they +won’t show up anywhere else in completions or error messages

+
+$ app -a 42 -A 330 -u Bobert
+Error: -A is not expected in this context + +
+
source

pub fn long(self, long: &'static str) -> Self

Add a long name to a flag/switch/argument

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    switch: bool,
+    arg: usize,
+    username: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let switch = short('s') // first `short` creates a builder
+        .short('S') // second switch is a hidden alias
+        .long("switch") // visible long name
+        .long("also-switch") // hidden alias
+        .help("Switch with many names")
+        .switch(); // `switch` finalizes the builder
+
+    let arg = long("argument") // long is also a builder
+        .short('a')
+        .short('A')
+        .long("also-arg")
+        .help("Argument with names")
+        .argument::<usize>("ARG");
+
+    let username = long("user")
+        .short('u')
+        .env("USER1")
+        .help("Custom user name")
+        .argument::<String>("USER");
+
+    construct!(Options {
+        switch,
+        arg,
+        username
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, short('S'), long("also-switch"))]
+    /// Switch with many names
+    switch: bool,
+    #[bpaf(short, long("argument"), short('A'), long("also-arg"))]
+    /// Argument with names
+    arg: usize,
+    #[bpaf(short, long("user"), env("USER1"), argument("USER"))]
+    /// Custom user name
+    username: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

As usual switch is optional, arguments are required

+
+$ app -a 42 -u Bobert
+Options { switch: false, arg: 42, username: "Bobert" } +
+

Help displays only visible aliases (and a current value for env arguments)

+
+$ app --help
+

Usage: app [-s] -a=ARG -u=USER

+Available options:
-s, --switch
+
Switch with many names
+
-a, --argument=ARG
+
Argument with names
+
-u, --user=USER
+
Custom user name
+
+
[env:USER1: N/A]
+
-h, --help
+
Prints help information
+
+

+ +
+

But you can still use hidden aliases, both short and long

+
+$ app --also-switch --also-arg 330 --user Bobert
+Options { switch: true, arg: 330, username: "Bobert" } +
+

And unless there’s many or similar modifiers having multiple aliases doesn’t mean +you can specify them multiple times:

+
+$ app -A 42 -a 330 -u Bobert
+Error: -a is not expected in this context + +
+

Also hidden aliases are really hidden and only meant to do backward compatibility stuff, they +won’t show up anywhere else in completions or error messages

+
+$ app -a 42 -A 330 -u Bobert
+Error: -A is not expected in this context + +
+
source

pub fn env(self, variable: &'static str) -> Self

Environment variable fallback

+

If named value isn’t present - try to fallback to this environment variable.

+

You can specify it multiple times, bpaf would use items past the first one as hidden aliases.

+

For flag and switch environment variable being present +gives the same result as the flag being present, allowing to implement things like NO_COLOR +variables:

+
$ NO_COLOR=1 app --do-something
+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    switch: bool,
+    arg: usize,
+    username: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let switch = short('s') // first `short` creates a builder
+        .short('S') // second switch is a hidden alias
+        .long("switch") // visible long name
+        .long("also-switch") // hidden alias
+        .help("Switch with many names")
+        .switch(); // `switch` finalizes the builder
+
+    let arg = long("argument") // long is also a builder
+        .short('a')
+        .short('A')
+        .long("also-arg")
+        .help("Argument with names")
+        .argument::<usize>("ARG");
+
+    let username = long("user")
+        .short('u')
+        .env("USER1")
+        .help("Custom user name")
+        .argument::<String>("USER");
+
+    construct!(Options {
+        switch,
+        arg,
+        username
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, short('S'), long("also-switch"))]
+    /// Switch with many names
+    switch: bool,
+    #[bpaf(short, long("argument"), short('A'), long("also-arg"))]
+    /// Argument with names
+    arg: usize,
+    #[bpaf(short, long("user"), env("USER1"), argument("USER"))]
+    /// Custom user name
+    username: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

As usual switch is optional, arguments are required

+
+$ app -a 42 -u Bobert
+Options { switch: false, arg: 42, username: "Bobert" } +
+

Help displays only visible aliases (and a current value for env arguments)

+
+$ app --help
+

Usage: app [-s] -a=ARG -u=USER

+Available options:
-s, --switch
+
Switch with many names
+
-a, --argument=ARG
+
Argument with names
+
-u, --user=USER
+
Custom user name
+
+
[env:USER1: N/A]
+
-h, --help
+
Prints help information
+
+

+ +
+

But you can still use hidden aliases, both short and long

+
+$ app --also-switch --also-arg 330 --user Bobert
+Options { switch: true, arg: 330, username: "Bobert" } +
+

And unless there’s many or similar modifiers having multiple aliases doesn’t mean +you can specify them multiple times:

+
+$ app -A 42 -a 330 -u Bobert
+Error: -a is not expected in this context + +
+

Also hidden aliases are really hidden and only meant to do backward compatibility stuff, they +won’t show up anywhere else in completions or error messages

+
+$ app -a 42 -A 330 -u Bobert
+Error: -A is not expected in this context + +
+
source

pub fn help<M>(self, help: M) -> Self
where + M: Into<Doc>,

Add a help message to a flag/switch/argument

+

bpaf converts doc comments and string into help by following those rules:

+
    +
  1. Everything up to the first blank line is included into a “short” help message
  2. +
  3. Everything is included into a “long” help message
  4. +
  5. bpaf preserves linebreaks followed by a line that starts with a space
  6. +
  7. Linebreaks are removed otherwise
  8. +
+

You can pass anything that can be converted into Doc, if you are not using +documentation generation functionality (doc) this can be &str.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    name: String,
+    output: Option<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help(
+            "\
+Output detailed help information, you can specify it multiple times
+
+ when used once it outputs basic diagnostic info,
+ when used twice or three times - it includes extra debugging.",
+            // ^ note extra spaces before "when" that preserve the linebreaks
+        )
+        .switch();
+    let name = long("name")
+        .help("Use this as a task name")
+        .argument("NAME");
+
+    let output = positional("OUTPUT")
+        .help("Save output to a file")
+        .optional();
+
+    construct!(Options {
+        verbose,
+        name,
+        output
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long)]
+    /// Output detailed help information, you can specify it multiple times
+    ///
+    ///  when used once it outputs basic diagnostic info,
+    ///  when used twice or three times - it includes extra debugging.
+    //  ^ note extra spaces before when that preserve the linebreaks
+    verbose: bool,
+
+    #[bpaf(argument("NAME"))]
+    /// Use this as a task name
+    name: String,
+
+    #[bpaf(positional("OUTPUT"))]
+    /// Save output to a file
+    output: Option<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

When --help used once it renders shoter version of the help information

+
+$ app --help
+

Usage: app [-v] --name=NAME [OUTPUT]

+Available positional items:
OUTPUT
+
Save output to a file
+
+

+Available options:
-v, --verbose
+
Output detailed help information, you can specify it multiple times
+
--name=NAME
+
Use this as a task name
+
-h, --help
+
Prints help information
+
+

+ +
+

When used twice - it renders full version. Documentation generator uses full +version as well

+
+$ app --help --help
+

Usage: app [-v] --name=NAME [OUTPUT]

+Available positional items:
OUTPUT
+
Save output to a file
+
+

+Available options:
-v, --verbose
+
Output detailed help information, you can specify it multiple times
+ when used once it outputs basic diagnostic info,
+when used twice or three times - it includes extra debugging.
+
--name=NAME
+
Use this as a task name
+
-h, --help
+
Prints help information
+
+

+ +
+

Presence or absense of a help message should not affect the parser’s output

+
+$ app --name Bob output.txt
+Options { verbose: false, name: "Bob", output: Some("output.txt") } +
+
source

pub fn switch(self) -> ParseFlag<bool>

Simple boolean flag

+

A special case of a flag that gets decoded into a bool, mostly serves as a convenient +shortcut to .flag(true, false).

+

In Derive API bpaf would use switch for bool fields inside named structs that don’t +have other consumer annotations (flag, +argument, etc).

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    release: bool,
+    default_features: bool,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help("Produce verbose output")
+        .switch();
+    let release = long("release")
+        .help("Build artifacts in release mode")
+        .flag(true, false);
+    let default_features = long("no-default-features")
+        .help("Do not activate default features")
+        // default_features uses opposite values,
+        // producing `true` when value is absent
+        .flag(false, true);
+
+    construct!(Options {
+        verbose,
+        release,
+        default_features,
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Produce verbose output
+    // bpaf uses `switch` for `bool` fields in named
+    // structs unless consumer attribute is present.
+    // But it is also possible to give it explicit
+    // consumer annotation to serve as a reminder:
+    // #[bpaf(short, long, switch)]
+    #[bpaf(short, long)]
+    verbose: bool,
+
+    #[bpaf(flag(true, false))]
+    /// Build artifacts in release mode
+    release: bool,
+
+    /// Do not activate default features
+    // default_features uses opposite values,
+    // producing `true` when value is absent
+    #[bpaf(long("no-default-features"), flag(false, true))]
+    default_features: bool,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help output bpaf shows switches as usual flags with no meta variable attached

+
+$ app --help
+

Usage: app [-v] [--release] [--no-default-features]

+Available options:
-v, --verbose
+
Produce verbose output
+
--release
+
Build artifacts in release mode
+
--no-default-features
+
Do not activate default features
+
-h, --help
+
Prints help information
+
+

+ +
+

Both switch and flag succeed if value is not present, switch returns true, flag returns +second value.

+
+$ app
+Options { verbose: false, release: false, default_features: true } +
+

When value is present - switch returns true, flag returns first value.

+
+$ app --verbose --no-default-features --detailed
+Error: --detailed is not expected in this context + +
+

Like with most parsrs unless specified switch and flag consume at most one item from the +command line:

+
+$ app --no-default-features --no-default-features
+Error: argument --no-default-features cannot be used multiple times in this context + +
+
source

pub fn flag<T>(self, present: T, absent: T) -> ParseFlag<T>
where + T: Clone + 'static,

Flag with custom present/absent values

+

More generic version of switch that can use arbitrary type instead of +bool.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    decision: Decision,
+}
+
+#[derive(Debug, Clone)]
+pub enum Decision {
+    Yes,
+    No,
+}
+
+fn parse_decision() -> impl Parser<Decision> {
+    long("decision")
+        .help("Positive decision")
+        .flag(Decision::Yes, Decision::No)
+}
+
+pub fn options() -> OptionParser<Options> {
+    let decision = parse_decision();
+    construct!(Options { decision }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Positive decision
+    #[bpaf(flag(Decision::Yes, Decision::No))]
+    decision: Decision,
+}
+
+#[derive(Debug, Clone)]
+pub enum Decision {
+    Yes,
+    No,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help output bpaf shows flags with no meta variable attached

+
+$ app --help
+

Usage: app [--decision]

+Available options:
--decision
+
Positive decision
+
-h, --help
+
Prints help information
+
+

+ +
+

Presense of a long name is decoded into Yes

+
+$ app --decision
+Options { decision: Yes } +
+

Absense is No

+
+$ app
+Options { decision: No } +
+
source

pub fn req_flag<T>(self, present: T) -> impl Parser<T>
where + T: Clone + 'static,

Required flag with custom value

+

Similar to flag takes no option arguments, but would only +succeed if user specifies its name on a command line. +Works best in combination with other parsers.

+

In derive style API bpaf would transform field-less enum variants into a parser +that accepts one of it’s variant names as req_flag. Additionally bpaf handles () +fields as req_flag.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub enum Style {
+    Intel,
+    Att,
+    Llvm,
+}
+
+#[derive(Debug, Clone)]
+pub enum Report {
+    /// Include defailed report
+    Detailed,
+    /// Include minimal report
+    Minimal,
+    /// No preferences
+    Undecided,
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    agree: (),
+    style: Style,
+    report: Report,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let agree = long("agree")
+        .help("You must agree to perform the action")
+        .req_flag(());
+
+    let intel = long("intel")
+        .help("Show assembly using Intel style")
+        .req_flag(Style::Intel);
+    let att = long("att")
+        .help("Show assembly using AT&T style")
+        .req_flag(Style::Att);
+    let llvm = long("llvm").help("Show llvm-ir").req_flag(Style::Llvm);
+    let style = construct!([intel, att, llvm]);
+
+    let detailed = long("detailed")
+        .help("Include detailed report")
+        .req_flag(Report::Detailed);
+    let minimal = long("minimal")
+        .help("Include minimal report")
+        .req_flag(Report::Minimal);
+    let report = construct!([detailed, minimal]).fallback(Report::Undecided);
+
+    construct!(Options {
+        agree,
+        style,
+        report
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+pub enum Style {
+    /// Show assembly using Intel style
+    Intel,
+    /// Show assembly using AT&T style
+    Att,
+    /// Show llvm-ir
+    Llvm,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(fallback(Report::Undecided))]
+pub enum Report {
+    /// Include detailed report
+    Detailed,
+    /// Include minimal report
+    Minimal,
+    #[bpaf(skip)]
+    /// No preferences
+    Undecided,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// You must agree to perform the action
+    agree: (),
+    // external here uses explicit reference to function `style`
+    // generated above
+    #[bpaf(external(style))]
+    style: Style,
+    // here reference is implicit and derived from field name: `report`
+    #[bpaf(external)]
+    report: Report,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help message req_flag look similarly to switch and +flag

+
+$ app --help
+

Usage: app --agree (--intel | --att | --llvm) [--detailed | --minimal]

+Available options:
--agree
+
You must agree to perform the action
+
--intel
+
Show assembly using Intel style
+
--att
+
Show assembly using AT&T style
+
--llvm
+
Show llvm-ir
+
--detailed
+
Include detailed report
+
--minimal
+
Include minimal report
+
-h, --help
+
Prints help information
+
+

+ +
+

Example contains two parsers that fails without any input: agree requires passing --agree

+
+$ app
+Error: expected --agree, pass --help for usage information + +
+

While style takes one of several possible values

+
+$ app --agree
+Error: expected --intel, --att, or more, pass --help for usage information + +
+

It is possible to alter the behavior using fallback or +hide.

+
+$ app --agree --intel
+Options { agree: (), style: Intel, report: Undecided } +
+

While parser for style takes any posted output - it won’t take multiple of them at once +(unless other combinators such as many permit it) or last.

+
+$ app --agree --att --llvm
+Error: --llvm cannot be used at the same time as --att + +
+
source

pub fn argument<T>(self, metavar: &'static str) -> ParseArgument<T>
where + T: FromStr + 'static,

Argument

+

A short (-a) or long (--name) name followed by either a space or = and +then by a string literal. -f foo, --flag bar or -o=- are all valid argument examples. Note, string +literal can’t start with - unless separated from the flag with =. For short flags value +can follow immediately: -fbar.

+

When using combinatoring API you can specify the type with turbofish, for parsing types +that don’t implement FromStr you can use consume a String/OsString first and parse +it by hands.

+

For metavar value you should pick something short and descriptive about the parameter, +usually in capital letters. For example for an abstract file parameter it could be +"FILE", for a username - "USER", etc.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    name: String,
+    age: usize,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let name = short('n')
+        .long("name")
+        .help("Specify user name")
+        // you can specify exact type argument should produce
+        // for as long as it implements `FromStr`
+        .argument::<String>("NAME");
+
+    let age = long("age")
+        .help("Specify user age")
+        // but often rust can figure it out from the context,
+        // here age is going to be `usize`
+        .argument("AGE")
+        .fallback(18)
+        .display_fallback();
+
+    construct!(Options { name, age }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    // you can specify exact type argument should produce
+    // for as long as it implements `FromStr`
+    #[bpaf(short, long, argument::<String>("NAME"))]
+    /// Specify user name
+    name: String,
+    // but often rust can figure it out from the context,
+    // here age is going to be `usize`
+    #[bpaf(argument("AGE"), fallback(18), display_fallback)]
+    /// Specify user age
+    age: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +
+$ app --help
+

Usage: app -n=NAME [--age=AGE]

+Available options:
-n, --name=NAME
+
Specify user name
+
--age=AGE
+
Specify user age
+
+
[default: 18]
+
-h, --help
+
Prints help information
+
+

+ +
+

--help shows arguments as a short name with attached metavariable

+

Value can be separated from flag by space, = sign

+
+$ app --name Bob --age 12
+Options { name: "Bob", age: 12 } +
+
+$ app --name "Bob" --age=12
+Options { name: "Bob", age: 12 } +
+
+$ app --name=Bob
+Options { name: "Bob", age: 18 } +
+
+$ app --name="Bob"
+Options { name: "Bob", age: 18 } +
+

Or in case of short name - be directly adjacent to it

+
+$ app -nBob
+Options { name: "Bob", age: 18 } +
+

For long names - this doesn’t work since parser can’t tell where name +stops and argument begins:

+
+$ app --age12
+Error: no such flag: --age12, did you mean --age? + +
+

Either way - value is required, passing just the argument name results in parse failure

+
+$ app --name
+Error: --name requires an argument NAME + +
+
+

You can further restrict it using adjacent

+

Trait Implementations§

source§

impl Clone for NamedArg

source§

fn clone(&self) -> NamedArg

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for NamedArg

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseAny.html b/bpaf/parsers/struct.ParseAny.html new file mode 100644 index 00000000..f1412d5c --- /dev/null +++ b/bpaf/parsers/struct.ParseAny.html @@ -0,0 +1,67 @@ +ParseAny in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseAny

source ·
pub struct ParseAny<T> { /* private fields */ }
Expand description

Consume an arbitrary value that satisfies a condition, created with any, implements +anywhere.

+

Implementations§

source§

impl<T> ParseAny<T>

source

pub fn help<M: Into<Doc>>(self, help: M) -> Self

Add a help message to any parser. +See examples in any

+
source

pub fn metavar<M: Into<Doc>>(self, metavar: M) -> Self

Replace metavar with a custom value +See examples in any

+
source

pub fn anywhere(self) -> Self

Try to apply the parser to each unconsumed element instead of just the front one

+

By default any tries to parse just the front unconsumed item behaving similar to +positional parser, anywhere changes it so it applies to every unconsumed item, +similar to argument parser.

+

See examples in any

+

Trait Implementations§

source§

impl<T> Parser<T> for ParseAny<T>

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<T> !RefUnwindSafe for ParseAny<T>

§

impl<T> !Send for ParseAny<T>

§

impl<T> !Sync for ParseAny<T>

§

impl<T> Unpin for ParseAny<T>

§

impl<T> !UnwindSafe for ParseAny<T>

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseArgument.html b/bpaf/parsers/struct.ParseArgument.html new file mode 100644 index 00000000..d47f85d2 --- /dev/null +++ b/bpaf/parsers/struct.ParseArgument.html @@ -0,0 +1,208 @@ +ParseArgument in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseArgument

source ·
pub struct ParseArgument<T> { /* private fields */ }
Expand description

Parser for a named argument, created with argument.

+

Implementations§

source§

impl<T> ParseArgument<T>

source

pub fn help<M>(self, help: M) -> Self
where + M: Into<Doc>,

Add a help message to an argument

+

See NamedArg::help

+
source§

impl<T> ParseArgument<T>

source

pub fn adjacent(self) -> Self

Restrict parsed arguments to have both flag and a value in the same word:

+

In other words adjacent restricted ParseArgument would accept --flag=value or +-fbar but not --flag value. Note, this is different from adjacent, +just plays a similar role.

+

Should allow to parse some of the more unusual things

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    package: String,
+}
+
+fn package() -> impl Parser<String> {
+    long("package")
+        .short('p')
+        .help("Package to use")
+        .argument("SPEC")
+        .adjacent()
+}
+
+pub fn options() -> OptionParser<Options> {
+    construct!(Options { package() }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, argument("SPEC"), adjacent)]
+    /// Package to use
+    package: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +
+$ app --help
+

Usage: app -p=SPEC

+Available options:
-p, --package=SPEC
+
Package to use
+
-h, --help
+
Prints help information
+
+

+ +
+

As with regular argument its adjacent variant is required by default

+
+$ app
+Error: expected --package=SPEC, pass --help for usage information + +
+

But unlike regular variant adjacent requires name and value to be separated by = only

+
+$ app -p=htb
+Options { package: "htb" } +
+
+$ app --package=bpaf
+Options { package: "bpaf" } +
+

Separating them by space results in parse failure

+
+$ app --package htb
+Error: expected --package=SPEC, got --package. Pass --help for usage information + +
+
+$ app -p htb
+Error: expected --package=SPEC, got -p. Pass --help for usage information + +
+
+$ app --package
+Error: expected --package=SPEC, got --package. Pass --help for usage information + +
+

Trait Implementations§

source§

impl<T: Clone> Clone for ParseArgument<T>

source§

fn clone(&self) -> ParseArgument<T>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T> Parser<T> for ParseArgument<T>
where + T: FromStr + 'static, + <T as FromStr>::Err: Display,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<T> RefUnwindSafe for ParseArgument<T>
where + T: RefUnwindSafe,

§

impl<T> Send for ParseArgument<T>
where + T: Send,

§

impl<T> Sync for ParseArgument<T>
where + T: Sync,

§

impl<T> Unpin for ParseArgument<T>
where + T: Unpin,

§

impl<T> UnwindSafe for ParseArgument<T>
where + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseCollect.html b/bpaf/parsers/struct.ParseCollect.html new file mode 100644 index 00000000..d238645b --- /dev/null +++ b/bpaf/parsers/struct.ParseCollect.html @@ -0,0 +1,223 @@ +ParseCollect in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseCollect

source ·
pub struct ParseCollect<P, C, T> { /* private fields */ }
Expand description

Apply inner parser several times and collect results into FromIterator, created with +collect, +Implements catch

+

Implementations§

source§

impl<T, C, P> ParseCollect<P, C, T>

source

pub fn catch(self) -> Self

Handle parse failures

+

Can be useful to decide to skip parsing of some items on a command line +When parser succeeds - catch version would return a value as usual +if it fails - catch would restore all the consumed values and return None.

+

There’s several structures that implement this attribute: ParseOptional, ParseMany +and ParseSome, behavior should be identical for all of them.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    height: Vec<usize>,
+    height_str: Vec<String>,
+    width: Vec<usize>,
+    width_str: Vec<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    // contains catch
+    let height = long("height")
+        .help("Height of a rectangle")
+        .argument::<usize>("PX")
+        .some("You must specify some heights")
+        .catch();
+
+    let height_str = long("height").argument::<String>("PX").many().hide();
+
+    // contains no catch
+    let width = long("width")
+        .help("Width of a rectangle")
+        .argument::<usize>("PX")
+        .some("You must specify some widths");
+
+    let width_str = long("width").argument::<String>("PX").many().hide();
+
+    construct!(Options {
+        height,
+        height_str,
+        width,
+        width_str
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(long, argument("PX"), some("You must specify some heights"), catch)]
+    /// Height of a rectangle
+    height: Vec<usize>,
+
+    #[bpaf(long("height"), argument("PX"), many, hide)]
+    height_str: Vec<String>,
+
+    #[bpaf(long, argument("PX"), some("You must specify some widths"))]
+    /// Width of a rectangle
+    width: Vec<usize>,
+
+    #[bpaf(long("width"), argument("PX"), many, hide)]
+    width_str: Vec<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Despite parser producing a funky value - help looks like you would expect from a parser that +takes two values

+
+$ app --help
+

Usage: app --height=PX... --width=PX...

+Available options:
--height=PX
+
Height of a rectangle
+
--width=PX
+
Width of a rectangle
+
-h, --help
+
Prints help information
+
+

+ +
+

When executed with no parameters parser fails because some requires you to specify at least +one matching parameter

+
+$ app
+Error: You must specify some heights + +
+

When executed with expected parameters fields with usize get their values

+
+$ app --height 100 --width 100 --height 12 --width 44
+Options { height: [100, 12], height_str: [], width: [100, 44], width_str: [] } +
+

With incorrect value for --height parameter inner part of height parser fails, some +combined with catch handles this failure and produces [] without consuming value from the +command line. Parser height_str runs next and consumes the value as a string

+
+$ app --height 10 --height twenty --width 33
+Options { height: [10], height_str: ["twenty"], width: [33], width_str: [] } +
+

In case of wrong --width - parser width fails, parser for some sees this as a +“value is present but not correct” and propagates the error outside, execution never reaches +width_str parser

+
+$ app --height 10 --width 33 --width ten
+Error: couldn't parse ten: invalid digit found in string + +
+

Trait Implementations§

source§

impl<T, C, P> Parser<C> for ParseCollect<P, C, T>
where + P: Parser<T>, + C: FromIterator<T>,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<P, C, T> RefUnwindSafe for ParseCollect<P, C, T>
where + C: RefUnwindSafe, + P: RefUnwindSafe, + T: RefUnwindSafe,

§

impl<P, C, T> Send for ParseCollect<P, C, T>
where + C: Send, + P: Send, + T: Send,

§

impl<P, C, T> Sync for ParseCollect<P, C, T>
where + C: Sync, + P: Sync, + T: Sync,

§

impl<P, C, T> Unpin for ParseCollect<P, C, T>
where + C: Unpin, + P: Unpin, + T: Unpin,

§

impl<P, C, T> UnwindSafe for ParseCollect<P, C, T>
where + C: UnwindSafe, + P: UnwindSafe, + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseCommand.html b/bpaf/parsers/struct.ParseCommand.html new file mode 100644 index 00000000..739d2c0c --- /dev/null +++ b/bpaf/parsers/struct.ParseCommand.html @@ -0,0 +1,291 @@ +ParseCommand in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseCommand

source ·
pub struct ParseCommand<T> { /* private fields */ }
Expand description

Builder structure for the [command]

+

Created with [command], implements parser for the inner structure, gives access to help.

+

Implementations§

source§

impl<P> ParseCommand<P>

source

pub fn help<M>(self, help: M) -> Self
where + M: Into<Doc>,

Add a brief description to a command

+

bpaf uses this description along with the command name +in help output so it shouldn’t exceed one or two lines. If help isn’t specified +bpaf falls back to descr from the inner parser.

+
§Combinatoric usage
+
fn inner() -> OptionParser<bool> {
+    short('i')
+        .help("Mysterious inner switch")
+        .switch()
+        .to_options()
+        .descr("performs an operation")
+}
+
+fn mysterious_parser() -> impl Parser<bool> {
+    inner().command("mystery")
+        .help("This command performs a mystery operation")
+}
+
§Derive usage
+

bpaf_derive uses doc comments for inner parser, no specific options are available. +See descr for more details

+ +
/// This command performs a mystery operation
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(command)]
+struct Mystery {
+    #[bpaf(short)]
+    /// Mysterious inner switch
+    inner: bool,
+}
+
§Example
$ app --help
+    <skip>
+Available commands:
+    mystery  This command performs a mystery operation
+
source

pub fn short(self, short: char) -> Self

Add a custom short alias for a command

+

Behavior is similar to short, only first short name is visible.

+
source

pub fn long(self, long: &'static str) -> Self

Add a custom hidden long alias for a command

+

Behavior is similar to long, but since you had to specify the first long +name when making the command - this one becomes a hidden alias.

+
source

pub fn adjacent(self) -> Self

Allow for the command to succeed even if there are non consumed items present

+

Normally a subcommand parser should handle the rest of the unconsumed elements thus +allowing only “vertical” chaining of commands. adjacent modifier lets command parser to +succeed if there are leftovers for as long as all comsumed items form a single adjacent +block. This opens possibilities to chain commands sequentially.

+

Let’s consider two examples with consumed items marked in bold :

+
    +
  • cmd -a -b -c -d
  • +
  • cmd -a -c -b -d
  • +
+

In the first example -b breaks the adjacency for all the consumed items so parsing will fail, +while here in the second one the name and all the consumed items are adjacent to each other so +parsing will succeed.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    premium: bool,
+    commands: Vec<Cmd>,
+}
+
+#[derive(Debug, Clone)]
+// shape of the variants doesn't really matter, let's use all of them :)
+enum Cmd {
+    Eat(String),
+    Drink { coffee: bool },
+    Sleep { time: usize },
+}
+
+fn cmd() -> impl Parser<Cmd> {
+    let eat = positional::<String>("FOOD")
+        .to_options()
+        .descr("Performs eating action")
+        .command("eat")
+        .adjacent()
+        .map(Cmd::Eat);
+
+    let coffee = long("coffee")
+        .help("Are you going to drink coffee?")
+        .switch();
+    let drink = construct!(Cmd::Drink { coffee })
+        .to_options()
+        .descr("Performs drinking action")
+        .command("drink")
+        .adjacent();
+
+    let time = long("time").argument::<usize>("HOURS");
+    let sleep = construct!(Cmd::Sleep { time })
+        .to_options()
+        .descr("Performs taking a nap action")
+        .command("sleep")
+        .adjacent();
+
+    construct!([eat, drink, sleep])
+}
+
+pub fn options() -> OptionParser<Options> {
+    let premium = short('p')
+        .long("premium")
+        .help("Opt in for premium serivces")
+        .switch();
+    let commands = cmd().many();
+    construct!(Options { premium, commands }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long)]
+    /// Opt in for premium serivces
+    pub premium: bool,
+    #[bpaf(external(cmd), many)]
+    pub commands: Vec<Cmd>,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+pub enum Cmd {
+    #[bpaf(command, adjacent)]
+    /// Performs eating action
+    Eat(#[bpaf(positional("FOOD"))] String),
+    #[bpaf(command, adjacent)]
+    /// Performs drinking action
+    Drink {
+        /// Are you going to drink coffee?
+        coffee: bool,
+    },
+    #[bpaf(command, adjacent)]
+    /// Performs taking a nap action
+    Sleep {
+        #[bpaf(argument("HOURS"))]
+        time: usize,
+    },
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Example implements a parser that supports one of three possible commands:

+
+$ app --help
+

Usage: app [-p] [COMMAND ...]...

+Available options:
-p, --premium
+
Opt in for premium serivces
+
-h, --help
+
Prints help information
+
+

+Available commands:
eat
+
Performs eating action
+
drink
+
Performs drinking action
+
sleep
+
Performs taking a nap action
+
+

+ +
+

As usual every command comes with its own help

+
+$ app drink --help
+

Performs drinking action

Usage: app drink [--coffee]

+Available options:
--coffee
+
Are you going to drink coffee?
+
-h, --help
+
Prints help information
+
+

+ +
+

Normally you can use one command at a time, but making commands adjacent lets +parser to succeed after consuming an adjacent block only and leaving leftovers for the rest of +the parser, consuming them as a Vec<Cmd> with many allows to chain multiple +items sequentially

+
+$ app eat Fastfood drink --coffee sleep --time=5
+Options { premium: false, commands: [Eat("Fastfood"), Drink { coffee: true }, Sleep { time: 5 }] } +
+

The way this works is by running parsers for each command. In the first iteration eat succeeds, +it consumes eat fastfood portion and appends its value to the resulting vector. Then second +iteration runs on leftovers, in this case it will be drink --coffee sleep --time=5. +Here drink succeeds and consumes drink --coffee portion, then sleep parser runs, etc.

+

You can mix chained commands with regular arguments that belong to the top level parser

+
+$ app sleep --time 10 --premium eat 'Bak Kut Teh' drink
+Options { premium: true, commands: [Sleep { time: 10 }, Eat("Bak Kut Teh"), Drink { coffee: false }] } +
+

But not inside the command itself since values consumed by the command are not going to be +adjacent

+
+$ app sleep --time 10 eat --premium 'Bak Kut Teh' drink
+Error: expected FOOD, pass --help for usage information + +
+

Trait Implementations§

source§

impl<T> Parser<T> for ParseCommand<T>

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<T> !RefUnwindSafe for ParseCommand<T>

§

impl<T> !Send for ParseCommand<T>

§

impl<T> !Sync for ParseCommand<T>

§

impl<T> Unpin for ParseCommand<T>

§

impl<T> !UnwindSafe for ParseCommand<T>

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseCompShell.html b/bpaf/parsers/struct.ParseCompShell.html new file mode 100644 index 00000000..9450b8fd --- /dev/null +++ b/bpaf/parsers/struct.ParseCompShell.html @@ -0,0 +1,63 @@ +ParseCompShell in bpaf::parsers - Rust +
pub struct ParseCompShell<P> { /* private fields */ }
Expand description

Parser that inserts static shell completion into bpaf’s dynamic shell completion

+

Trait Implementations§

source§

impl<P, T> Parser<T> for ParseCompShell<P>
where + P: Parser<T> + Sized,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<P> RefUnwindSafe for ParseCompShell<P>
where + P: RefUnwindSafe,

§

impl<P> Send for ParseCompShell<P>
where + P: Send,

§

impl<P> Sync for ParseCompShell<P>
where + P: Sync,

§

impl<P> Unpin for ParseCompShell<P>
where + P: Unpin,

§

impl<P> UnwindSafe for ParseCompShell<P>
where + P: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseCon.html b/bpaf/parsers/struct.ParseCon.html new file mode 100644 index 00000000..90337565 --- /dev/null +++ b/bpaf/parsers/struct.ParseCon.html @@ -0,0 +1,848 @@ +ParseCon in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseCon

source ·
pub struct ParseCon<P> {
+    pub inner: P,
+    pub meta: Meta,
+    pub failfast: bool,
+}
Expand description

Create parser from a function, construct! uses it internally

+

Fields§

§inner: P

inner parser closure

+
§meta: Meta

metas for inner parsers

+
§failfast: bool

To produce a better error messages while parsing constructed values +we want to look at all the items so values that can be consumed are consumed +autocomplete relies on the same logic

+

However when dealing with adjacent restriction detecting the first item relies on failing +fast

+

Implementations§

source§

impl<T> ParseCon<T>

source

pub fn adjacent(self) -> ParseAdjacent<Self>

Automagically restrict the inner parser scope to accept adjacent values only

+

adjacent can solve surprisingly wide variety of problems: sequential command chaining, +multi-value arguments, option-structs to name a few. If you want to run a parser on a +sequential subset of arguments - adjacent might be able to help you. Check the examples +for better intuition.

+

Let’s consider two examples with consumed items marked in bold and constructor containing +parsers for -c and -d.

+
    +
  • -a -b -c -d
  • +
  • -a -c -b -d
  • +
+

In the first example -b breaks the adjacency for all the consumed items so parsing will fail, +while here in the second one all the consumed items are adjacent to each other so +parsing will succeed.

+
§Multi-value arguments
+

Parsing things like --point X Y Z

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    point: Vec<Point>,
+    rotate: bool,
+}
+
+#[derive(Debug, Clone)]
+struct Point {
+    point: (),
+    x: usize,
+    y: usize,
+    z: f64,
+}
+
+fn point() -> impl Parser<Point> {
+    let point = short('p')
+        .long("point")
+        .help("Point coordinates")
+        .req_flag(());
+    let x = positional::<usize>("X").help("X coordinate of a point");
+    let y = positional::<usize>("Y").help("Y coordinate of a point");
+    let z = positional::<f64>("Z").help("Height of a point above the plane");
+    construct!(Point { point, x, y, z }).adjacent()
+}
+
+pub fn options() -> OptionParser<Options> {
+    let rotate = short('r')
+        .long("rotate")
+        .help("Face the camera towards the first point")
+        .switch();
+    let point = point().many();
+    construct!(Options { point, rotate }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(external, many)]
+    point: Vec<Point>,
+    #[bpaf(short, long)]
+    /// Face the camera towards the first point
+    rotate: bool,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(adjacent)]
+struct Point {
+    #[bpaf(short, long)]
+    /// Point coordinates
+    point: (),
+    #[bpaf(positional("X"))]
+    /// X coordinate of a point
+    x: usize,
+    #[bpaf(positional("Y"))]
+    /// Y coordinate of a point
+    y: usize,
+    #[bpaf(positional("Z"))]
+    /// Height of a point above the plane
+    z: f64,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Fields can have different types, including Option or Vec, in this example they are two +usize and one f64.

+
+$ app --help
+

Usage: app [-p X Y Z]... [-r]

+Available options:
-p X Y Z
-p, --point
+
Point coordinates
+
X
+
X coordinate of a point
+
Y
+
Y coordinate of a point
+
Z
+
Height of a point above the plane
+

-r, --rotate
+
Face the camera towards the first point
+
-h, --help
+
Prints help information
+
+

+ +
+

flag --point takes 3 positional arguments: two integers for X and Y coordinates and one floating point for height, order is +important, switch --rotate can go on either side of it

+
+$ app --rotate --point 10 20 3.1415
+Options { point: [Point { point: (), x: 10, y: 20, z: 3.1415 }], rotate: true } +
+

parser accepts multiple points, they must not interleave

+
+$ app --point 10 20 3.1415 --point 1 2 0.0
+Options { point: [Point { point: (), x: 10, y: 20, z: 3.1415 }, Point { point: (), x: 1, y: 2, z: 0.0 }], rotate: false } +
+

--rotate can’t go in the middle of the point definition as the parser expects the second item

+
+$ app --point 10 20 --rotate 3.1415
+Error: expected Z, pass --help for usage information + +
+
+
§Structure groups
+

Parsing things like --rect --width W --height H --rect --height H --width W

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    rect: Vec<Rect>,
+    mirror: bool,
+}
+
+#[derive(Debug, Clone)]
+struct Rect {
+    rect: (),
+    width: usize,
+    height: usize,
+    painted: bool,
+}
+
+fn rect() -> impl Parser<Rect> {
+    let rect = long("rect").help("Define a new rectangle").req_flag(());
+    let width = short('w')
+        .long("width")
+        .help("Rectangle width in pixels")
+        .argument::<usize>("PX");
+    let height = short('h')
+        .long("height")
+        .help("Rectangle height in pixels")
+        .argument::<usize>("PX");
+    let painted = short('p')
+        .long("painted")
+        .help("Should rectangle be filled?")
+        .switch();
+    construct!(Rect {
+        rect,
+        width,
+        height,
+        painted,
+    })
+    .adjacent()
+}
+
+pub fn options() -> OptionParser<Options> {
+    let mirror = long("mirror").help("Mirror the image").switch();
+    let rect = rect().many();
+    construct!(Options { rect, mirror }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(external, many)]
+    rect: Vec<Rect>,
+    /// Mirror the image
+    mirror: bool,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(adjacent)]
+struct Rect {
+    /// Define a new rectangle
+    rect: (),
+    #[bpaf(short, long, argument("PX"))]
+    /// Rectangle width in pixels
+    width: usize,
+    #[bpaf(short, long, argument("PX"))]
+    /// Rectangle height in pixels
+    height: usize,
+    #[bpaf(short, long)]
+    /// Should rectangle be filled?
+    painted: bool,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

This example parses multipe rectangles from a command line defined by dimensions and the fact +if its filled or not, to make things more interesting - every group of coordinates must be +prefixed with --rect

+
+$ app --help
+

Usage: app [--rect -w=PX -h=PX [-p]]... [--mirror]

+Available options:
--rect -w=PX -h=PX [-p]
--rect
+
Define a new rectangle
+
-w, --width=PX
+
Rectangle width in pixels
+
-h, --height=PX
+
Rectangle height in pixels
+
-p, --painted
+
Should rectangle be filled?
+

--mirror
+
Mirror the image
+
-h, --help
+
Prints help information
+
+

+ +
+

Order of items within the rectangle is not significant and you can have several of them, +because fields are still regular arguments - order doesn’t matter for as long as they belong +to some rectangle

+
+$ app --rect --width 10 --height 10 --rect --height=10 --width=10
+Options { rect: [Rect { rect: (), width: 10, height: 10, painted: false }, Rect { rect: (), width: 10, height: 10, painted: false }], mirror: false } +
+

You can have optional values that belong to the group inside and outer flags in the middle

+
+$ app --rect --width 10 --painted --height 10 --mirror --rect --height 10 --width 10
+Options { rect: [Rect { rect: (), width: 10, height: 10, painted: true }, Rect { rect: (), width: 10, height: 10, painted: false }], mirror: true } +
+

But with adjacent they cannot interleave

+
+$ app --rect --rect --width 10 --painted --height 10 --height 10 --width 10
+Error: expected --width=PX, pass --help for usage information + +
+

Or have items that don’t belong to the group inside them

+
+$ app --rect --width 10 --mirror --painted --height 10 --rect --height 10 --width 10
+Error: expected --height=PX, pass --help for usage information + +
+
+
§Chaining commands
+

This example explains adjacent, but the same idea holds. +Parsing things like cmd1 --arg1 cmd2 --arg2 --arg3 cmd3 --flag

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    premium: bool,
+    commands: Vec<Cmd>,
+}
+
+#[derive(Debug, Clone)]
+// shape of the variants doesn't really matter, let's use all of them :)
+enum Cmd {
+    Eat(String),
+    Drink { coffee: bool },
+    Sleep { time: usize },
+}
+
+fn cmd() -> impl Parser<Cmd> {
+    let eat = positional::<String>("FOOD")
+        .to_options()
+        .descr("Performs eating action")
+        .command("eat")
+        .adjacent()
+        .map(Cmd::Eat);
+
+    let coffee = long("coffee")
+        .help("Are you going to drink coffee?")
+        .switch();
+    let drink = construct!(Cmd::Drink { coffee })
+        .to_options()
+        .descr("Performs drinking action")
+        .command("drink")
+        .adjacent();
+
+    let time = long("time").argument::<usize>("HOURS");
+    let sleep = construct!(Cmd::Sleep { time })
+        .to_options()
+        .descr("Performs taking a nap action")
+        .command("sleep")
+        .adjacent();
+
+    construct!([eat, drink, sleep])
+}
+
+pub fn options() -> OptionParser<Options> {
+    let premium = short('p')
+        .long("premium")
+        .help("Opt in for premium serivces")
+        .switch();
+    let commands = cmd().many();
+    construct!(Options { premium, commands }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long)]
+    /// Opt in for premium serivces
+    pub premium: bool,
+    #[bpaf(external(cmd), many)]
+    pub commands: Vec<Cmd>,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+pub enum Cmd {
+    #[bpaf(command, adjacent)]
+    /// Performs eating action
+    Eat(#[bpaf(positional("FOOD"))] String),
+    #[bpaf(command, adjacent)]
+    /// Performs drinking action
+    Drink {
+        /// Are you going to drink coffee?
+        coffee: bool,
+    },
+    #[bpaf(command, adjacent)]
+    /// Performs taking a nap action
+    Sleep {
+        #[bpaf(argument("HOURS"))]
+        time: usize,
+    },
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Example implements a parser that supports one of three possible commands:

+
+$ app --help
+

Usage: app [-p] [COMMAND ...]...

+Available options:
-p, --premium
+
Opt in for premium serivces
+
-h, --help
+
Prints help information
+
+

+Available commands:
eat
+
Performs eating action
+
drink
+
Performs drinking action
+
sleep
+
Performs taking a nap action
+
+

+ +
+

As usual every command comes with its own help

+
+$ app drink --help
+

Performs drinking action

Usage: app drink [--coffee]

+Available options:
--coffee
+
Are you going to drink coffee?
+
-h, --help
+
Prints help information
+
+

+ +
+

Normally you can use one command at a time, but making commands adjacent lets +parser to succeed after consuming an adjacent block only and leaving leftovers for the rest of +the parser, consuming them as a Vec<Cmd> with many allows to chain multiple +items sequentially

+
+$ app eat Fastfood drink --coffee sleep --time=5
+Options { premium: false, commands: [Eat("Fastfood"), Drink { coffee: true }, Sleep { time: 5 }] } +
+

The way this works is by running parsers for each command. In the first iteration eat succeeds, +it consumes eat fastfood portion and appends its value to the resulting vector. Then second +iteration runs on leftovers, in this case it will be drink --coffee sleep --time=5. +Here drink succeeds and consumes drink --coffee portion, then sleep parser runs, etc.

+

You can mix chained commands with regular arguments that belong to the top level parser

+
+$ app sleep --time 10 --premium eat 'Bak Kut Teh' drink
+Options { premium: true, commands: [Sleep { time: 10 }, Eat("Bak Kut Teh"), Drink { coffee: false }] } +
+

But not inside the command itself since values consumed by the command are not going to be +adjacent

+
+$ app sleep --time 10 eat --premium 'Bak Kut Teh' drink
+Error: expected FOOD, pass --help for usage information + +
+
+
§Capturing everything between markers
+

Parsing things like find . --exec foo {} -bar ; --more

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    exec: Option<Vec<OsString>>,
+    switch: bool,
+}
+
+fn exec() -> impl Parser<Option<Vec<OsString>>> {
+    // this defines starting token - "--exec"
+    let start = long("exec")
+        .help("Spawn a process for each file found")
+        .req_flag(());
+    // this consumes everything that is not ";"
+    let body = any("COMMAND", |s| (s != ";").then_some(s))
+        .help("Command and arguments, {} will be replaced with a file name")
+        .some("You need to pass some arguments to exec");
+    // this defines endint goken - ";"
+    let end = literal(";");
+    // this consumes everything between starting token and ending token
+    construct!(start, body, end)
+        // this makes it so everything between those tokens is consumed
+        .adjacent()
+        // drop the surrounding tokens leaving just the arguments
+        .map(|x| x.1)
+        // and make it optional so that instead of an empty Vec
+        // it is `None` when no `--exec` flags was passed.
+        .optional()
+}
+
+pub fn options() -> OptionParser<Options> {
+    let switch = short('s')
+        .long("switch")
+        .help("Regular top level switch")
+        .switch();
+    construct!(Options { exec(), switch }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(external(execs))]
+    exec: Option<Vec<OsString>>,
+    #[bpaf(long, short)]
+    /// Regular top level switch
+    switch: bool,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(adjacent)]
+struct Exec {
+    /// Spawn a process for each file found
+    exec: (),
+
+    #[bpaf(
+        any("COMMAND", not_semi),
+        some("Command and arguments, {} will be replaced with a file name")
+    )]
+    /// Command and arguments, {} will be replaced with a file name
+    body: Vec<OsString>,
+
+    #[bpaf(external(is_semi))]
+    end: (),
+}
+
+fn not_semi(s: OsString) -> Option<OsString> {
+    (s != ";").then_some(s)
+}
+
+fn is_semi() -> impl Parser<()> {
+    // TODO - support literal in bpaf_derive
+    literal(";")
+}
+
+// a different alternative would be to put a singular Exec
+fn execs() -> impl Parser<Option<Vec<OsString>>> {
+    exec().map(|e| e.body).optional()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Generated --help message is somewhat descriptive of the purpose

+
+$ app --help
+

Usage: app [--exec COMMAND... ;] [-s]

+Available options:
--exec COMMAND... ;
--exec
+
Spawn a process for each file found
+
COMMAND
+
Command and arguments, {} will be replaced with a file name
+

-s, --switch
+
Regular top level switch
+
-h, --help
+
Prints help information
+
+

+ +
+

You can have as many items between --exec and ; as you want, they all will be captured +inside the exec vector. Extra options can go either before or after the block.

+
+$ app --exec foo --bar ; -s
+Options { exec: Some(["foo", "--bar"]), switch: true } +
+

This example uses some to make sure there are some parameters, but that’s +optional.

+
+$ app --exec ;
+Error: --exec is not expected in this context + +
+
+
§Multi-value arguments with optional flags
+

Parsing things like --foo ARG1 --flag --inner ARG2

+

So you can parse things while parsing things. Not sure why you might need this, but you can +:)

+ +
#[derive(Debug, Clone)]
+pub struct Options {
+    meal: Vec<Meal>,
+    premium: bool,
+}
+
+#[derive(Debug, Clone)]
+struct Meal {
+    m: (),
+    spicy: Option<usize>,
+    drink: bool,
+    dish: usize,
+}
+
+/// You can mix all sorts of things inside the adjacent group
+fn meal() -> impl Parser<Meal> {
+    let m = short('o')
+        .long("meal")
+        .help("A meal [o]rder consists of a main dish with an optional drink")
+        .req_flag(());
+    let spicy = long("spicy")
+        .help("On a scale from 1 to a lot, how spicy do you want your meal?")
+        .argument::<usize>("SPICY")
+        .optional();
+    let drink = long("drink")
+        .help("Do you want drink with your meal?")
+        .switch();
+    let dish = positional::<usize>("DISH").help("Main dish number");
+    construct!(Meal {
+        m,
+        spicy,
+        drink,
+        dish
+    })
+    .adjacent()
+}
+
+pub fn options() -> OptionParser<Options> {
+    let premium = short('p')
+        .long("premium")
+        .help("Do you want to opt in for premium service?")
+        .switch();
+    let meal = meal().many();
+    construct!(Options { meal, premium }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +
+$ app --help
+

Usage: app [-o [--spicy=SPICY] [--drink] DISH]... [-p]

+Available options:
-o [--spicy=SPICY] [--drink] DISH
-o, --meal
+
A meal [o]rder consists of a main dish with an optional drink
+
--spicy=SPICY
+
On a scale from 1 to a lot, how spicy do you want your meal?
+
--drink
+
Do you want drink with your meal?
+
DISH
+
Main dish number
+

-p, --premium
+
Do you want to opt in for premium service?
+
-h, --help
+
Prints help information
+
+

+ +
+

Let’s start simple - a single flag accepts a bunch of stuff, and eveything is present

+
+$ app --meal 330 --spicy 10 --drink
+Options { meal: [Meal { m: (), spicy: Some(10), drink: true, dish: 330 }], premium: false } +
+

You can omit some parts, but also have multiple groups thank to many

+
+$ app --meal 100 --drink --meal 30 --spicy 10 --meal 50
+Options { meal: [Meal { m: (), spicy: None, drink: true, dish: 100 }, Meal { m: (), spicy: Some(10), drink: false, dish: 30 }, Meal { m: (), spicy: None, drink: false, dish: 50 }], premium: false } +
+

As usual it can be mixed with standalone flags

+
+$ app --premium --meal 42
+Options { meal: [Meal { m: (), spicy: None, drink: false, dish: 42 }], premium: true } +
+

Thanks to many whole meal part is optional

+
+$ app --premium
+Options { meal: [], premium: true } +
+

Error messages should be somewhat descriptive

+
+$ app --meal --drink --spicy 500
+Error: expected DISH, pass --help for usage information + +
+
+
§Performance and other considerations
+

bpaf can run adjacently restricted parsers multiple times to refine the guesses. It’s +best not to have complex inter-fields verification since they might trip up the detection +logic: instead of restricting, for example “sum of two fields to be 5 or greater” inside the +adjacent parser, you can restrict it outside, once adjacent done the parsing.

+

There’s also similar method adjacent that allows to restrict argument +parser to work only for arguments where both key and a value are in the same shell word: +-f=bar or -fbar, but not -f bar.

+

Trait Implementations§

source§

impl<T, P> Parser<T> for ParseCon<P>
where + P: Fn(bool, &mut State) -> Result<T, Error>,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<P> RefUnwindSafe for ParseCon<P>
where + P: RefUnwindSafe,

§

impl<P> Send for ParseCon<P>
where + P: Send,

§

impl<P> Sync for ParseCon<P>
where + P: Sync,

§

impl<P> Unpin for ParseCon<P>
where + P: Unpin,

§

impl<P> UnwindSafe for ParseCon<P>
where + P: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseCount.html b/bpaf/parsers/struct.ParseCount.html new file mode 100644 index 00000000..eb4c125b --- /dev/null +++ b/bpaf/parsers/struct.ParseCount.html @@ -0,0 +1,69 @@ +ParseCount in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseCount

source ·
pub struct ParseCount<P, T> { /* private fields */ }
Expand description

Apply inner parser as many times as it succeeds while consuming something and return this +number

+

Trait Implementations§

source§

impl<T, P> Parser<usize> for ParseCount<P, T>
where + P: Parser<T>,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<P, T> RefUnwindSafe for ParseCount<P, T>
where + P: RefUnwindSafe, + T: RefUnwindSafe,

§

impl<P, T> Send for ParseCount<P, T>
where + P: Send, + T: Send,

§

impl<P, T> Sync for ParseCount<P, T>
where + P: Sync, + T: Sync,

§

impl<P, T> Unpin for ParseCount<P, T>
where + P: Unpin, + T: Unpin,

§

impl<P, T> UnwindSafe for ParseCount<P, T>
where + P: UnwindSafe, + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseFallback.html b/bpaf/parsers/struct.ParseFallback.html new file mode 100644 index 00000000..85b9a857 --- /dev/null +++ b/bpaf/parsers/struct.ParseFallback.html @@ -0,0 +1,260 @@ +ParseFallback in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseFallback

source ·
pub struct ParseFallback<P, T> { /* private fields */ }
Expand description

Parser that substitutes missing value but not parse failure, created with +fallback.

+

Implementations§

source§

impl<P, T: Display> ParseFallback<P, T>

source

pub fn display_fallback(self) -> Self

Show fallback value in --help using Display +representation

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    jobs: usize,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let jobs = long("jobs")
+        .help("Number of jobs")
+        .argument("JOBS")
+        .fallback(42)
+        .display_fallback();
+    construct!(Options { jobs }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+#[allow(dead_code)]
+pub struct Options {
+    /// Number of jobs
+    #[bpaf(argument("JOBS"), fallback(42), display_fallback)]
+    jobs: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

fallback changes parser to fallback to a default value used when argument is not specified

+
+$ app
+Options { jobs: 42 } +
+

If value is present - fallback value is ignored

+
+$ app --jobs 10
+Options { jobs: 10 } +
+

Parsing errors are preserved and preserved to user

+
+$ app --jobs ten
+Error: couldn't parse ten: invalid digit found in string + +
+

With display_fallback and +debug_fallback you can make it so default value +is visible in --help output

+
+$ app --help
+

Usage: app [--jobs=JOBS]

+Available options:
--jobs=JOBS
+
Number of jobs
+
+
[default: 42]
+
-h, --help
+
Prints help information
+
+

+ +
+
source§

impl<P, T: Debug> ParseFallback<P, T>

source

pub fn debug_fallback(self) -> Self

Show fallback value in --help using Debug +representation

+
Combinatoric example + +
fn try_to_get_version() -> Result<usize, &'static str> {
+    Ok(42)
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    version: usize,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let version = long("version")
+        .help("Specify protocol version")
+        .argument("VERS")
+        .fallback_with(try_to_get_version)
+        .debug_fallback();
+    construct!(Options { version }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
fn try_to_get_version() -> Result<usize, &'static str> {
+    Ok(42)
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(argument("VERS"), fallback_with(try_to_get_version), debug_fallback)]
+    /// Specify protocol version
+    version: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

fallback_with changes parser to fallback to a value that comes from a potentially failing +computation when argument is not specified

+
+$ app
+Options { version: 42 } +
+

If value is present - fallback value is ignored

+
+$ app --version 10
+Options { version: 10 } +
+

Parsing errors are preserved and preserved to user

+
+$ app --version ten
+Error: couldn't parse ten: invalid digit found in string + +
+

bpaf encases parsers with fallback value of some sort in usage with []

+
+$ app --help
+

Usage: app [--version=VERS]

+Available options:
--version=VERS
+
Specify protocol version
+
+
[default: 42]
+
-h, --help
+
Prints help information
+
+

+ +
+

Trait Implementations§

source§

impl<P, T> Parser<T> for ParseFallback<P, T>
where + P: Parser<T>, + T: Clone,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<P, T> RefUnwindSafe for ParseFallback<P, T>
where + P: RefUnwindSafe, + T: RefUnwindSafe,

§

impl<P, T> Send for ParseFallback<P, T>
where + P: Send, + T: Send,

§

impl<P, T> Sync for ParseFallback<P, T>
where + P: Sync, + T: Sync,

§

impl<P, T> Unpin for ParseFallback<P, T>
where + P: Unpin, + T: Unpin,

§

impl<P, T> UnwindSafe for ParseFallback<P, T>
where + P: UnwindSafe, + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseFallbackWith.html b/bpaf/parsers/struct.ParseFallbackWith.html new file mode 100644 index 00000000..b4a6e5c4 --- /dev/null +++ b/bpaf/parsers/struct.ParseFallbackWith.html @@ -0,0 +1,275 @@ +ParseFallbackWith in bpaf::parsers - Rust +
pub struct ParseFallbackWith<T, P, F, E> { /* private fields */ }
Expand description

Parser that substitutes missing value with a function results but not parser +failure, created with fallback_with.

+

Implementations§

source§

impl<P, T: Display, F, E> ParseFallbackWith<T, P, F, E>
where + F: Fn() -> Result<T, E>,

source

pub fn display_fallback(self) -> Self

Show fallback_with value in --help using Display +representation

+

If fallback function fails - no value will show up

+
Combinatoric example + +
fn try_to_get_version() -> Result<usize, &'static str> {
+    Ok(42)
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    version: usize,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let version = long("version")
+        .help("Specify protocol version")
+        .argument("VERS")
+        .fallback_with(try_to_get_version)
+        .display_fallback();
+    construct!(Options { version }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
fn try_to_get_version() -> Result<usize, &'static str> {
+    Ok(42)
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(argument("VERS"), fallback_with(try_to_get_version), display_fallback)]
+    /// Specify protocol version
+    version: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

fallback_with changes parser to fallback to a value that comes from a potentially failing +computation when argument is not specified

+
+$ app
+Options { version: 42 } +
+

If value is present - fallback value is ignored

+
+$ app --version 10
+Options { version: 10 } +
+

Parsing errors are preserved and preserved to user

+
+$ app --version ten
+Error: couldn't parse ten: invalid digit found in string + +
+

bpaf encases parsers with fallback value of some sort in usage with []

+
+$ app --help
+

Usage: app [--version=VERS]

+Available options:
--version=VERS
+
Specify protocol version
+
+
[default: 42]
+
-h, --help
+
Prints help information
+
+

+ +
+
source§

impl<P, T: Debug, F, E> ParseFallbackWith<T, P, F, E>
where + F: Fn() -> Result<T, E>,

source

pub fn debug_fallback(self) -> Self

Show fallback_with value in --help using Debug +representation

+

If fallback function fails - no value will show up

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    jobs: usize,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let jobs = long("jobs")
+        .help("Number of jobs")
+        .argument("JOBS")
+        .fallback(42)
+        .debug_fallback();
+    construct!(Options { jobs }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+#[allow(dead_code)]
+pub struct Options {
+    /// Number of jobs
+    #[bpaf(argument("JOBS"), fallback(42), debug_fallback)]
+    jobs: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

fallback changes parser to fallback to a default value used when argument is not specified

+
+$ app
+Options { jobs: 42 } +
+

If value is present - fallback value is ignored

+
+$ app --jobs 10
+Options { jobs: 10 } +
+

Parsing errors are preserved and preserved to user

+
+$ app --jobs ten
+Error: couldn't parse ten: invalid digit found in string + +
+

With display_fallback and +debug_fallback you can make it so default value +is visible in --help output

+
+$ app --help
+

Usage: app [--jobs=JOBS]

+Available options:
--jobs=JOBS
+
Number of jobs
+
+
[default: 42]
+
-h, --help
+
Prints help information
+
+

+ +
+

Trait Implementations§

source§

impl<T, P, F, E> Parser<T> for ParseFallbackWith<T, P, F, E>
where + P: Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<T, P, F, E> RefUnwindSafe for ParseFallbackWith<T, P, F, E>

§

impl<T, P, F, E> Send for ParseFallbackWith<T, P, F, E>
where + E: Send, + F: Send, + P: Send, + T: Send,

§

impl<T, P, F, E> Sync for ParseFallbackWith<T, P, F, E>
where + E: Sync, + F: Sync, + P: Sync, + T: Sync,

§

impl<T, P, F, E> Unpin for ParseFallbackWith<T, P, F, E>
where + E: Unpin, + F: Unpin, + P: Unpin, + T: Unpin,

§

impl<T, P, F, E> UnwindSafe for ParseFallbackWith<T, P, F, E>
where + E: UnwindSafe, + F: UnwindSafe, + P: UnwindSafe, + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseFlag.html b/bpaf/parsers/struct.ParseFlag.html new file mode 100644 index 00000000..c5ba5e96 --- /dev/null +++ b/bpaf/parsers/struct.ParseFlag.html @@ -0,0 +1,66 @@ +ParseFlag in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseFlag

source ·
pub struct ParseFlag<T> { /* private fields */ }
Expand description

Parser for a named switch, created with NamedArg::flag or NamedArg::switch

+

Implementations§

source§

impl<T> ParseFlag<T>

source

pub fn help<M>(self, help: M) -> Self
where + M: Into<Doc>,

Add a help message to flag

+

See NamedArg::help

+

Trait Implementations§

source§

impl<T: Clone> Clone for ParseFlag<T>

source§

fn clone(&self) -> ParseFlag<T>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T: Clone + 'static> Parser<T> for ParseFlag<T>

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<T> RefUnwindSafe for ParseFlag<T>
where + T: RefUnwindSafe,

§

impl<T> Send for ParseFlag<T>
where + T: Send,

§

impl<T> Sync for ParseFlag<T>
where + T: Sync,

§

impl<T> Unpin for ParseFlag<T>
where + T: Unpin,

§

impl<T> UnwindSafe for ParseFlag<T>
where + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseLast.html b/bpaf/parsers/struct.ParseLast.html new file mode 100644 index 00000000..f53f57d0 --- /dev/null +++ b/bpaf/parsers/struct.ParseLast.html @@ -0,0 +1,64 @@ +ParseLast in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseLast

source ·
pub struct ParseLast<P> { /* private fields */ }
Expand description

Apply inner parser as many times as it succeeds while consuming something and return this +number

+

Trait Implementations§

source§

impl<T, P> Parser<T> for ParseLast<P>
where + P: Parser<T>,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<P> RefUnwindSafe for ParseLast<P>
where + P: RefUnwindSafe,

§

impl<P> Send for ParseLast<P>
where + P: Send,

§

impl<P> Sync for ParseLast<P>
where + P: Sync,

§

impl<P> Unpin for ParseLast<P>
where + P: Unpin,

§

impl<P> UnwindSafe for ParseLast<P>
where + P: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseMany.html b/bpaf/parsers/struct.ParseMany.html new file mode 100644 index 00000000..fd019358 --- /dev/null +++ b/bpaf/parsers/struct.ParseMany.html @@ -0,0 +1,199 @@ +ParseMany in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseMany

source ·
pub struct ParseMany<P> { /* private fields */ }
Expand description

Apply inner parser several times and collect results into Vec, created with +many, implements catch.

+

Implementations§

source§

impl<P> ParseMany<P>

source

pub fn catch(self) -> Self

Handle parse failures

+

Can be useful to decide to skip parsing of some items on a command line +When parser succeeds - catch version would return a value as usual +if it fails - catch would restore all the consumed values and return None.

+

There’s several structures that implement this attribute: ParseOptional, ParseMany +and ParseSome, behavior should be identical for all of them.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    height: Vec<usize>,
+    height_str: Vec<String>,
+    width: Vec<usize>,
+    width_str: Vec<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    // contains catch
+    let height = long("height")
+        .help("Height of a rectangle")
+        .argument::<usize>("PX")
+        .many()
+        .catch();
+
+    let height_str = long("height").argument::<String>("PX").many().hide();
+
+    // contains no catch
+    let width = long("width")
+        .help("Width of a rectangle")
+        .argument::<usize>("PX")
+        .many();
+
+    let width_str = long("width").argument::<String>("PX").many().hide();
+
+    construct!(Options {
+        height,
+        height_str,
+        width,
+        width_str
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(long, argument("PX"), many, catch)]
+    /// Height of a rectangle
+    height: Vec<usize>,
+
+    #[bpaf(long("height"), argument("PX"), many, hide)]
+    height_str: Vec<String>,
+
+    #[bpaf(long, argument("PX"), many)]
+    /// Width of a rectangle
+    width: Vec<usize>,
+
+    #[bpaf(long("width"), argument("PX"), many, hide)]
+    width_str: Vec<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Despite parser producing a funky value - help looks like you would expect from a parser that +takes two values

+
+$ app --help
+

Usage: app [--height=PX]... [--width=PX]...

+Available options:
--height=PX
+
Height of a rectangle
+
--width=PX
+
Width of a rectangle
+
-h, --help
+
Prints help information
+
+

+ +
+

When executed with no parameters it produces four [] values - all parsers succeed by the +nature of them being many

+
+$ app
+Options { height: [], height_str: [], width: [], width_str: [] } +
+

When executed with expected parameters fields with usize get their values

+
+$ app --height 100 --width 100 --height 12 --width 44
+Options { height: [100, 12], height_str: [], width: [100, 44], width_str: [] } +
+

With incorrect value for --height parameter inner part of height parser fails, many +combined with catch handles this failure and produces [] without consuming value from the +command line. Parser height_str runs next and consumes the value as a string

+
+$ app --height ten --height twenty
+Options { height: [], height_str: ["ten", "twenty"], width: [], width_str: [] } +
+

In case of wrong --width - parser width fails, parser for many sees this as a +“value is present but not correct” and propagates the error outside, execution never reaches +width_str parser

+
+$ app --width ten
+Error: couldn't parse ten: invalid digit found in string + +
+

Trait Implementations§

source§

impl<T, P> Parser<Vec<T>> for ParseMany<P>
where + P: Parser<T>,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<P> RefUnwindSafe for ParseMany<P>
where + P: RefUnwindSafe,

§

impl<P> Send for ParseMany<P>
where + P: Send,

§

impl<P> Sync for ParseMany<P>
where + P: Sync,

§

impl<P> Unpin for ParseMany<P>
where + P: Unpin,

§

impl<P> UnwindSafe for ParseMany<P>
where + P: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseOptional.html b/bpaf/parsers/struct.ParseOptional.html new file mode 100644 index 00000000..9628d6a5 --- /dev/null +++ b/bpaf/parsers/struct.ParseOptional.html @@ -0,0 +1,203 @@ +ParseOptional in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseOptional

source ·
pub struct ParseOptional<P> { /* private fields */ }
Expand description

Apply inner parser, return a value in Some if items requested by it are all present, restore +and return None if any are missing. Created with optional. Implements +catch

+

Implementations§

source§

impl<P> ParseOptional<P>

source

pub fn catch(self) -> Self

Handle parse failures for optional parsers

+

Can be useful to decide to skip parsing of some items on a command line. +When parser succeeds - catch version would return a value as usual +if it fails - catch would restore all the consumed values and return None.

+

There’s several structures that implement this attribute: ParseOptional, ParseMany +and ParseSome, behavior should be identical for all of them.

+

Those examples are very artificial and designed to show what difference catch makes, to +actually parse arguments like in examples you should parse or construct +enum with alternative branches

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    height: Option<usize>,
+    height_str: Option<String>,
+    width: Option<usize>,
+    width_str: Option<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    // contains catch
+    let height = long("height")
+        .help("Height of a rectangle")
+        .argument::<usize>("PX")
+        .optional()
+        .catch();
+
+    let height_str = long("height").argument::<String>("PX").optional().hide();
+
+    // contains no catch
+    let width = long("width")
+        .help("Width of a rectangle")
+        .argument::<usize>("PX")
+        .optional();
+
+    let width_str = long("width").argument::<String>("PX").optional().hide();
+
+    construct!(Options {
+        height,
+        height_str,
+        width,
+        width_str
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(long, argument("PX"), optional, catch)]
+    /// Height of a rectangle
+    height: Option<usize>,
+
+    #[bpaf(long("height"), argument("PX"), optional, hide)]
+    height_str: Option<String>,
+
+    #[bpaf(long, argument("PX"), optional)]
+    /// Width of a rectangle
+    width: Option<usize>,
+
+    #[bpaf(long("width"), argument("PX"), optional, hide)]
+    width_str: Option<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Despite parser producing a funky value - help looks like you would expect from a parser that +takes two values

+
+$ app --help
+

Usage: app [--height=PX] [--width=PX]

+Available options:
--height=PX
+
Height of a rectangle
+
--width=PX
+
Width of a rectangle
+
-h, --help
+
Prints help information
+
+

+ +
+

When executed with no parameters it produces four None values - all parsers succeed by the +nature of them being optional

+
+$ app
+Options { height: None, height_str: None, width: None, width_str: None } +
+

When executed with expected parameters fields with usize get their values

+
+$ app --height 100 --width 100
+Options { height: Some(100), height_str: None, width: Some(100), width_str: None } +
+

With incorrect value for --height parameter inner part of height parser fails, optional +combined with catch handles this failure and produces None without consuming value from the +command line. Parser height_str runs next and consumes the value as a string

+
+$ app --height ten
+Options { height: None, height_str: Some("ten"), width: None, width_str: None } +
+

In case of wrong --width - parser width fails, parser for optional sees this as a +“value is present but not correct” and propagates the error outside, execution never reaches +width_str parser

+
+$ app --width ten
+Error: couldn't parse ten: invalid digit found in string + +
+

Trait Implementations§

source§

impl<T, P> Parser<Option<T>> for ParseOptional<P>
where + P: Parser<T>,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<P> RefUnwindSafe for ParseOptional<P>
where + P: RefUnwindSafe,

§

impl<P> Send for ParseOptional<P>
where + P: Send,

§

impl<P> Sync for ParseOptional<P>
where + P: Sync,

§

impl<P> Unpin for ParseOptional<P>
where + P: Unpin,

§

impl<P> UnwindSafe for ParseOptional<P>
where + P: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParsePositional.html b/bpaf/parsers/struct.ParsePositional.html new file mode 100644 index 00000000..cdf4db00 --- /dev/null +++ b/bpaf/parsers/struct.ParsePositional.html @@ -0,0 +1,334 @@ +ParsePositional in bpaf::parsers - Rust +
pub struct ParsePositional<T> { /* private fields */ }
Expand description

Parse a positional item, created with positional

+

You can add extra information to positional parsers with help +and strict on this struct.

+

Implementations§

source§

impl<T> ParsePositional<T>

source

pub fn help<M>(self, help: M) -> Self
where + M: Into<Doc>,

Add a help message to a positional parser

+

bpaf converts doc comments and string into help by following those rules:

+
    +
  1. Everything up to the first blank line is included into a “short” help message
  2. +
  3. Everything is included into a “long” help message
  4. +
  5. bpaf preserves linebreaks followed by a line that starts with a space
  6. +
  7. Linebreaks are removed otherwise
  8. +
+

You can pass anything that can be converted into Doc, if you are not using +documentation generation functionality (doc) this can be &str.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    crate_name: String,
+    feature_name: Option<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help("Display detailed information")
+        .switch();
+
+    let crate_name = positional("CRATE").help("Crate name to use");
+
+    let feature_name = positional("FEATURE")
+        .help("Display information about this feature")
+        .optional();
+
+    construct!(Options {
+        verbose,
+        // You must place positional items and commands after
+        // all other parsers
+        crate_name,
+        feature_name
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Display detailed information
+    #[bpaf(short, long)]
+    verbose: bool,
+
+    // You must place positional items and commands after
+    // all other parsers
+    #[bpaf(positional("CRATE"))]
+    /// Crate name to use
+    crate_name: String,
+
+    #[bpaf(positional("FEATURE"))]
+    /// Display information about this feature
+    feature_name: Option<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Positional items show up in a separate group of arguments if they contain a help message, +otherwise they will show up only in Usage part.

+
+$ app --help
+

Usage: app [-v] CRATE [FEATURE]

+Available positional items:
CRATE
+
Crate name to use
+
FEATURE
+
Display information about this feature
+
+

+Available options:
-v, --verbose
+
Display detailed information
+
-h, --help
+
Prints help information
+
+

+ +
+

You can mix positional items with regular items

+
+$ app --verbose bpaf
+Options { verbose: true, crate_name: "bpaf", feature_name: None } +
+

And since bpaf API expects to have non positional items consumed before positional ones - you +can use them in a different order. In this example bpaf corresponds to a crate_name field and +--verbose – to verbose.

+
+$ app bpaf --verbose
+Options { verbose: true, crate_name: "bpaf", feature_name: None } +
+

In previous examples optional field feature was missing, this one contains it.

+
+$ app bpaf autocomplete
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("autocomplete") } +
+

Users can use -- to tell bpaf to treat remaining items as positionals - this might be +required to handle unusual items.

+
+$ app bpaf -- --verbose
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("--verbose") } +
+
+$ app -- bpaf --verbose
+Options { verbose: false, crate_name: "bpaf", feature_name: Some("--verbose") } +
+

Without using -- bpaf would only accept items that don’t start with - as positional.

+
+$ app --detailed
+Error: expected CRATE, got --detailed. Pass --help for usage information + +
+
+$ app --verbose
+Error: expected CRATE, pass --help for usage information + +
+

You can use any to work around this restriction.

+
source

pub fn strict(self) -> Self

Changes positional parser to be a “strict” positional

+

Usually positional items can appear anywhere on a command line:

+
$ ls -d bpaf
+$ ls bpaf -d
+
+

here ls takes a positional item bpaf and a flag -d

+

But in some cases it might be useful to have a stricter separation between +positonal items and flags, such as passing arguments to a subprocess:

+
$ cargo run --example basic -- --help
+
+

here cargo takes a --help as a positional item and passes it to the example

+

bpaf allows to require user to pass -- for positional items with strict annotation. +bpaf would display such positional elements differently in usage line as well.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbose: bool,
+    binary: String,
+    args: Vec<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbose = short('v')
+        .long("verbose")
+        .help("Produce detailed report")
+        .switch();
+    let binary = long("bin").help("Binary to execute").argument("BIN");
+    let args = positional("ARG")
+        .help("Arguments for the binary")
+        .strict()
+        .many();
+    construct!(Options {
+        verbose,
+        binary,
+        args
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long)]
+    /// Produce detailed report
+    verbose: bool,
+    #[bpaf(long("bin"), argument("BIN"))]
+    /// Binary to execute
+    binary: String,
+    #[bpaf(positional("ARG"), strict, many)]
+    /// Arguments for the binary
+    args: Vec<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Usage line for a cargo-run like app that takes an app name and possibly many strictly +positional child arguments can look like this:

+
+$ app --help
+

Usage: app [-v] --bin=BIN -- [ARG]...

+Available positional items:
ARG
+
Arguments for the binary
+
+

+Available options:
-v, --verbose
+
Produce detailed report
+
--bin=BIN
+
Binary to execute
+
-h, --help
+
Prints help information
+
+

+ +
+

Here any argument passed before double dash goes to the parser itself

+
+$ app --bin dd --verbose
+Options { verbose: true, binary: "dd", args: [] } +
+

Anything after it - collected into strict arguments

+
+$ app --bin dd -- --verbose
+Options { verbose: false, binary: "dd", args: ["--verbose"] } +
+

Trait Implementations§

source§

impl<T: Clone> Clone for ParsePositional<T>

source§

fn clone(&self) -> ParsePositional<T>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T> Parser<T> for ParsePositional<T>
where + T: FromStr + 'static, + <T as FromStr>::Err: Display,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<T> RefUnwindSafe for ParsePositional<T>
where + T: RefUnwindSafe,

§

impl<T> Send for ParsePositional<T>
where + T: Send,

§

impl<T> Sync for ParsePositional<T>
where + T: Sync,

§

impl<T> Unpin for ParsePositional<T>
where + T: Unpin,

§

impl<T> UnwindSafe for ParsePositional<T>
where + T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/parsers/struct.ParseSome.html b/bpaf/parsers/struct.ParseSome.html new file mode 100644 index 00000000..79070020 --- /dev/null +++ b/bpaf/parsers/struct.ParseSome.html @@ -0,0 +1,212 @@ +ParseSome in bpaf::parsers - Rust +

Struct bpaf::parsers::ParseSome

source ·
pub struct ParseSome<P> { /* private fields */ }
Expand description

Apply inner parser several times and collect results into Vec, created with +some, requires for at least one item to be available to succeed. +Implements catch

+

Implementations§

source§

impl<P> ParseSome<P>

source

pub fn catch(self) -> Self

Handle parse failures

+

Can be useful to decide to skip parsing of some items on a command line +When parser succeeds - catch version would return a value as usual +if it fails - catch would restore all the consumed values and return None.

+

There’s several structures that implement this attribute: ParseOptional, ParseMany +and ParseSome, behavior should be identical for all of them.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    height: Vec<usize>,
+    height_str: Vec<String>,
+    width: Vec<usize>,
+    width_str: Vec<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    // contains catch
+    let height = long("height")
+        .help("Height of a rectangle")
+        .argument::<usize>("PX")
+        .some("You must specify some heights")
+        .catch();
+
+    let height_str = long("height").argument::<String>("PX").many().hide();
+
+    // contains no catch
+    let width = long("width")
+        .help("Width of a rectangle")
+        .argument::<usize>("PX")
+        .some("You must specify some widths");
+
+    let width_str = long("width").argument::<String>("PX").many().hide();
+
+    construct!(Options {
+        height,
+        height_str,
+        width,
+        width_str
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(long, argument("PX"), some("You must specify some heights"), catch)]
+    /// Height of a rectangle
+    height: Vec<usize>,
+
+    #[bpaf(long("height"), argument("PX"), many, hide)]
+    height_str: Vec<String>,
+
+    #[bpaf(long, argument("PX"), some("You must specify some widths"))]
+    /// Width of a rectangle
+    width: Vec<usize>,
+
+    #[bpaf(long("width"), argument("PX"), many, hide)]
+    width_str: Vec<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Despite parser producing a funky value - help looks like you would expect from a parser that +takes two values

+
+$ app --help
+

Usage: app --height=PX... --width=PX...

+Available options:
--height=PX
+
Height of a rectangle
+
--width=PX
+
Width of a rectangle
+
-h, --help
+
Prints help information
+
+

+ +
+

When executed with no parameters parser fails because some requires you to specify at least +one matching parameter

+
+$ app
+Error: You must specify some heights + +
+

When executed with expected parameters fields with usize get their values

+
+$ app --height 100 --width 100 --height 12 --width 44
+Options { height: [100, 12], height_str: [], width: [100, 44], width_str: [] } +
+

With incorrect value for --height parameter inner part of height parser fails, some +combined with catch handles this failure and produces [] without consuming value from the +command line. Parser height_str runs next and consumes the value as a string

+
+$ app --height 10 --height twenty --width 33
+Options { height: [10], height_str: ["twenty"], width: [33], width_str: [] } +
+

In case of wrong --width - parser width fails, parser for some sees this as a +“value is present but not correct” and propagates the error outside, execution never reaches +width_str parser

+
+$ app --height 10 --width 33 --width ten
+Error: couldn't parse ten: invalid digit found in string + +
+

Trait Implementations§

source§

impl<T, P> Parser<Vec<T>> for ParseSome<P>
where + P: Parser<T>,

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Auto Trait Implementations§

§

impl<P> RefUnwindSafe for ParseSome<P>
where + P: RefUnwindSafe,

§

impl<P> Send for ParseSome<P>
where + P: Send,

§

impl<P> Sync for ParseSome<P>
where + P: Sync,

§

impl<P> Unpin for ParseSome<P>
where + P: Unpin,

§

impl<P> UnwindSafe for ParseSome<P>
where + P: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/sidebar-items.js b/bpaf/sidebar-items.js new file mode 100644 index 00000000..c49f80f7 --- /dev/null +++ b/bpaf/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"derive":["Bpaf"],"enum":["ParseFailure","ShellComp"],"fn":["any","choice","env","fail","literal","long","positional","pure","pure_with","short"],"macro":["construct"],"mod":["_documentation","batteries","doc","params","parsers"],"struct":["Args","Doc","OptionParser"],"trait":["Parser"]}; \ No newline at end of file diff --git a/bpaf/struct.Args.html b/bpaf/struct.Args.html new file mode 100644 index 00000000..c6a9e5f4 --- /dev/null +++ b/bpaf/struct.Args.html @@ -0,0 +1,61 @@ +Args in bpaf - Rust +

Struct bpaf::Args

source ·
pub struct Args<'a> { /* private fields */ }
Expand description

All currently present command line parameters with some extra metainfo

+

Use it for unit tests and manual parsing. For production use you would want to replace the +program name with set_name, but for tests passing a slice of strings to +run_inner is usually more convenient.

+

The easiest way to create Args is by using its From instance.

+ +
let parser = short('f')
+    .switch()
+    .to_options();
+let value = parser
+    .run_inner(Args::from(&["-f"]))
+    .unwrap();
+assert!(value);
+
+// this also works
+let value = parser.run_inner(&["-f"])
+    .unwrap();
+assert!(value);
+

Implementations§

source§

impl Args<'_>

source

pub fn set_comp(self, rev: usize) -> Self

Enable completions with custom output revision style

+

Use revision 0 if you want to test completion mechanism

+ +
let parser = short('f').switch().to_options();
+// ask bpaf to produce more input from "-", for
+// suggesting new items use "" at the end
+let r = parser.run_inner(Args::from(&["-"])
+    .set_comp(0))
+    .unwrap_err()
+    .unwrap_stdout();
+assert_eq!(r, "-f");
+
source

pub fn set_name(self, name: &str) -> Self

Add an application name for args created from custom input

+ +
let parser = short('f').switch().to_options();
+let r = parser
+    .run_inner(Args::from(&["--help"]).set_name("my_app"))
+    .unwrap_err()
+    .unwrap_stdout();
+
source§

impl Args<'_>

source

pub fn current_args() -> Self

Get a list of command line arguments from OS

+

Trait Implementations§

source§

impl<'a> From<&'a [&'a OsStr]> for Args<'a>

source§

fn from(value: &'a [&'a OsStr]) -> Self

Converts to this type from the input type.
source§

impl<'a> From<&'a [&'a str]> for Args<'a>

source§

fn from(value: &'a [&'a str]) -> Self

Converts to this type from the input type.
source§

impl<const N: usize> From<&'static [&'static str; N]> for Args<'_>

source§

fn from(value: &'static [&'static str; N]) -> Self

Converts to this type from the input type.
source§

impl<'a> From<&'a [OsString]> for Args<'a>

source§

fn from(value: &'a [OsString]) -> Self

Converts to this type from the input type.
source§

impl<'a> From<&'a [String]> for Args<'a>

source§

fn from(value: &'a [String]) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<'a> !RefUnwindSafe for Args<'a>

§

impl<'a> !Send for Args<'a>

§

impl<'a> !Sync for Args<'a>

§

impl<'a> Unpin for Args<'a>

§

impl<'a> !UnwindSafe for Args<'a>

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/struct.Doc.html b/bpaf/struct.Doc.html new file mode 100644 index 00000000..811064de --- /dev/null +++ b/bpaf/struct.Doc.html @@ -0,0 +1,48 @@ +Doc in bpaf - Rust +

Struct bpaf::Doc

source ·
pub struct Doc { /* private fields */ }
Expand description

String with styled segments.

+

You can add style information to generated documentation and help messages +For simpliest possible results you can also pass a string slice in all the places +that require impl Into<Doc>

+

Implementations§

source§

impl Doc

source

pub fn monochrome(&self, full: bool) -> String

Render a monochrome version of the document

+

full indicates if full message should be rendered, this makes +difference for rendered help message, otherwise you can pass true.

+
source§

impl Doc

source

pub fn render_markdown(&self, full: bool) -> String

Render doc into markdown document, used by documentation sample generator

+
source§

impl Doc

source

pub fn text(&mut self, text: &str)

Append a fragment of plain text to Doc

+

See Doc for usage examples

+
source

pub fn literal(&mut self, text: &str)

Append a fragment of literal text to Doc

+

See Doc for usage examples

+
source

pub fn emphasis(&mut self, text: &str)

Append a fragment of text with emphasis to Doc

+

See Doc for usage examples

+
source

pub fn invalid(&mut self, text: &str)

Append a fragment of unexpected user input to Doc

+

See Doc for usage examples

+
source

pub fn meta(&mut self, meta: MetaInfo<'_>, for_usage: bool)

Append a fragment of parser metadata to Doc

+

See Doc for usage examples

+
source

pub fn doc(&mut self, buf: &Doc)

Append a Doc to Doc

+

See Doc for usage examples

+
source

pub fn em_doc(&mut self, buf: &Doc)

Append a Doc to Doc for plaintext documents try to format +first line as a help section header

+

Trait Implementations§

source§

impl Clone for Doc

source§

fn clone(&self) -> Doc

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Doc

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for Doc

source§

fn default() -> Doc

Returns the “default value” for a type. Read more
source§

impl Display for Doc

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl From<&[(&str, Style)]> for Doc

source§

fn from(val: &[(&str, Style)]) -> Self

Converts to this type from the input type.
source§

impl<const N: usize> From<&'static [(&'static str, Style); N]> for Doc

source§

fn from(val: &'static [(&'static str, Style); N]) -> Self

Converts to this type from the input type.
source§

impl From<&str> for Doc

source§

fn from(value: &str) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl RefUnwindSafe for Doc

§

impl Send for Doc

§

impl Sync for Doc

§

impl Unpin for Doc

§

impl UnwindSafe for Doc

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T> ToOwned for T
where + T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T> ToString for T
where + T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/struct.OptionParser.html b/bpaf/struct.OptionParser.html new file mode 100644 index 00000000..5440e442 --- /dev/null +++ b/bpaf/struct.OptionParser.html @@ -0,0 +1,1086 @@ +OptionParser in bpaf - Rust +

Struct bpaf::OptionParser

source ·
pub struct OptionParser<T> { /* private fields */ }
Expand description

Ready to run Parser with additional information attached

+

Created with to_options

+

In addition to the inner parser OptionParser contains documentation about a program or a +subcommand as a whole, version, custom usage, if specified, and handles custom parsers for +--version and --help flags.

+

Implementations§

source§

impl<T> OptionParser<T>

source

pub fn render_html(&self, app: impl Into<String>) -> String

Render command line documentation for the app into html/markdown mix

+
source

pub fn render_markdown(&self, app: impl Into<String>) -> String

Render command line documentation for the app into Markdown

+
source§

impl<T> OptionParser<T>

source

pub fn render_manpage( + &self, + app: impl AsRef<str>, + section: Section<'_>, + last_update_date: Option<&str>, + vendor: Option<&str>, + application_title: Option<&str> +) -> String

Render command line documentation for the app into a manpage

+
source§

impl<T> OptionParser<T>

source

pub fn run(self) -> T
where + Self: Sized,

Execute the OptionParser, extract a parsed value or print some diagnostic and exit

+
§Usage
+
/// Parses number of repetitions of `-v` on a command line
+fn verbosity() -> OptionParser<usize> {
+    let parser = short('v')
+        .req_flag(())
+        .many()
+        .map(|xs|xs.len());
+
+    parser
+        .to_options()
+        .descr("Takes verbosity flag and does nothing else")
+}
+
+fn main() {
+    let verbosity: usize = verbosity().run();
+}
+
source

pub fn try_run(self) -> Result<T, ParseFailure>
where + Self: Sized,

👎Deprecated: You should switch to equivalent parser.run_inner(Args::current_args())

Execute the OptionParser, extract a parsed value or return a ParseFailure

+

In most cases using run is sufficient, you can use try_run if you +want to control the exit code or you need to perform a custom cleanup.

+
§Usage
+
/// Parses number of repetitions of `-v` on a command line
+fn verbosity() -> OptionParser<usize> {
+    let parser = short('v')
+        .req_flag(())
+        .many()
+        .map(|xs|xs.len());
+
+    parser
+        .to_options()
+        .descr("Takes verbosity flag and does nothing else")
+}
+
+fn main() {
+    let verbosity: Option<usize> = match verbosity().try_run() {
+        Ok(v) => Some(v),
+        Err(ParseFailure::Stdout(buf, full)) => {
+            print!("{}", buf.monochrome(full));
+            None
+        }
+        Err(ParseFailure::Completion(msg)) => {
+            print!("{}", msg);
+            None
+        }
+        Err(ParseFailure::Stderr(buf)) => {
+            eprintln!("{}", buf.monochrome(true));
+            None
+        }
+    };
+
+    // Run cleanup tasks
+}
+
§Errors
+

ParseFailure represents parsing errors, autocomplete results and generated --help +output.

+
source

pub fn run_inner<'a>( + &self, + args: impl Into<Args<'a>> +) -> Result<T, ParseFailure>
where + Self: Sized,

Execute the OptionParser and produce a values for unit tests or manual processing

+ +
#[test]
+fn positional_argument() {
+    let parser =
+        positional::<String>("FILE")
+            .help("File to process")
+            .to_options();
+
+    let help = parser
+        .run_inner(&["--help"])
+        .unwrap_err()
+        .unwrap_stdout();
+    let expected_help = "\
+Usage: FILE
+
+Available positional items:
+    FILE        File to process
+
+Available options:
+    -h, --help  Prints help information
+";
+    assert_eq!(expected_help, help);
+}
+

See also Args and it’s From impls to produce input and +ParseFailure::unwrap_stderr / ParseFailure::unwrap_stdout for processing results.

+
§Errors
+

If parser can’t produce desired result run_inner returns ParseFailure +which represents runtime behavior: one branch to print something to stdout and exit with +success and the other branch to print something to stderr and exit with failure.

+

bpaf generates contents of this ParseFailure using expected textual output from +parse, stdout/stderr isn’t actually captured.

+

Exact string reperentations may change between versions including minor releases.

+
source

pub fn version<B: Into<Doc>>(self, version: B) -> Self

Set the version field.

+

By default bpaf won’t include any version info and won’t accept --version switch.

+
§Combinatoric usage
+
use bpaf::*;
+fn options() -> OptionParser<bool>  {
+   short('s')
+       .switch()
+       .to_options()
+       .version(env!("CARGO_PKG_VERSION"))
+}
+
§Derive usage
+

version annotation is available after options and command annotations, takes +an optional argument - version value to use, otherwise bpaf_derive would use value from cargo.

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options, version)]
+struct Options {
+    #[bpaf(short)]
+    switch: bool
+}
+
§Example
$ app --version
+Version: 0.5.0
+
source

pub fn descr<B: Into<Doc>>(self, descr: B) -> Self

Set the description field

+

Description field should be 1-2 lines long briefly explaining program purpose. If +description field is present bpaf would print it right before the usage line.

+
§Combinatoric usage
+
fn options() -> OptionParser<bool>  {
+   short('s')
+       .switch()
+       .to_options()
+       .descr("This is a description")
+       .header("This is a header")
+       .footer("This is a footer")
+}
+
§Derive usage
+

bpaf_derive uses doc comments on the struct / enum to derive description, it skips single empty +lines and uses double empty lines break it into blocks. bpaf_derive would use first block as the +description, second block - header, third block - footer.

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options, version)]
+/// This is a description
+///
+///
+/// This is a header
+///
+///
+/// This is a footer
+///
+///
+/// This is just a comment
+struct Options {
+    #[bpaf(short)]
+    switch: bool
+}
+
§Example
This is a description
+
+Usage: [-s]
+
+This is a header
+
+Available options:
+    -s
+    -h, --help     Prints help information
+    -V, --version  Prints version information
+
+This is a footer
+
source

pub fn header<B: Into<Doc>>(self, header: B) -> Self

Set the header field

+

bpaf displays the header between the usage line and a list of the available options in --help output

+
§Combinatoric usage
+
fn options() -> OptionParser<bool>  {
+   short('s')
+       .switch()
+       .to_options()
+       .descr("This is a description")
+       .header("This is a header")
+       .footer("This is a footer")
+}
+
§Derive usage
+

bpaf_derive uses doc comments on the struct / enum to derive description, it skips single empty +lines and uses double empty lines break it into blocks. bpaf_derive would use first block as the +description, second block - header, third block - footer.

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options, version)]
+/// This is a description
+///
+///
+/// This is a header
+///
+///
+/// This is a footer
+///
+///
+/// This is just a comment
+struct Options {
+    #[bpaf(short)]
+    switch: bool
+}
+
§Example
This is a description
+
+Usage: [-s]
+
+This is a header
+
+Available options:
+    -s
+    -h, --help     Prints help information
+    -V, --version  Prints version information
+
+This is a footer
+
source

pub fn footer<M: Into<Doc>>(self, footer: M) -> Self

Set the footer field

+

bpaf displays the footer after list of the available options in --help output

+
§Combinatoric usage
+
fn options() -> OptionParser<bool>  {
+   short('s')
+       .switch()
+       .to_options()
+       .descr("This is a description")
+       .header("This is a header")
+       .footer("This is a footer")
+}
+
§Derive usage
+

bpaf_derive uses doc comments on the struct / enum to derive description, it skips single empty +lines and uses double empty lines break it into blocks. bpaf_derive would use first block as the +description, second block - header, third block - footer.

+ +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options, version)]
+/// This is a description
+///
+///
+/// This is a header
+///
+///
+/// This is a footer
+///
+///
+/// This is just a comment
+struct Options {
+    #[bpaf(short)]
+    switch: bool
+}
+
§Example
This is a description
+
+Usage: [-s]
+
+This is a header
+
+Available options:
+    -s
+    -h, --help     Prints help information
+    -V, --version  Prints version information
+
+This is a footer
+
source

pub fn usage<B>(self, usage: B) -> Self
where + B: Into<Doc>,

Set custom usage field

+

Custom usage field to use instead of one derived by bpaf.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    release: bool,
+    binary: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let release = short('r')
+        .long("release")
+        .help("Perform actions in release mode")
+        .switch();
+
+    let binary = short('b')
+        .long("binary")
+        .help("Use this binary")
+        .argument("BIN");
+
+    construct!(Options { release, binary })
+        .to_options()
+        .usage("Usage: my_program [--release] [--binary=BIN] ...")
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options, usage("Usage: my_program [--release] [--binary=BIN] ..."))]
+pub struct Options {
+    #[bpaf(short, long)]
+    /// Perform actions in release mode
+    release: bool,
+    #[bpaf(short, long, argument("BIN"))]
+    /// Use this binary
+    binary: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Method usage lets you to override the whole usage line

+
+$ app --help
+

Usage: my_program [--release] [--binary=BIN] ...

+Available options:
-r, --release
+
Perform actions in release mode
+
-b, --binary=BIN
+
Use this binary
+
-h, --help
+
Prints help information
+
+

+ +
+

It doesn’t alter parser’s behavior otherwise

+
+$ app
+Error: expected --binary=BIN, pass --help for usage information + +
+
+$ app -r --binary test
+Options { release: true, binary: "test" } +
+
source

pub fn with_usage<F>(self, f: F) -> Self
where + F: Fn(Doc) -> Doc,

Generate new usage line using automatically derived usage

+

You can customize the surroundings of the usage line while still +having part that frequently changes generated by bpaf

+ +
#[derive(Debug, Clone)]
+pub struct Options {
+    release: bool,
+    binary: String,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let release = short('r')
+        .long("release")
+        .help("Perform actions in release mode")
+        .switch();
+
+    let binary = short('b')
+        .long("binary")
+        .help("Use this binary")
+        .argument("BIN");
+
+    construct!(Options { release, binary })
+        .to_options()
+        .with_usage(|u| {
+            let mut doc = Doc::default();
+            doc.emphasis("Usage: ");
+            doc.literal("my_program");
+            doc.text(" ");
+            doc.doc(&u);
+            doc
+        })
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

with_usage lets you to place some custom text around generated usage line

+
+$ app --help
+

Usage: my_program [-r] -b=BIN

+Available options:
-r, --release
+
Perform actions in release mode
+
-b, --binary=BIN
+
Use this binary
+
-h, --help
+
Prints help information
+
+

+ +
+

It doesn’t alter parser’s behavior otherwise

+
+$ app
+Error: expected --binary=BIN, pass --help for usage information + +
+
+$ app -r --binary test
+Options { release: true, binary: "test" } +
+
+

At the moment this method is not directly supported by derive API, +but since it gives you an object of OptionParser<T> +type you can alter it using Combinatoric API:

+
#[derive(Debug, Clone, Bpaf)] {
+pub struct Options {
+    ...
+}
+
+fn my_decor(usage: Doc) -> Doc {
+    ...
+}
+
+fn main() {
+    let options = options().with_usage(my_decor).run();
+    ...
+}
+
source

pub fn check_invariants(&self, _cosmetic: bool)

Check the invariants bpaf relies on for normal operations

+

Takes a parameter whether to check for cosmetic invariants or not +(max help width exceeding 120 symbols, etc), currently not in use

+

Best used as part of your test suite:

+ +
#[test]
+fn check_options() {
+    options().check_invariants(false)
+}
+
§Panics
+

check_invariants indicates problems with panic

+
source

pub fn help_parser(self, parser: NamedArg) -> Self

Customize parser for --help

+

By default bpaf displays help when program is called with either --help or -h, you +can customize those names and description in the help message

+

Note, --help is something user expects to work

+ +
#[derive(Debug, Clone)]
+pub struct Options {
+    package: Option<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let help = long("help").short('H').help("Renders help information");
+    let version = long("version")
+        .short('v')
+        .help("Renders version information");
+    let package = short('p')
+        .help("Package to check")
+        .argument("SPEC")
+        .optional();
+
+    construct!(Options { package })
+        .to_options()
+        .descr("Command with custom flags for help and version")
+        .version("0.42")
+        .help_parser(help)
+        .version_parser(version)
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

This example replaces description and short name for --help parser. Long name works as is

+
+$ app --help
+

Command with custom flags for help and version

Usage: app [-p=SPEC]

+Available options:
-p=SPEC
+
Package to check
+
-H, --help
+
Renders help information
+
-v, --version
+
Renders version information
+
+

+ +
+

Short name is now capitalized

+
+$ app -H
+

Command with custom flags for help and version

Usage: app [-p=SPEC]

+Available options:
-p=SPEC
+
Package to check
+
-H, --help
+
Renders help information
+
-v, --version
+
Renders version information
+
+

+ +
+

and old short name no longer works.

+
+$ app -h
+Error: -h is not expected in this context + +
+

Same with --version parser - new description, original long name and custom short name are +both working

+
+$ app --version
+

Version: 0.42

+ +
+
+$ app -v
+

Version: 0.42

+ +
+
source

pub fn version_parser(self, parser: NamedArg) -> Self

Customize parser for --version

+

By default bpaf displays version information when program is called with either --version +or -V (and version is available), you can customize those names and description in the help message

+

Note, --version is something user expects to work

+ +
#[derive(Debug, Clone)]
+pub struct Options {
+    package: Option<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let help = long("help").short('H').help("Renders help information");
+    let version = long("version")
+        .short('v')
+        .help("Renders version information");
+    let package = short('p')
+        .help("Package to check")
+        .argument("SPEC")
+        .optional();
+
+    construct!(Options { package })
+        .to_options()
+        .descr("Command with custom flags for help and version")
+        .version("0.42")
+        .help_parser(help)
+        .version_parser(version)
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

This example replaces description and short name for --help parser. Long name works as is

+
+$ app --help
+

Command with custom flags for help and version

Usage: app [-p=SPEC]

+Available options:
-p=SPEC
+
Package to check
+
-H, --help
+
Renders help information
+
-v, --version
+
Renders version information
+
+

+ +
+

Short name is now capitalized

+
+$ app -H
+

Command with custom flags for help and version

Usage: app [-p=SPEC]

+Available options:
-p=SPEC
+
Package to check
+
-H, --help
+
Renders help information
+
-v, --version
+
Renders version information
+
+

+ +
+

and old short name no longer works.

+
+$ app -h
+Error: -h is not expected in this context + +
+

Same with --version parser - new description, original long name and custom short name are +both working

+
+$ app --version
+

Version: 0.42

+ +
+
+$ app -v
+

Version: 0.42

+ +
+
source

pub fn fallback_to_usage(self) -> Self

Print help if app was called with no parameters

+

By default bpaf tries to parse command line options and displays the best possible +error it can come up with. If application requires a subcommand or some argument +and user specified none - it might be a better experience for user to print +the help message.

+ +
// create option parser in a usual way, derive or combinatoric API
+let opts = options().fallback_to_usage().run();
+
source

pub fn max_width(self, width: usize) -> Self

Set the width of the help message printed to the terminal upon failure

+

By default, the help message is printed with a width of 100 characters. +This method allows to change where the help message is wrapped.

+

Setting the max width too low may negatively affect the readability of the help message. +Also, the alignment padding of broken lines is always applied.

+
source§

impl<T> OptionParser<T>

source

pub fn command(self, name: &'static str) -> ParseCommand<T>
where + T: 'static,

Parse a subcommand

+

Subcommands allow to use a totally independent parser inside a current one. Inner parser +can have its own help message, description, version and so on. You can nest them arbitrarily +too.

+
§Important restriction
+

When parsing command arguments from command lines you should have parsers for all your +named values before parsers for commands and positional items. In derive API fields parsed as +positional should be at the end of your struct/enum. Same rule applies +to parsers with positional fields or commands inside: such parsers should go to the end as well.

+

Use check_invariants in your test to ensure correctness.

+

For example for non positional non_pos and a command command parsers

+ +
let valid = construct!(non_pos(), command());
+let invalid = construct!(command(), non_pos());
+

bpaf panics during help generation unless if this restriction holds

+

You can attach a single visible short alias and multiple hiddden short and long aliases +using short and long methods.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Cmd {
+    flag: bool,
+    arg: usize,
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    flag: bool,
+    cmd: Cmd,
+}
+
+fn cmd() -> impl Parser<Cmd> {
+    let flag = long("flag")
+        .help("This flag is specific to command")
+        .switch();
+    let arg = long("arg").argument::<usize>("ARG");
+    construct!(Cmd { flag, arg })
+        .to_options()
+        .descr("Command to do something")
+        .command("cmd")
+        // you can chain add extra short and long names
+        .short('c')
+}
+
+pub fn options() -> OptionParser<Options> {
+    let flag = long("flag")
+        .help("This flag is specific to the outer layer")
+        .switch();
+    construct!(Options { flag, cmd() }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+// `command` annotation with no name gets the name from the object it is attached to,
+// but you can override it using something like #[bpaf(command("my_command"))]
+// you can chain more short and long names here to serve as aliases
+#[bpaf(command("cmd"), short('c'))]
+/// Command to do something
+pub struct Cmd {
+    /// This flag is specific to command
+    flag: bool,
+    arg: usize,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// This flag is specific to the outer layer
+    flag: bool,
+    #[bpaf(external)]
+    cmd: Cmd,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Commands show up on both outer level help

+
+$ app --help
+

Usage: app [--flag] COMMAND ...

+Available options:
--flag
+
This flag is specific to the outer layer
+
-h, --help
+
Prints help information
+
+

+Available commands:
cmd, c
+
Command to do something
+
+

+ +
+

As well as showing their own help

+
+$ app cmd --help
+

Command to do something

Usage: app cmd [--flag] --arg=ARG

+Available options:
--flag
+
This flag is specific to command
+
--arg=ARG
+
-h, --help
+
Prints help information
+
+

+ +
+

In this example there’s only one command and it is required, so is the argument inside of it

+
+$ app cmd --arg 42
+Options { flag: false, cmd: Cmd { flag: false, arg: 42 } } +
+

If you don’t specify this command - parsing will fail

+

You can have the same flag names inside and outside of the command, but it might be confusing +for the end user. This example enables the outer flag

+
+$ app --flag cmd --arg 42
+Options { flag: true, cmd: Cmd { flag: false, arg: 42 } } +
+

And this one - both inside and outside

+
+$ app --flag cmd --arg 42 --flag
+Options { flag: true, cmd: Cmd { flag: true, arg: 42 } } +
+

And that’s the confusing part - unless you add context restrictions with +adjacent and parse command first - outer flag wins. +So it’s best not to mix names on different levels

+
+$ app cmd --arg 42 --flag
+Options { flag: true, cmd: Cmd { flag: false, arg: 42 } } +
+
+

To represent multiple possible commands it is convenient to use enums

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub enum Options {
+    /// Run a binary
+    Run {
+        /// Name of a binary to run
+        bin: String,
+
+        /// Arguments to pass to a binary
+        args: Vec<String>,
+    },
+    /// Compile a binary
+    Build {
+        /// Name of a binary to build
+        bin: String,
+
+        /// Compile the binary in release mode
+        release: bool,
+    },
+}
+
+// combine mode gives more flexibility to share the same code across multiple parsers
+fn run() -> impl Parser<Options> {
+    let bin = long("bin").help("Name of a binary to run").argument("BIN");
+    let args = positional("ARG")
+        .strict()
+        .help("Arguments to pass to a binary")
+        .many();
+
+    construct!(Options::Run { bin, args })
+}
+
+pub fn options() -> OptionParser<Options> {
+    let run = run().to_options().descr("Run a binary").command("run");
+
+    let bin = long("bin")
+        .help("Name of a binary to build ")
+        .argument("BIN");
+    let release = long("release")
+        .help("Compile the binary in release mode")
+        .switch();
+    let build = construct!(Options::Build { bin, release })
+        .to_options()
+        .descr("Compile a binary")
+        .command("build");
+
+    construct!([run, build]).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub enum Options {
+    #[bpaf(command)]
+    /// Run a binary
+    Run {
+        #[bpaf(argument("BIN"))]
+        /// Name of a binary to run
+        bin: String,
+
+        #[bpaf(positional("ARG"), strict, many)]
+        /// Arguments to pass to a binary
+        args: Vec<String>,
+    },
+    #[bpaf(command)]
+    /// Compile a binary
+    Build {
+        #[bpaf(argument("BIN"))]
+        /// Name of a binary to build
+        bin: String,
+
+        /// Compile the binary in release mode
+        release: bool,
+    },
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

Help contains both commands, bpaf takes short command description from the inner command +description

+
+$ app --help
+

Usage: app COMMAND ...

+Available options:
-h, --help
+
Prints help information
+
+

+Available commands:
run
+
Run a binary
+
build
+
Compile a binary
+
+

+ +
+

Same as before each command gets its own help message

+
+$ app run --help
+

Run a binary

Usage: app run --bin=BIN -- [ARG]...

+Available positional items:
ARG
+
Arguments to pass to a binary
+
+

+Available options:
--bin=BIN
+
Name of a binary to run
+
-h, --help
+
Prints help information
+
+

+ +
+

And can be executed separately

+
+$ app run --bin basic
+Run { bin: "basic", args: [] } +
+
+$ app build --bin demo --release
+Build { bin: "demo", release: true } +
+

Auto Trait Implementations§

§

impl<T> !RefUnwindSafe for OptionParser<T>

§

impl<T> !Send for OptionParser<T>

§

impl<T> !Sync for OptionParser<T>

§

impl<T> Unpin for OptionParser<T>

§

impl<T> !UnwindSafe for OptionParser<T>

Blanket Implementations§

source§

impl<T> Any for T
where + T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where + T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

+
source§

impl<T, U> Into<U> for T
where + U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
§

impl<D> OwoColorize for D

§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where + C: Color,

Set the foreground color generically Read more
§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where + C: Color,

Set the background color generically. Read more
§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at +compile-time. If the color is constant, use either OwoColorize::fg or +a color-specific method, such as OwoColorize::green, Read more
§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where + Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at +compile-time. If the color is constant, use either OwoColorize::bg or +a color-specific method, such as OwoColorize::on_yellow, Read more
§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( + &self +) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
\ No newline at end of file diff --git a/bpaf/structs/struct.ParseCollect.html b/bpaf/structs/struct.ParseCollect.html new file mode 100644 index 00000000..5e313698 --- /dev/null +++ b/bpaf/structs/struct.ParseCollect.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/parsers/struct.ParseCollect.html...

+ + + \ No newline at end of file diff --git a/bpaf/structs/struct.ParseCon.html b/bpaf/structs/struct.ParseCon.html new file mode 100644 index 00000000..d9aa3ad5 --- /dev/null +++ b/bpaf/structs/struct.ParseCon.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/parsers/struct.ParseCon.html...

+ + + \ No newline at end of file diff --git a/bpaf/structs/struct.ParseCount.html b/bpaf/structs/struct.ParseCount.html new file mode 100644 index 00000000..53522857 --- /dev/null +++ b/bpaf/structs/struct.ParseCount.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/parsers/struct.ParseCount.html...

+ + + \ No newline at end of file diff --git a/bpaf/structs/struct.ParseFallback.html b/bpaf/structs/struct.ParseFallback.html new file mode 100644 index 00000000..cafb7da1 --- /dev/null +++ b/bpaf/structs/struct.ParseFallback.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/parsers/struct.ParseFallback.html...

+ + + \ No newline at end of file diff --git a/bpaf/structs/struct.ParseFallbackWith.html b/bpaf/structs/struct.ParseFallbackWith.html new file mode 100644 index 00000000..173f0532 --- /dev/null +++ b/bpaf/structs/struct.ParseFallbackWith.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/parsers/struct.ParseFallbackWith.html...

+ + + \ No newline at end of file diff --git a/bpaf/structs/struct.ParseLast.html b/bpaf/structs/struct.ParseLast.html new file mode 100644 index 00000000..5ba4d72a --- /dev/null +++ b/bpaf/structs/struct.ParseLast.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/parsers/struct.ParseLast.html...

+ + + \ No newline at end of file diff --git a/bpaf/structs/struct.ParseMany.html b/bpaf/structs/struct.ParseMany.html new file mode 100644 index 00000000..0875fcc6 --- /dev/null +++ b/bpaf/structs/struct.ParseMany.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/parsers/struct.ParseMany.html...

+ + + \ No newline at end of file diff --git a/bpaf/structs/struct.ParseOptional.html b/bpaf/structs/struct.ParseOptional.html new file mode 100644 index 00000000..a16b19da --- /dev/null +++ b/bpaf/structs/struct.ParseOptional.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/parsers/struct.ParseOptional.html...

+ + + \ No newline at end of file diff --git a/bpaf/structs/struct.ParseSome.html b/bpaf/structs/struct.ParseSome.html new file mode 100644 index 00000000..a5d98709 --- /dev/null +++ b/bpaf/structs/struct.ParseSome.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bpaf/parsers/struct.ParseSome.html...

+ + + \ No newline at end of file diff --git a/bpaf/trait.Parser.html b/bpaf/trait.Parser.html new file mode 100644 index 00000000..e0b91f97 --- /dev/null +++ b/bpaf/trait.Parser.html @@ -0,0 +1,2573 @@ +Parser in bpaf - Rust +

Trait bpaf::Parser

source ·
pub trait Parser<T> {
+
Show 21 methods // Provided methods + fn many(self) -> ParseMany<Self> + where Self: Sized { ... } + fn collect<C>(self) -> ParseCollect<Self, C, T> + where C: FromIterator<T>, + Self: Sized { ... } + fn some(self, message: &'static str) -> ParseSome<Self> + where Self: Sized + Parser<T> { ... } + fn optional(self) -> ParseOptional<Self> + where Self: Sized + Parser<T> { ... } + fn count(self) -> ParseCount<Self, T> + where Self: Sized + Parser<T> { ... } + fn last(self) -> ParseLast<Self> + where Self: Sized + Parser<T> { ... } + fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R> + where Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString { ... } + fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R> + where Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static { ... } + fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F> + where Self: Sized + Parser<T>, + F: Fn(&T) -> bool { ... } + fn fallback(self, value: T) -> ParseFallback<Self, T> + where Self: Sized + Parser<T> { ... } + fn fallback_with<F, E>( + self, + fallback: F + ) -> ParseFallbackWith<T, Self, F, E> + where Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString { ... } + fn hide(self) -> ParseHide<Self> + where Self: Sized + Parser<T> { ... } + fn hide_usage(self) -> ParseUsage<Self> + where Self: Sized + Parser<T> { ... } + fn custom_usage<M>(self, usage: M) -> ParseUsage<Self> + where M: Into<Doc>, + Self: Sized + Parser<T> { ... } + fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self> + where Self: Sized + Parser<T> { ... } + fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F> + where Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc { ... } + fn complete<M, F>(self, op: F) -> ParseComp<Self, F> + where M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T> { ... } + fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self> + where Self: Sized + Parser<T> { ... } + fn to_options(self) -> OptionParser<T> + where Self: Sized + Parser<T> + 'static { ... } + fn run(self) -> T + where Self: Sized + Parser<T> + 'static { ... } + fn boxed(self) -> Box<dyn Parser<T>> + where Self: Sized + Parser<T> + 'static { ... } +
}
Expand description

Simple or composed argument parser

+

§Overview

+

It’s best to think of an object implementing Parser trait as a container with a value +inside that is composable with other Parser containers using construct! and the only +way to extract this value is by transforming it to OptionParser with +to_options and running it with run. At which +point you either get your value out or bpaf would generate a message describing a problem +(missing argument, validation failure, user requested help, etc) and the program would +exit.

+

Values inside can be of any type for as long as they implement Debug, Clone and +there are no lifetimes other than static.

+

When consuming the values you can jump straight to a value that implements +FromStr trait and then transform it into something that your program would use. Alternatively, +you can consume either String or OsString and parse that by hand. It’s better to perform +as much parsing and validation inside the Parser as possible so the program itself gets +strictly typed and correct value while the user gets immediate feedback on what’s wrong with the +arguments they pass.

+

Order of operations matters, each subsequent parser gets the output of the earlier one. Both +parsers a and b would consume multiple numeric values, each less than 10, but a +validates a single value and then consumes multiple of them already validated, while b first +consumes and then performs validation. The former approach is usually more readable.

+ +
let a = short('a').argument::<usize>("N")
+    .guard(|&a| a < 10, "`a` must be below 10")
+    .many();
+let b = short('b').argument::<usize>("N")
+    .many()
+    .guard(|bs| bs.iter().all(|&b| b < 10), "`b` must be below 10");
+

The same logic applies to derive API - the current type depends on the order of annotations:

+ +
#[derive(Bpaf, Debug, Clone)]
+struct Simple {
+    #[bpaf(argument("N"), guard(less_than_10, "`a` must be below 10"), many)]
+    a: Vec<usize>,
+    #[bpaf(argument("N"), many, guard(all_less_than_10, "`b` must be below 10"))]
+    b: Vec<usize>,
+}
+

For example suppose your program needs the user to specify dimensions of a rectangle, with sides +being 1..20 units long and the total area must not exceed 200 units square. A parser that +consumes it might look like this:

+ +
#[derive(Debug, Copy, Clone)]
+struct Rectangle {
+    width: u32,
+    height: u32,
+}
+
+fn rectangle() -> impl Parser<Rectangle> {
+    let invalid_size = "Sides of a rectangle must be 1..20 units long";
+    let invalid_area = "Area of a rectangle must not exceed 200 units square";
+    let width = long("width")
+        .help("Width of the rectangle")
+        .argument::<u32>("PX")
+        .guard(|&x| 1 <= x && x <= 10, invalid_size);
+    let height = long("height")
+        .help("Height of the rectangle")
+        .argument::<u32>("PX")
+        .guard(|&x| 1 <= x && x <= 10, invalid_size);
+    construct!(Rectangle { width, height })
+        .guard(|&r| r.width * r.height <= 400, invalid_area)
+}
+

§Derive specific considerations

+

Every method defined on this trait belongs to the postprocessing section of the field +annotation. bpaf would try to figure out what chain to use for as long as there are no +options changing the type: you can use fallback, +fallback_with, guard, hide and +group_help but not the rest of them.

+ +
#[derive(Debug, Clone, Bpaf)]
+struct Options {
+    // no annotation at all - `bpaf` inserts implicit `argument` and gets the right type
+    number_1: u32,
+
+    // fallback isn't changing the type so `bpaf` still handles it
+    #[bpaf(fallback(42))]
+    number_2: u32,
+
+    // `bpaf` inserts implicit `argument`, `optional` and the right type
+    number_3: Option<u32>,
+
+    // fails to compile: you need to specify `argument`
+    // #[bpaf(optional)]
+    // number_4: Option<u32>,
+
+    #[bpaf(argument("N"), optional)]
+    number_5: Option<u32>,
+
+    // explicit consumer and a full postprocessing chain
+    #[bpaf(argument::<u32>("N"), optional)]
+    number_6: Option<u32>,
+}
+

Provided Methods§

source

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec

+

many preserves any parsing failures and propagates them outwards, with an extra +catch statement you can instead stop at the first value +that failed to parse and ignore it and all the subsequent ones.

+

many will collect at most one result that does not consume anything from the argument +list allowing using it in combination with any parsers with a fallback. After the first +one, it will keep collecting the results as long as they consume something.

+

For derive usage bpaf would insert implicit many when the resulting type is a +vector.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    argument: Vec<u32>,
+    switches: Vec<bool>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = long("argument")
+        .help("important argument")
+        .argument("ARG")
+        .many();
+    let switches = long("switch").help("some switch").switch().many();
+    construct!(Options { argument, switches }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// important argument
+    argument: Vec<u32>,
+    /// some switch
+    #[bpaf(long("switch"), switch)]
+    switches: Vec<bool>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In usage lines many items are indicated with ...

+
+$ app --help
+

Usage: app [--argument=ARG]... [--switch]...

+Available options:
--argument=ARG
+
important argument
+
--switch
+
some switch
+
-h, --help
+
Prints help information
+
+

+ +
+

Run inner parser as many times as possible collecting all the new results +First false is collected from a switch even if it is not consuming anything

+
+$ app --argument 10 --argument 20
+Options { argument: [10, 20], switches: [false] } +
+

If there’s no matching parameters - it would produce an empty vector. Note, in case of +switch parser or other parsers that can succeed without consuming anything +it would capture that value so many captures the first one of those. +You can use req_flag to avoid that.

+
+$ app
+Options { argument: [], switches: [false] } +
+

For parsers that can succeed without consuming anything such as flag or switch - many +only collects values as long as they produce something

+
+$ app --switch --switch
+Options { argument: [], switches: [true, true] } +
+
+
§See also
+

some also collects results to a vector but requires at least one +element to succeed, collect collects results into a FromIterator +structure

+
source

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser

+

A generic variant of many, instead of collecting into a vector +it collects into any collection that implements FromIterator trait

+

collect preserves any parsing failures and propagates them outwards, with extra +catch statement you can instead stop at the first value +that failed to parse and ignore it and all the subsequent ones.

+
Combinatoric example + +
use std::collections::BTreeSet;
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    argument: BTreeSet<u32>,
+    switches: BTreeSet<bool>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = long("argument")
+        .help("important argument")
+        .argument("ARG")
+        .collect();
+    let switches = long("switch").help("some switch").switch().collect();
+    construct!(Options { argument, switches }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
use std::collections::BTreeSet;
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// important argument
+    #[bpaf(argument::<u32>("ARG"), collect)]
+    argument: BTreeSet<u32>,
+    /// some switch
+    #[bpaf(long("switch"), switch, collect)]
+    switches: BTreeSet<bool>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In usage lines collect items are indicated with ...

+
+$ app --help
+

Usage: app --argument=ARG... [--switch]...

+Available options:
--argument=ARG
+
important argument
+
--switch
+
some switch
+
-h, --help
+
Prints help information
+
+

+ +
+

Run inner parser as many times as possible collecting all the new results +First false is collected from a switch even if it is not consuming anything

+
+$ app --argument 10 --argument 20 --argument 20
+Options { argument: {10, 20}, switches: {false} } +
+

If there’s no matching parameters - it would produce an empty set. Note, in case of +switch parser or other parsers that can succeed without consuming anything +it would capture that value so many captures the first one of those. +You can use req_flag to avoid that.

+
+$ app
+Options { argument: {}, switches: {false} } +
+

For parsers that can succeed without consuming anything such as flag or switch - many +only collects values as long as they produce something

+
+$ app --switch --switch
+Options { argument: {}, switches: {true} } +
+
+

collect will collect at most one result that does not consume anything from the argument +list allowing using it in combination of any parsers with a fallback. After the first one +it will keep collecting the results as long as they consume something.

+
source

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec

+

Takes a string used as an error message if there are no specified parameters

+

some preserves any parsing failures and propagates them outwards, with an extra +catch statement you can instead stop at the first value +that failed to parse and ignore it and all the subsequent ones.

+

some will collect at most one result that does not consume anything from the argument +list allowing using it in combination with any parsers with a fallback. After the first +one, it will keep collecting the results as long as they consume something.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    argument: Vec<u32>,
+    switches: Vec<bool>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = long("argument")
+        .help("important argument")
+        .argument("ARG")
+        .some("want at least one argument");
+    let switches = long("switch")
+        .help("some switch")
+        .req_flag(true)
+        .some("want at least one switch");
+    construct!(Options { argument, switches }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// important argument
+    #[bpaf(argument("ARG"), some("want at least one argument"))]
+    argument: Vec<u32>,
+    /// some switch
+    #[bpaf(long("switch"), req_flag(true), some("want at least one switch"))]
+    switches: Vec<bool>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In usage lines some items are indicated with ...

+
+$ app --help
+

Usage: app --argument=ARG... --switch...

+Available options:
--argument=ARG
+
important argument
+
--switch
+
some switch
+
-h, --help
+
Prints help information
+
+

+ +
+

Run inner parser as many times as possible collecting all the new results, but unlike +many needs to collect at least one element to succeed

+
+$ app --argument 10 --argument 20 --switch
+Options { argument: [10, 20], switches: [true] } +
+

With not enough parameters to satisfy both parsers at least once - it fails

+
+$ app
+Error: want at least one argument + +
+

both parsers need to succeed to create a struct

+
+$ app --argument 10
+Error: want at least one switch + +
+

For parsers that can succeed without consuming anything such as flag or switch - some +only collects values as long as they produce something

+
+$ app --switch --argument 10
+Options { argument: [10], switches: [true] } +
+
+
§See also
+

many also collects results to a vector but succeeds with +no matching values. collect collects results into a FromIterator +structure

+
source

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one

+

optional converts any missing items into None and passes the remaining parsing +failures untouched. With an extra catch statement, you can handle +those failures too.

+
§Derive usage
+

By default, bpaf would automatically use optional for fields of type Option<T>, +for as long as it’s not prevented from doing so by present postprocessing options. +But it’s also possible to specify it explicitly.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    version: Option<usize>,
+    feature: Option<String>,
+}
+pub fn options() -> OptionParser<Options> {
+    let version = long("version").argument("VERS").optional();
+    let feature = long("feature").argument("FEAT").optional();
+    construct!(Options { version, feature }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(argument("VERS"))]
+    version: Option<usize>,
+    #[bpaf(argument("FEAT"))]
+    feature: Option<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

bpaf encases optional arguments in usage with []

+
+$ app --help
+

Usage: app [--version=VERS] [--feature=FEAT]

+Available options:
--version=VERS
+
--feature=FEAT
+
-h, --help
+
Prints help information
+
+

+ +
+

Missing arguments are turned into None

+
+$ app
+Options { version: None, feature: None } +
+

Present values are Some

+
+$ app --version 10
+Options { version: Some(10), feature: None } +
+

As usual you can specify both

+
+$ app --version 10 --feature feat
+Options { version: Some(10), feature: Some("feat") } +
+
+
source

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number.

+

When you are dealing with a parser that can succeed without consuming +anything from a command line - bpaf will count first such success as well.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    verbosity: usize,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let verbosity = short('v')
+        .long("verbose")
+        .help("Increase the verbosity level")
+        .req_flag(())
+        .count();
+
+    construct!(Options { verbosity }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Increase the verbosity level
+    #[bpaf(short('v'), long("verbose"), req_flag(()), count)]
+    verbosity: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help message req_flag look similarly to switch and +flag

+
+$ app --help
+

Usage: app [-v]...

+Available options:
-v, --verbose
+
Increase the verbosity level
+
-h, --help
+
Prints help information
+
+

+ +
+

Since parser uses req_flag it succeeds exactly 0 times if there’s no parameters

+
+$ app
+Options { verbosity: 0 } +
+

If it was specified - count tracks it a discards parsed values

+
+$ app -vvv
+Options { verbosity: 3 } +
+
+$ app --verbose --verbose
+Options { verbosity: 2 } +
+
source

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value

+

You can use this to allow users to pick contradicting options

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub enum Style {
+    Intel,
+    Att,
+    Llvm,
+}
+
+#[derive(Debug, Clone)]
+pub enum Report {
+    /// Include defailed report
+    Detailed,
+    /// Include minimal report
+    Minimal,
+    /// No preferences
+    Undecided,
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    style: Style,
+    report: Report,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let intel = long("intel")
+        .help("Show assembly using Intel style")
+        .req_flag(Style::Intel);
+    let att = long("att")
+        .help("Show assembly using AT&T style")
+        .req_flag(Style::Att);
+    let llvm = long("llvm").help("Show llvm-ir").req_flag(Style::Llvm);
+    let style = construct!([intel, att, llvm]).last();
+
+    let detailed = long("detailed")
+        .help("Include detailed report")
+        .req_flag(Report::Detailed);
+    let minimal = long("minimal")
+        .help("Include minimal report")
+        .req_flag(Report::Minimal);
+    let report = construct!([detailed, minimal])
+        .last()
+        .fallback(Report::Undecided);
+
+    construct!(Options { style, report }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(last)]
+pub enum Style {
+    /// Show assembly using Intel style
+    Intel,
+    /// Show assembly using AT&T style
+    Att,
+    /// Show llvm-ir
+    Llvm,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(last, fallback(Report::Undecided))]
+pub enum Report {
+    /// Include detailed report
+    Detailed,
+    /// Include minimal report
+    Minimal,
+    #[bpaf(skip)]
+    /// No preferences
+    Undecided,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    // external here uses explicit reference to function `style`
+    // generated above
+    #[bpaf(external(style))]
+    style: Style,
+    // here reference is implicit and derived from field name: `report`
+    #[bpaf(external)]
+    report: Report,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In --help message last shows that inner parser can run multiple times

+
+$ app --help
+

Usage: app (--intel | --att | --llvm)... [--detailed | --minimal]...

+Available options:
--intel
+
Show assembly using Intel style
+
--att
+
Show assembly using AT&T style
+
--llvm
+
Show llvm-ir
+
--detailed
+
Include detailed report
+
--minimal
+
Include minimal report
+
-h, --help
+
Prints help information
+
+

+ +
+

style takes one of several possible values and last lets user to pass it several times

+
+$ app --intel
+Options { style: Intel, report: Undecided } +
+
+$ app --intel --att
+Options { style: Att, report: Undecided } +
+
+$ app --intel --att --intel
+Options { style: Intel, report: Undecided } +
+

same goes with report

+
+$ app --intel --detailed
+Options { style: Intel, report: Detailed } +
+
+$ app --att --detailed --minimal
+Options { style: Att, report: Minimal } +
+
source

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value

+

Transformation preserves the present/absent state of the value: to parse an optional value you +can either first try to parse it and then mark it as optional or first +deal with the optionality and then parse a value wrapped in Option. In most cases +the former approach is more concise.

+

Similarly, it is possible to parse multiple items with many or +some by either parsing a single item first and then turning it into a Vec +or collecting them into a Vec first and then parsing the whole vector. The former approach +is more concise.

+

This is a most general of transforming parsers and you can express +map and guard in terms of it.

+

Examples are a bit artificial, to parse a value from a string you can specify +the type directly in the argument’s turbofish and then apply map.

+
§Derive usage:
+

parse takes a single parameter: function name to call. Function type should match +parameter F used by parse in combinatoric API.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    number: u32,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let number = long("number")
+        .argument::<String>("N")
+        // normally you'd use argument::<u32> to get a numeric
+        // value and `map` to double it
+        .parse::<_, _, ParseIntError>(|s| Ok(u32::from_str(&s)? * 2));
+    construct!(Options { number }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
fn twice_the_num(s: String) -> Result<u32, ParseIntError> {
+    Ok(u32::from_str(&s)? * 2)
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(argument::<String>("N"), parse(twice_the_num))]
+    number: u32,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

parse don’t make any changes to generated --help message

+
+$ app --help
+

Usage: app --number=N

+Available options:
--number=N
+
-h, --help
+
Prints help information
+
+

+ +
+

You can use parse to apply arbitrary failing transformation to any input. +For example here --number takes a numerical value and doubles it

+
+$ app --number 10
+Options { number: 20 } +
+

But if function inside the parser fails - user will get the error back unless it’s handled +in some other way

+
+$ app --number ten
+Error: couldn't parse ten: invalid digit found in string + +
+
+
source

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value

+

A common case of the parse method, exists mostly for convenience.

+
§Derive usage:
+

The map takes a single parameter: function name to call. This function should transform +the value produced by the parser into a new value of the same or different type.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    number: u32,
+}
+pub fn options() -> OptionParser<Options> {
+    let number = long("number").argument::<u32>("N").map(|x| x * 2);
+    construct!(Options { number }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
fn twice_the_num(n: u32) -> u32 {
+    n * 2
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(argument::<u32>("N"), map(twice_the_num))]
+    number: u32,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

map don’t make any changes to generated --help message

+

You can use map to apply arbitrary pure transformation to any input. +Here --number takes a numerical value and doubles it

+
+$ app --number 10
+Options { number: 20 } +
+

But if function inside the parser fails - user will get the error back unless it’s handled +in some way. In fact here execution never reaches map function - +argument tries to parse ten as a number, fails and reports the error

+
+$ app --number ten
+Error: couldn't parse ten: invalid digit found in string + +
+
+
source

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message

+

If the value doesn’t satisfy the constraint - the parser fails with the specified error message.

+
§Derive usage
+

Derive variant of the guard takes a function name instead of a closure, mostly to keep things +clean. The second argument can be either a string literal or a constant name for a static str.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    number: u32,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let number = long("number").argument::<u32>("N").guard(
+        |n| *n <= 10,
+        "Values greater than 10 are only available in the DLC pack!",
+    );
+    construct!(Options { number }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
fn dlc_check(number: &u32) -> bool {
+    *number <= 10
+}
+
+const DLC_NEEDED: &str = "Values greater than 10 are only available in the DLC pack!";
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(argument("N"), guard(dlc_check, DLC_NEEDED))]
+    number: u32,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

guard don’t make any changes to generated --help message

+
+$ app --help
+

Usage: app --number=N

+Available options:
--number=N
+
-h, --help
+
Prints help information
+
+

+ +
+

You can use guard to set boundary limits or perform other checks on parsed values. +Parser accepts numbers below 10

+
+$ app --number 5
+Options { number: 5 } +
+

And fails with the error message on higher values:

+
+$ app --number 11
+Error: 11: Values greater than 10 are only available in the DLC pack! + +
+

But if function inside the parser fails - user will get the error back unless it’s handled +in some way

+
+$ app --number ten
+Error: couldn't parse ten: invalid digit found in string + +
+
+
source

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line

+

Parser would still fail if the value is present but failure comes from some transformation

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    jobs: usize,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let jobs = long("jobs")
+        .help("Number of jobs")
+        .argument("JOBS")
+        .fallback(42)
+        .display_fallback();
+    construct!(Options { jobs }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+#[allow(dead_code)]
+pub struct Options {
+    /// Number of jobs
+    #[bpaf(argument("JOBS"), fallback(42), display_fallback)]
+    jobs: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

fallback changes parser to fallback to a default value used when argument is not specified

+
+$ app
+Options { jobs: 42 } +
+

If value is present - fallback value is ignored

+
+$ app --jobs 10
+Options { jobs: 10 } +
+

Parsing errors are preserved and preserved to user

+
+$ app --jobs ten
+Error: couldn't parse ten: invalid digit found in string + +
+

With display_fallback and +debug_fallback you can make it so default value +is visible in --help output

+
+$ app --help
+

Usage: app [--jobs=JOBS]

+Available options:
--jobs=JOBS
+
Number of jobs
+
+
[default: 42]
+
-h, --help
+
Prints help information
+
+

+ +
+
+
§See also
+

fallback_with would allow to try to fallback to a value that +comes from a failing computation such as reading a file. By default fallback value will +not be shown in the --help output, you can change that by using +display_fallback and +debug_fallback.

+
source

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present

+

Would still fail if the value is present but failure comes from some earlier transformation

+
Combinatoric example + +
fn try_to_get_version() -> Result<usize, &'static str> {
+    Ok(42)
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    version: usize,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let version = long("version")
+        .help("Specify protocol version")
+        .argument("VERS")
+        .fallback_with(try_to_get_version)
+        .display_fallback();
+    construct!(Options { version }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
fn try_to_get_version() -> Result<usize, &'static str> {
+    Ok(42)
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(argument("VERS"), fallback_with(try_to_get_version), display_fallback)]
+    /// Specify protocol version
+    version: usize,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

fallback_with changes parser to fallback to a value that comes from a potentially failing +computation when argument is not specified

+
+$ app
+Options { version: 42 } +
+

If value is present - fallback value is ignored

+
+$ app --version 10
+Options { version: 10 } +
+

Parsing errors are preserved and preserved to user

+
+$ app --version ten
+Error: couldn't parse ten: invalid digit found in string + +
+

bpaf encases parsers with fallback value of some sort in usage with []

+
+$ app --help
+

Usage: app [--version=VERS]

+Available options:
--version=VERS
+
Specify protocol version
+
+
[default: 42]
+
-h, --help
+
Prints help information
+
+

+ +
+
+
§See also
+

fallback implements similar logic expect that failures aren’t expected. +By default fallback value will not be shown in the --help output, you can change that by using +display_fallback and +debug_fallback.

+
source

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation

+

Best used for optional parsers or parsers with a defined fallback, usually for implementing +backward compatibility or hidden aliases

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    argument: u32,
+    switch: bool,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = long("argument")
+        .help("important argument")
+        .argument("ARG")
+        .fallback(30);
+    let switch = long("switch").help("secret switch").switch().hide();
+    construct!(Options { argument, switch }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// important argument
+    #[bpaf(fallback(30))]
+    argument: u32,
+    /// secret switch
+    #[bpaf(hide)]
+    switch: bool,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

hide removes the inner parser from any help or autocompletion logic

+
+$ app --help
+

Usage: app [--argument=ARG]

+Available options:
--argument=ARG
+
important argument
+
-h, --help
+
Prints help information
+
+

+ +
+

But doesn’t change the parsing behavior in any way otherwise

+
+$ app --argument 32
+Options { argument: 32, switch: false } +
+
+$ app --argument 42 --switch
+Options { argument: 42, switch: true } +
+
+
source

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line

+

Parsers hidden from usage will still show up in the available arguments list. Best used on +optional things that augment the main application functionality but not define it. +Alternatively, you can use custom_usage to replace a single +option or a group of them with some other text.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    argument: u32,
+    switch: bool,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = long("argument")
+        .help("important argument")
+        .argument("ARG")
+        .fallback(30);
+    let switch = long("switch")
+        .help("not that important switch")
+        .switch()
+        .hide_usage();
+    construct!(Options { argument, switch }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[allow(dead_code)]
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// important argument
+    #[bpaf(fallback(30))]
+    argument: u32,
+    /// not that important switch
+    #[bpaf(hide_usage)]
+    switch: bool,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

hide_usage hides the inner parser from the generated usage line, but not from the rest of the help or completion

+
+$ app --help
+

Usage: app [--argument=ARG]

+Available options:
--argument=ARG
+
important argument
+
--switch
+
not that important switch
+
-h, --help
+
Prints help information
+
+

+ +
+

But doesn’t change the parsing behavior in any way otherwise

+
+$ app --argument 32
+Options { argument: 32, switch: false } +
+
+$ app --argument 32 --switch
+Options { argument: 32, switch: true } +
+
source

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line

+
Combinatoric example + +
const BINARY_USAGE: &[(&str, Style)] = &[
+    ("--binary", Style::Literal),
+    ("=", Style::Text),
+    ("BINARY", Style::Metavar),
+];
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Binary to run
+    #[bpaf(short, long, argument("BIN"), custom_usage(BINARY_USAGE))]
+    binary: Option<String>,
+
+    /// Package to check
+    #[bpaf(short, long, argument("PACKAGE"))]
+    package: Option<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    binary: Option<String>,
+    package: Option<String>,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let binary = short('b')
+        .long("binary")
+        .help("Binary to run")
+        .argument("BIN")
+        .optional()
+        .custom_usage(&[
+            ("--binary", Style::Literal),
+            ("=", Style::Text),
+            ("BINARY", Style::Metavar),
+        ]);
+
+    let package = short('p')
+        .long("package")
+        .help("Package to check")
+        .argument("PACKAGE")
+        .optional();
+
+    construct!(Options { binary, package }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

custom_usage changes how parser shows up in the “Usage” section of generated --help, note +lack of [], long name instead of a short one and different metavariable value

+
+$ app --help
+

Usage: app --binary=BINARY [-p=PACKAGE]

+Available options:
-b, --binary=BIN
+
Binary to run
+
-p, --package=PACKAGE
+
Package to check
+
-h, --help
+
Prints help information
+
+

+ +
+

Parsing behavior stays unchanged

+
+$ app --binary cargo-asm --package cargo-show-asm
+Options { binary: Some("cargo-asm"), package: Some("cargo-show-asm") } +
+
source

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser

+

bpaf inserts the group help message before the block with all the fields +from the inner parser and an empty line after the block.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Rectangle {
+    width: u32,
+    height: u32,
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    argument: u32,
+    rectangle: Rectangle,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = long("argument")
+        .help("important argument")
+        .argument("ARG")
+        .fallback(30);
+
+    let width = long("width")
+        .help("Width of the rectangle")
+        .argument("W")
+        .fallback(10);
+    let height = long("height")
+        .help("Height of the rectangle")
+        .argument("H")
+        .fallback(10);
+    let rectangle = construct!(Rectangle { width, height }).group_help("Takes a rectangle");
+
+    construct!(Options {
+        argument,
+        rectangle
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+pub struct Rectangle {
+    /// Width of the rectangle
+    #[bpaf(argument("W"), fallback(10))]
+    width: u32,
+    /// Height of the rectangle
+    #[bpaf(argument("H"), fallback(10))]
+    height: u32,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// important argument
+    #[bpaf(fallback(30))]
+    argument: u32,
+    /// secret switch
+    #[bpaf(external, group_help("Takes a rectangle"))]
+    rectangle: Rectangle,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

group_help adds extra decoration for the inner group in --help message

+
+$ app --help
+

Usage: app [--argument=ARG] [--width=W] [--height=H]

+Takes a rectangle
--width=W
+
Width of the rectangle
+
--height=H
+
Height of the rectangle
+
+

+Available options:
--argument=ARG
+
important argument
+
-h, --help
+
Prints help information
+
+

+ +
+

And doesn’t change the parsing behavior in any way

+
+$ app --argument 32 --width 20 --height 13
+Options { argument: 32, rectangle: Rectangle { width: 20, height: 13 } } +
+
source

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo

+ +
use bpaf::doc::*;
+use bpaf::*;
+#[derive(Debug, Clone)]
+pub struct Rectangle {
+    width: u32,
+    height: u32,
+}
+
+#[derive(Debug, Clone)]
+pub struct Options {
+    argument: u32,
+    rectangle: Rectangle,
+}
+
+fn generate_rectangle_help(meta: MetaInfo) -> Doc {
+    let mut buf = Doc::default();
+    buf.text("The app takes a rectangle defined by width and height\n\nYou can customize the screen size using ");
+    buf.meta(meta, true);
+    buf.text(" parameters");
+    buf
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = long("argument")
+        .help("important argument")
+        .argument("ARG")
+        .fallback(30);
+    let width = long("width")
+        .help("Width of the rectangle")
+        .argument("W")
+        .fallback(10);
+    let height = long("height")
+        .help("Height of the rectangle")
+        .argument("H")
+        .fallback(10);
+    let rectangle =
+        construct!(Rectangle { width, height }).with_group_help(generate_rectangle_help);
+
+    construct!(Options {
+        argument,
+        rectangle
+    })
+    .to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

with_group_help lets you write longer description for group of options that can also refer to +those options. Similar to group_help encased optios are separated from +the rest by a blank line.

+

Invoking help with a single --help flag renders shot(er) version of the help message +that contanis only the first paragraph for each block:

+
+$ app --help
+

Usage: app [--argument=ARG] [--width=W] [--height=H]

+The app takes a rectangle defined by width and height
You can customize the screen size using [--width=W] [--height=H] parameters
--width=W
+
Width of the rectangle
+
--height=H
+
Height of the rectangle
+
+

+Available options:
--argument=ARG
+
important argument
+
-h, --help
+
Prints help information
+
+

+ +
+

Invoking help with double --help --help flag renders the full help message with all the +descriptions added

+
+$ app --help --help
+

Usage: app [--argument=ARG] [--width=W] [--height=H]

+The app takes a rectangle defined by width and height
You can customize the screen size using [--width=W] [--height=H] parameters
--width=W
+
Width of the rectangle
+
--height=H
+
Height of the rectangle
+
+

+Available options:
--argument=ARG
+
important argument
+
-h, --help
+
Prints help information
+
+

+ +
+

Other than rendering the help message that there’s no interactions with other parsers

+
+$ app --width 120 --height 11
+Options { argument: 30, rectangle: Rectangle { width: 120, height: 11 } } +
+
+$ app --argument 12
+Options { argument: 12, rectangle: Rectangle { width: 10, height: 10 } } +
+
source

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion

+

Allows to generate autocompletion information for the shell. Completer places generated input +in place of metavar placeholders, so running completer on something that doesn’t have a +positional or an argument doesn’t make much sense.

+

Takes a function as a parameter that tries to complete partial input to a full one with an +optional description. bpaf would substitute a current positional item or an argument with an empty +string if a value isn’t available yet so it’s best to run complete where parsing can’t fail: +right after argument or positional, but this isn’t enforced.

+
§Example
$ app --name L<TAB>
+$ app --name Lupusregina _
+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    name: String,
+}
+
+fn completer(input: &String) -> Vec<(&'static str, Option<&'static str>)> {
+    let names = ["Yuri", "Lupusregina", "Solution", "Shizu", "Entoma"];
+    names
+        .iter()
+        .filter(|name| name.starts_with(input))
+        .map(|name| (*name, None))
+        .collect::<Vec<_>>()
+}
+
+pub fn options() -> OptionParser<Options> {
+    let name = short('n')
+        .long("name")
+        .help("Specify character's name")
+        .argument("NAME")
+        .complete(completer);
+    construct!(Options { name }).to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
/// suggest completions for the input
+fn completer(input: &String) -> Vec<(&'static str, Option<&'static str>)> {
+    let names = ["Yuri", "Lupusregina", "Solution", "Shizu", "Entoma"];
+    names
+        .iter()
+        .filter(|name| name.starts_with(input))
+        .map(|name| (*name, None))
+        .collect::<Vec<_>>()
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    #[bpaf(short, long, argument("NAME"), complete(completer))]
+    /// Specify character's name
+    name: String,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

complete annotation does not affect parsing results or generated help message

+
+$ app --help
+

Usage: app -n=NAME

+Available options:
-n, --name=NAME
+
Specify character's name
+
-h, --help
+
Prints help information
+
+

+ +
+
+$ app --name Bob
+Options { name: "Bob" } +
+

But when invoked with shell completion can generate suggestions for user to what to type:

+
$ app --name L<TAB>
+$ app --name Lupisregina
+
+
§A simple example
examples/simple_dynamic.rs + +
//! Simple dynamic completion example
+
+#![allow(dead_code)]
+use bpaf::*;
+
+fn crates(input: &String) -> Vec<(&'static str, Option<&'static str>)> {
+    let crates = [
+        (
+            "cargo-hackerman",
+            "Workspace hack management and package/feature query",
+        ),
+        ("cargo-prebuilt", "Download prebuilt crate binaries"),
+        ("cargo-show-asm", "Display generated assembly"),
+        (
+            "cargo-supply-chain",
+            "Gather author, contributor, publisher data on crates",
+        ),
+        ("chezmoi_modify_manager", "Chezmoi addon to patch ini files"),
+        ("xvf", "Easy archive extraction"),
+        ("newdoc", "Generate pre-populated module files"),
+        (
+            "nust64",
+            "Tools for compiling a Rust project into an N64 ROM",
+        ),
+        ("uggo", "CLI tool to query builds from u.gg"),
+    ];
+
+    crates
+        .iter()
+        .filter(|p| p.0.starts_with(input))
+        .map(|name| (name.0, Some(name.1)))
+        .collect::<Vec<_>>()
+}
+
+#[derive(Debug, Clone, Copy, Bpaf)]
+/// Format for generated report
+#[bpaf(fallback(Format::Text))]
+enum Format {
+    /// Generate report in JSON format
+    Json,
+    /// Generate report in XML format
+    Xml,
+    /// Generate report in plaintext format
+    Text,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options)]
+pub struct Options {
+    /// Select crate for analysis
+    #[bpaf(long("crate"), argument("NAME"), complete(crates))]
+    name: String,
+    /// Include dependencies into report
+    dependencies: bool,
+    #[bpaf(external)]
+    format: Format,
+    /// Upload report to a url
+    #[bpaf(positional("URL"))]
+    upload: Option<String>,
+}
+
+fn main() {
+    println!("{:?}", options().run());
+}
+
+
+
Output +

Let’s consider a simple application that performs crate analysis

+

Application generates help message as usual

+
+$ app --help
+

Usage: app --crate=NAME [--dependencies] [--json | --xml | --text] [URL]

+Format for generated report
--json
+
Generate report in JSON format
+
--xml
+
Generate report in XML format
+
--text
+
Generate report in plaintext format
+
+

+Available positional items:
URL
+
Upload report to a url
+
+

+Available options:
--crate=NAME
+
Select crate for analysis
+
--dependencies
+
Include dependencies into report
+
-h, --help
+
Prints help information
+
+

+ +
+

Shell (zsh in this case) with help of completion system can request possible items to type +along with some description

+
+% simple_dynamic \t
+% simple_dynamic
+--crate=NAME             -- Select crate for analysis
+--dependencies           -- Include dependencies into report
+URL: Upload report to a url
+Format for generated report
+--json                   -- Generate report in JSON format
+--xml                    -- Generate report in XML format
+--text                   -- Generate report in plaintext format
+
+

When user provides enough input to identify a possible item - shell substitutes it and allows +to perform more completions

+
+% simple_dynamic --j\t
+% simple_dynamic --json
+
+

Since all output format keys are mutually exclusive - with --json already present on a +command line --xml and --text won’t show up

+
+% simple_dynamic --json \t
+% simple_dynamic --json
+--crate=NAME             -- Select crate for analysis
+--dependencies           -- Include dependencies into report
+URL: Upload report to a url
+
+

With dynamic completion it is easy to provide shell with more details. For example one of the +options your application can take can be a crate name from reverse dependencies. Using +complete method you can tell bpaf what values your parser expects and bpaf would +communicate this to shell. In this example possible completions are generated by crates +function from a static list, but you can use any other source. bpaf would only call crates +function when trying to complete a crate name.

+
+% simple_dynamic --json --crate \t
+% simple_dynamic --json --crate
+NAME: Select crate for analysis
+cargo-hackerman          -- Workspace hack management and package/feature query
+cargo-prebuilt           -- Download prebuilt crate binaries
+cargo-show-asm           -- Display generated assembly
+cargo-supply-chain       -- Gather author, contributor, publisher data on crates
+chezmoi_modify_manager   -- Chezmoi addon to patch ini files
+xvf                      -- Easy archive extraction
+newdoc                   -- Generate pre-populated module files
+nust64                   -- Tools for compiling a Rust project into an N64 ROM
+uggo                     -- CLI tool to query builds from u.gg
+
+

As usual completion system uses input to filter on possible variants

+
+% simple_dynamic --json --crate cargo-\t
+% simple_dynamic --json --crate cargo-
+cargo-hackerman          -- Workspace hack management and package/feature query
+cargo-prebuilt           -- Download prebuilt crate binaries
+cargo-show-asm           -- Display generated assembly
+cargo-supply-chain       -- Gather author, contributor, publisher data on crates
+
+

And as soon as there’s enough to identify input in a unique way - shell would substitute it.

+
+% simple_dynamic --json --crate cargo-ha\t
+% simple_dynamic --json --crate cargo-hackerman
+
+

Outside of generating completion info - complete annotation does not affect the results

+
+$ app --json --crate cargo-hackerman
+Options { name: "cargo-hackerman", dependencies: false, format: Json, upload: None } +
+
+
§More detailed example
examples/derive_show_asm.rs + +
//! Parsing snippet from cargo-show-asm
+//! Derive + typed fallback + external both with and without name
+
+use bpaf::{construct, long, Bpaf, Parser, ShellComp};
+use std::{convert::Infallible, path::PathBuf};
+
+#[derive(Clone, Debug, Bpaf)]
+#[bpaf(options("asm"))] // derives cargo helper for cargo-asm
+#[allow(clippy::struct_excessive_bools)]
+pub struct Options {
+    #[bpaf(external(parse_manifest_path))]
+    pub manifest_path: PathBuf,
+    /// Custom target directory for generated artifacts
+    #[bpaf(argument("DIR"))]
+    pub target_dir: Option<PathBuf>,
+    /// Package to use if ambigous
+    #[bpaf(long, short, argument("SPEC"))]
+    pub package: Option<String>,
+    #[bpaf(external, optional)]
+    pub focus: Option<Focus>,
+    /// Produce a build plan instead of actually building
+    pub dry: bool,
+    /// Requires Cargo.lock and cache are up to date
+    pub frozen: bool,
+    /// Requires Cargo.lock is up to date
+    pub locked: bool,
+    /// Run without accessing the network
+    pub offline: bool,
+    #[bpaf(external)]
+    pub format: Format,
+    #[bpaf(external, fallback(Syntax::Intel))]
+    pub syntax: Syntax,
+    #[bpaf(external)]
+    pub selected_function: SelectedFunction,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+/// Item to pick from the output
+pub struct SelectedFunction {
+    /// Complete or partial function name to filter
+    #[bpaf(positional("FUNCTION"))]
+    pub function: Option<String>,
+    /// Select nth item from a filtered list
+    #[bpaf(positional("INDEX"), fallback(0))]
+    pub nth: usize,
+}
+
+fn parse_manifest_path() -> impl Parser<PathBuf> {
+    long("manifest-path")
+        .help("Path to Cargo.toml")
+        .argument::<PathBuf>("PATH")
+        .complete_shell(ShellComp::File {
+            mask: Some("*.toml"),
+        })
+        .parse(|p| {
+            // cargo-metadata wants to see
+            if p.is_absolute() {
+                Ok(p)
+            } else {
+                std::env::current_dir()
+                    .map(|d| d.join(p))
+                    .and_then(|full_path| full_path.canonicalize())
+            }
+        })
+        .fallback_with(|| std::env::current_dir().map(|x| x.join("Cargo.toml")))
+}
+
+#[derive(Debug, Clone, Bpaf)]
+/// How to render output
+pub struct Format {
+    /// Print interleaved Rust code
+    pub rust: bool,
+
+    #[bpaf(external(color_detection))]
+    pub color: bool,
+
+    /// include full demangled name instead of just prefix
+    pub full_name: bool,
+}
+
+#[derive(Debug, Clone, Bpaf)]
+/// Pick output type
+///
+/// included help
+///
+///
+/// Extended help
+pub enum Syntax {
+    /// Generate assembly using Intel style
+    Intel,
+    /// Generate assembly using AT&T style
+    Att,
+}
+
+fn color_detection() -> impl Parser<bool> {
+    let yes = long("color")
+        .help("Enable color highlighting")
+        .req_flag(true);
+    let no = long("no-color")
+        .help("Disable color highlighting")
+        .req_flag(false);
+    construct!([yes, no]).fallback_with::<_, Infallible>(|| {
+        // we can call for supports-color crate here
+        Ok(true)
+    })
+}
+
+fn comp_examples(prefix: &String) -> Vec<(String, Option<String>)> {
+    // in the actual app we can ask cargo-metadata for this info
+    let examples = ["derive_show_asm", "coreutils", "comonad"];
+    examples
+        .iter()
+        .filter_map(|e| {
+            if e.starts_with(prefix) {
+                Some((e.to_string(), None))
+            } else {
+                None
+            }
+        })
+        .collect()
+}
+
+#[derive(Debug, Clone, Bpaf)]
+/// Select artifact to use for analysis
+///
+/// Only one is valid
+pub enum Focus {
+    /// Show results from library code
+    Lib,
+
+    Test(
+        /// Show results from a test
+        #[bpaf(long("test"), argument("TEST"))]
+        String,
+    ),
+
+    Bench(
+        /// Show results from a benchmark
+        #[bpaf(long("bench"), argument("BENCH"))]
+        String,
+    ),
+
+    Example(
+        /// Show results from an example
+        #[bpaf(long("example"), argument("EXAMPLE"), complete(comp_examples))]
+        String,
+    ),
+
+    Bin(
+        /// Show results from a binary
+        #[bpaf(long("bin"), argument("BIN"))]
+        String,
+    ),
+}
+
+fn main() {
+    println!("{:#?}", options().run());
+}
+
+
+
Output +

Example defines this parser

+
+$ app --help
+

Usage: app [--manifest-path=PATH] [--target-dir=DIR] [-p=SPEC] [--lib | --test=TEST | --bench=BENCH | --example=EXAMPLE | --bin=BIN] [--dry] [--frozen] [--locked] [--offline] [--rust] [--color | --no-color] [--full-name] [--intel | --att] [FUNCTION] [INDEX]

+Select artifact to use for analysis
Only one is valid
--lib
+
Show results from library code
+
--test=TEST
+
Show results from a test
+
--bench=BENCH
+
Show results from a benchmark
+
--example=EXAMPLE
+
Show results from an example
+
--bin=BIN
+
Show results from a binary
+
+

+How to render output
--rust
+
Print interleaved Rust code
+
--color
+
Enable color highlighting
+
--no-color
+
Disable color highlighting
+
--full-name
+
include full demangled name instead of just prefix
+
+

+Pick output type
included help
--intel
+
Generate assembly using Intel style
+
--att
+
Generate assembly using AT&T style
+
+

+Item to pick from the output
FUNCTION
+
Complete or partial function name to filter
+
INDEX
+
Select nth item from a filtered list
+
+

+Available options:
--manifest-path=PATH
+
Path to Cargo.toml
+
--target-dir=DIR
+
Custom target directory for generated artifacts
+
-p, --package=SPEC
+
Package to use if ambigous
+
--dry
+
Produce a build plan instead of actually building
+
--frozen
+
Requires Cargo.lock and cache are up to date
+
--locked
+
Requires Cargo.lock is up to date
+
--offline
+
Run without accessing the network
+
-h, --help
+
Prints help information
+
+

+ +
+

By default completion system lists all possible cases

+
+% derive_show_asm \t
+% derive_show_asm
+--manifest-path=PATH     -- Path to Cargo.toml
+--target-dir=DIR         -- Custom target directory for generated artifacts
+--package=SPEC           -- Package to use if ambigous
+--dry                    -- Produce a build plan instead of actually building
+--frozen                 -- Requires Cargo.lock and cache are up to date
+--locked                 -- Requires Cargo.lock is up to date
+--offline                -- Run without accessing the network
+Select artifact to use for analysis
+--lib                    -- Show results from library code
+--test=TEST              -- Show results from a test
+--bench=BENCH            -- Show results from a benchmark
+--example=EXAMPLE        -- Show results from an example
+--bin=BIN                -- Show results from a binary
+How to render output
+--rust                   -- Print interleaved Rust code
+--color                  -- Enable color highlighting
+--no-color               -- Disable color highlighting
+--full-name              -- include full demangled name instead of just prefix
+Pick output type
+--intel                  -- Generate assembly using Intel style
+--att                    -- Generate assembly using AT&T style
+Item to pick from the output
+FUNCTION: Complete or partial function name to filter
+
+

But when user tries to complete example name - it only lists examples produced by +comp_examples function

+
+% derive_show_asm --example \t
+% derive_show_asm --example
+Select artifact to use for analysis
+EXAMPLE: Show results from an example
+derive_show_asm
+coreutils
+comonad
+
+

And completes the full name when user gives enough information

+
+% derive_show_asm --example cor\t
+% derive_show_asm --example coreutils
+
+
+
source

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion

+

Allows to ask existing shell completion to provide some information such as a file or +directory names or pass through existing shell completion scripts, see +ShellComp for accessible functionality

+

Places function calls in place of metavar placeholder, so running complete_shell on +something that doesn’t have a positional or argument doesn’t +make much sense.

+
§Example
$ app --output C<TAB>
+$ app --output Cargo.toml _
+
§Combinatoric usage
+
fn output() -> impl Parser<String> {
+    long("output")
+        .help("Cargo.toml file to use as output")
+        .argument("OUTPUT")
+        .complete_shell(ShellComp::File { mask: Some("*.toml") })
+}
+
§Derive usage
+
#[derive(Debug, Clone, Bpaf)]
+struct Options {
+    /// Cargo.toml file to use as output
+    #[bpaf(argument("OUTPUT"), complete_shell(ShellComp::File { mask: Some("*.toml") }))]
+    output: String,
+}
+
source

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it

+
§Derive usage
+

Add a top-level options annotation to generate OptionParser instead of default +Parser.

+

In addition to options annotation, you can also specify either version or +version(value) annotation. The former uses version from cargo, later uses the +specified value which should be an expression of type &'static str, see +version.

+
Combinatoric example + +
#[derive(Debug, Clone)]
+pub struct Options {
+    argument: u32,
+}
+
+pub fn options() -> OptionParser<Options> {
+    let argument = short('i').argument::<u32>("ARG");
+    construct!(Options { argument })
+        .to_options()
+        .version("3.1415")
+        .descr("This is a short description")
+        .header("It can contain multiple blocks, this block goes before options")
+        .footer("This one goes after")
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Derive example + +
#[derive(Debug, Clone, Bpaf)]
+#[bpaf(options, version("3.1415"))]
+/// This is a short description
+///
+///
+/// It can contain multiple blocks, this block goes before options
+///
+///
+/// This one goes after
+pub struct Options {
+    #[bpaf(short('i'))]
+    argument: u32,
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
+
Output +

In addition to all the arguments specified by user bpaf adds a few more. One of them is +--help:

+
+$ app --help
+

This is a short description

Usage: app -i=ARG

It can contain multiple blocks, this block goes before options

+Available options:
-i=ARG
+
-h, --help
+
Prints help information
+
-V, --version
+
Prints version information
+
+

This one goes after

+ +
+

The other one is --version - passing a string literal or something like +env!("CARGO_PKG_VERSION") to get version from cargo directly usually works

+
+$ app --version
+

Version: 3.1415

+ +
+

Other than that bpaf tries its best to provide a helpful error messages

+
+$ app
+Error: expected -i=ARG, pass --help for usage information + +
+

And if all parsers are satisfied run produces the result

+
+$ app -i 10
+Options { argument: 10 } +
+
+
§See also
+

There’s some methods implemented on OptionParser directly to customize the appearance

+
source

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser

+

Generally, you’d want to use Parser::to_options to finalize the parser and OptionParser::run, +but this also works for simple cases:

+ +
fn main() {
+    let name = short('n').long("name").argument::<String>("USER").run();
+    // do things with name
+}
+
source

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser

+

The boxed parser doesn’t expose internal representation in its type and allows to return +of different parsers in different conditional branches

+

You can create it with a single argument construct macro or by using boxed annotation

+ +

+pub fn options() -> OptionParser<f64> {
+    let miles = long("distance")
+        .help("distance in miles")
+        .argument::<f64>("MILES")
+        .map(|d| d * 1.609344);
+
+    let km = long("distance")
+        .help("distance in km")
+        .argument::<f64>("KM");
+
+    // suppose this is reading from config fule
+    let use_metric = true;
+
+    // without use of `boxed` here branches have different types so it won't typecheck
+    // boxed make it so branches have the same type as long as they return the same type
+    let distance = if use_metric {
+        km.boxed()
+    } else {
+        miles.boxed()
+    };
+
+    distance.to_options()
+}
+
+fn main() {
+    println!("{:?}", options().run())
+}
+
Output +

It is also possible to make dynamic choice about the parsers. This example defines two parsers +for distance - imperial and metric and picks one from some source available at runtime only.

+

Help message will contain only one parser

+
+$ app --help
+

Usage: app --distance=KM

+Available options:
--distance=KM
+
distance in km
+
-h, --help
+
Prints help information
+
+

+ +
+

and only one parser will produce a result

+
+$ app --distance 10
+10.0 +
+

Trait Implementations§

source§

impl<T> Parser<T> for Box<dyn Parser<T>>

source§

fn many(self) -> ParseMany<Self>
where + Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where + C: FromIterator<T>, + Self: Sized,

Transform parser into a collection parser Read more
source§

fn some(self, message: &'static str) -> ParseSome<Self>
where + Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
source§

fn optional(self) -> ParseOptional<Self>
where + Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
source§

fn count(self) -> ParseCount<Self, T>
where + Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
source§

fn last(self) -> ParseLast<Self>
where + Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> Result<R, E>, + E: ToString,

Apply a failing transformation to a contained value Read more
source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where + Self: Sized + Parser<T>, + F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(&T) -> bool,

Validate or fail with a message Read more
source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where + Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where + Self: Sized + Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

Use value produced by this function as default if the value isn’t present Read more
source§

fn hide(self) -> ParseHide<Self>
where + Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
source§

fn hide_usage(self) -> ParseUsage<Self>
where + Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where + M: Into<Doc>, + Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line
source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where + Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where + Self: Sized + Parser<T>, + F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
source§

fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
where + M: Into<String>, + F: Fn(&T) -> Vec<(M, Option<M>)>, + Self: Sized + Parser<T>,

Dynamic shell completion Read more
source§

fn complete_shell(self, op: ShellComp) -> ParseCompShell<Self>
where + Self: Sized + Parser<T>,

Static shell completion Read more
source§

fn to_options(self) -> OptionParser<T>
where + Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
source§

fn run(self) -> T
where + Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
source§

fn boxed(self) -> Box<dyn Parser<T>>
where + Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Implementations on Foreign Types§

source§

impl<T> Parser<T> for Box<dyn Parser<T>>

Implementors§

source§

impl<P, T> Parser<T> for ParseCompShell<P>
where + P: Parser<T> + Sized,

source§

impl<P, T> Parser<T> for ParseFallback<P, T>
where + P: Parser<T>, + T: Clone,

source§

impl<T> Parser<T> for ParseAny<T>

source§

impl<T> Parser<T> for ParseArgument<T>
where + T: FromStr + 'static, + <T as FromStr>::Err: Display,

source§

impl<T> Parser<T> for ParseCommand<T>

source§

impl<T> Parser<T> for ParsePositional<T>
where + T: FromStr + 'static, + <T as FromStr>::Err: Display,

source§

impl<T, C, P> Parser<C> for ParseCollect<P, C, T>
where + P: Parser<T>, + C: FromIterator<T>,

source§

impl<T, P> Parser<Option<T>> for ParseOptional<P>
where + P: Parser<T>,

source§

impl<T, P> Parser<usize> for ParseCount<P, T>
where + P: Parser<T>,

source§

impl<T, P> Parser<Vec<T>> for ParseMany<P>
where + P: Parser<T>,

source§

impl<T, P> Parser<Vec<T>> for ParseSome<P>
where + P: Parser<T>,

source§

impl<T, P> Parser<T> for ParseCon<P>
where + P: Fn(bool, &mut State) -> Result<T, Error>,

source§

impl<T, P> Parser<T> for ParseLast<P>
where + P: Parser<T>,

source§

impl<T, P, F, E> Parser<T> for ParseFallbackWith<T, P, F, E>
where + P: Parser<T>, + F: Fn() -> Result<T, E>, + E: ToString,

source§

impl<T: Clone + 'static> Parser<T> for ParseFlag<T>

\ No newline at end of file diff --git a/crates.js b/crates.js new file mode 100644 index 00000000..4398e7d8 --- /dev/null +++ b/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["bpaf"]; \ No newline at end of file diff --git a/help.html b/help.html new file mode 100644 index 00000000..4da619cf --- /dev/null +++ b/help.html @@ -0,0 +1,2 @@ +Help +

Rustdoc help

Back
\ No newline at end of file diff --git a/search-index.js b/search-index.js new file mode 100644 index 00000000..d1c5dbb9 --- /dev/null +++ b/search-index.js @@ -0,0 +1,5 @@ +var searchIndex = new Map(JSON.parse('[\ +["bpaf",{"doc":"Lightweight and flexible command line argument parser with …","t":"FYPPFPPFGKPGPPCHCNNNNNNNNNNHNNNNNNNNQNNNNCHNHNNNNNNNNNNNNNNNNNNNNNNNNNNHHNNNNCNCHNHHNNNNNNNNHNNNNNNNNNNNNNNNNNNNNNNNNOOOOOOCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCHHHHHPFPPPPPPPFPPGPGPPPNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNFFFFFFNNNNNNNNNNNNNNNNNNNFFFFFFFFFFFFFFFFNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN","n":["Args","Bpaf","Completion","Dir","Doc","File","Nothing","OptionParser","ParseFailure","Parser","Raw","ShellComp","Stderr","Stdout","_documentation","any","batteries","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","boxed","check_invariants","choice","clone","clone","clone_into","clone_into","collect","command","complete","complete_shell","construct","count","current_args","custom_usage","descr","doc","env","exit_code","fail","fallback","fallback_to_usage","fallback_with","fmt","fmt","footer","from","from","from","from","from","from","from","from","from","group_help","guard","header","help_parser","hide","hide_usage","into","into","into","into","last","literal","long","many","map","max_width","optional","params","parse","parsers","positional","print_mesage","pure","pure_with","render_html","render_manpage","render_markdown","run","run","run_inner","set_comp","set_name","short","some","to_options","to_owned","to_owned","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_run","type_id","type_id","type_id","type_id","unwrap_stderr","unwrap_stdout","usage","version","version_parser","with_group_help","with_usage","bash","elvish","fish","mask","mask","zsh","_0_intro","_1_tutorials","_2_howto","_3_cookbook","_4_explanation","_0_types_of_arguments","_1_combinatoric_api","_2_derive_api","_3_picking_type","_0_switch","_1_argument","_2_positional","_3_command","_4_exotic","_0_simple_parser","_1_chaining","_2_combining","_3_subcommands","_4_decorating","_0_switch","_1_argument","_2_positional","_0_intro","_1_custom_names","_2_custom_consumers","_3_postpr","_4_enums_and_structs","_5_generate","_6_nesting","_7_commands","_8_cargo","_0_testing","_1_completion","_00_find","_01_dd","_02_xorg","_03_command_chaining","_04_multi_value","_05_struct_groups","_06_multi_flag","_07_skip_positional","_08_cargo_helper","_09_numeric_flags","cargo_helper","get_usage","toggle_flag","verbose_and_quiet_by_number","verbose_by_slice","Custom","Doc","Emphasis","FileFormat","Game","General","Invalid","LibraryFunction","Literal","MetaInfo","Metavar","Misc","Section","SpecialFile","Style","Sysadmin","SystemCall","Text","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","default","doc","em_doc","emphasis","eq","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","into","into","into","into","invalid","literal","meta","monochrome","render_markdown","text","to_owned","to_owned","to_owned","to_owned","to_string","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","NamedArg","ParseAny","ParseArgument","ParseCommand","ParseFlag","ParsePositional","adjacent","adjacent","anywhere","argument","env","flag","help","help","help","help","help","long","long","metavar","req_flag","short","short","strict","switch","NamedArg","ParseAny","ParseArgument","ParseCollect","ParseCommand","ParseCompShell","ParseCon","ParseCount","ParseFallback","ParseFallbackWith","ParseFlag","ParseLast","ParseMany","ParseOptional","ParsePositional","ParseSome","adjacent","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","catch","catch","catch","catch","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","debug_fallback","debug_fallback","display_fallback","display_fallback","failfast","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","help","inner","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","meta","to_owned","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id"],"q":[[0,"bpaf"],[117,"bpaf::ShellComp"],[123,"bpaf::_documentation"],[128,"bpaf::_documentation::_1_tutorials"],[132,"bpaf::_documentation::_1_tutorials::_0_types_of_arguments"],[137,"bpaf::_documentation::_1_tutorials::_1_combinatoric_api"],[142,"bpaf::_documentation::_1_tutorials::_1_combinatoric_api::_0_simple_parser"],[145,"bpaf::_documentation::_1_tutorials::_2_derive_api"],[154,"bpaf::_documentation::_2_howto"],[156,"bpaf::_documentation::_3_cookbook"],[166,"bpaf::batteries"],[171,"bpaf::doc"],[248,"bpaf::params"],[273,"bpaf::parsers"],[427,"core::str::traits"],[428,"core::option"],[429,"core::ops::function"],[430,"alloc::boxed"],[431,"core::iter::traits::collect"],[432,"core::iter::traits::collect"],[433,"core::convert"],[434,"alloc::vec"],[435,"alloc::string"],[436,"core::fmt"],[437,"core::fmt"],[438,"std::ffi::os_str"],[439,"core::fmt"],[440,"core::clone"],[441,"core::fmt"]],"d":["All currently present command line parameters with some …","Derive macro for bpaf command line parser","This also goes to stdout with exit code of 0, this cannot …","Similar to File but limited to directories only For bash …","String with styled segments.","A file or directory name with an optional file mask.","Don’t produce anything at all from this parser - can be …","Ready to run Parser with additional information attached","Unsuccessful command line parsing outcome, use it for unit …","Simple or composed argument parser","You can also specify a raw value to use for each supported …","Shell specific completion","Print this to stderr and exit with failure code","Print this to stdout and exit with success code","Project documentation","Parse a single arbitrary item from a command line","Batteries included - helpful parsers that use only public …","","","","","","","","","Create a boxed representation for a parser","Check the invariants bpaf relies on for normal operations","Choose between several parsers specified at runtime","","","","","Transform parser into a collection parser","Parse a subcommand","Dynamic shell completion","Static shell completion","Compose several parsers to produce a single result","Count how many times the inner parser succeeds, and return …","Get a list of command line arguments from OS","Customize how this parser looks like in the usage line","Set the description field","Documentation generation system","Parse an environment variable","Returns the exit code for the failure","Fail with a fixed error message","Use this value as default if the value isn’t present on …","Print help if app was called with no parameters","Use value produced by this function as default if the …","","","Set the footer field","Returns the argument unchanged.","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Attach a help message to a complex parser","Validate or fail with a message","Set the header field","Customize parser for --help","Ignore this parser during any sort of help generation","Ignore this parser when generating a usage line","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Apply the inner parser as many times as it succeeds, …","A specialized version of any that consumes an arbitrary …","Parse a flag/switch/argument that has a long name","Consume zero or more items from a command line and collect …","Apply a pure transformation to a contained value","Set the width of the help message printed to the terminal …","Turn a required argument into an optional one","Tools to define primitive parsers","Apply a failing transformation to a contained value","This module exposes parsers that accept further …","Parse a positional argument","Prints a message to stdout or stderr appropriate to the …","Parser that produces a fixed value","Wrap a calculated value into a Parser","Render command line documentation for the app into …","Render command line documentation for the app into a …","Render command line documentation for the app into Markdown","Execute the OptionParser, extract a parsed value or print …","Finalize and run the parser","Execute the OptionParser and produce a values for unit …","Enable completions with custom output revision style","Add an application name for args created from custom input","Parse a flag/switch/argument that has a short name","Consume one or more items from a command line and collect …","Transform Parser into OptionParser to get ready to run it","","","","","","","","","","","Execute the OptionParser, extract a parsed value or return …","","","","","Returns the contained stderr values - for unit tests","Returns the contained stdout values - for unit tests","Set custom usage field","Set the version field.","Customize parser for --version","Make a help message for a complex parser from its MetaInfo","Generate new usage line using automatically derived usage","This raw string will be used for bash shell …","This raw string will be used for elvish shell …","This raw string will be used for fish shell …","Optional filemask to use, no spaces, no tabs","Optional filemask to use, no spaces, no tabs","This raw string will be used for zsh shell …"," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," ","Strip a command name if present at the front when used as …","Get usage for a parser","Pick last passed value between two different flags","--verbose and --quiet flags with results encoded as number","--verbose and --quiet flags with results choosen from a …","Custom section","String with styled segments.","Word with emphasis - things like “Usage”, “Available …","File formats and conventions","Games and screensavers","General commands","Invalid input given by user - used to display invalid …","Library functions such as C standard library functions","Something user needs to type literally - command names, etc","Parser metainformation","Metavavar placeholder - something user needs to replace …","Miscellaneous","Manual page section","Special files (usually devices in /dev) and drivers","Style of a text fragment inside of Doc","System administration commands and daemons","System calls","Plain text, no decorations","","","","","","","","","","","","","","","","","","Append a Doc to Doc","Append a Doc to Doc for plaintext documents try to format …","Append a fragment of text with emphasis to Doc","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","Returns the argument unchanged.","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Append a fragment of unexpected user input to Doc","Append a fragment of literal text to Doc","Append a fragment of parser metadata to Doc","Render a monochrome version of the document","Render doc into markdown document, used by documentation …","Append a fragment of plain text to Doc","","","","","","","","","","","","","","","","","","A named thing used to create flag, switch or argument","Consume an arbitrary value that satisfies a condition, …","Parser for a named argument, created with argument.","Builder structure for the command","Parser for a named switch, created with NamedArg::flag or …","Parse a positional item, created with positional","Allow for the command to succeed even if there are non …","Restrict parsed arguments to have both flag and a value in …","Try to apply the parser to each unconsumed element instead …","Argument","Environment variable fallback","Flag with custom present/absent values","Add a brief description to a command","Add a help message to any parser. See examples in any","Add a help message to a flag/switch/argument","Add a help message to flag","Add a help message to a positional parser","Add a custom hidden long alias for a command","Add a long name to a flag/switch/argument","Replace metavar with a custom value See examples in any","Required flag with custom value","Add a custom short alias for a command","Add a short name to a flag/switch/argument","Changes positional parser to be a “strict” positional","Simple boolean flag","A named thing used to create flag, switch or argument","Consume an arbitrary value that satisfies a condition, …","Parser for a named argument, created with argument.","Apply inner parser several times and collect results into …","Builder structure for the command","Parser that inserts static shell completion into bpaf’s …","Create parser from a function, construct! uses it …","Apply inner parser as many times as it succeeds while …","Parser that substitutes missing value but not parse …","Parser that substitutes missing value with a function …","Parser for a named switch, created with NamedArg::flag or …","Apply inner parser as many times as it succeeds while …","Apply inner parser several times and collect results into …","Apply inner parser, return a value in Some if items …","Parse a positional item, created with positional","Apply inner parser several times and collect results into …","Automagically restrict the inner parser scope to accept …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Handle parse failures","Handle parse failures","Handle parse failures for optional parsers","Handle parse failures","","","","","","","","","Show fallback_with value in --help using Debug …","Show fallback value in --help using Debug representation","Show fallback_with value in --help using Display …","Show fallback value in --help using Display representation","To produce a better error messages while parsing …","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Add a help message to an argument","inner parser closure","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","metas for inner parsers","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"i":[0,0,15,14,0,14,14,0,0,0,14,0,15,15,0,0,0,25,9,14,15,25,9,14,15,7,9,0,14,15,14,15,7,9,7,7,0,7,25,7,9,0,0,15,0,7,9,7,14,15,9,25,25,25,25,25,25,9,14,15,7,7,9,9,7,7,25,9,14,15,7,0,0,7,7,9,7,0,7,0,0,15,0,0,9,9,9,9,7,9,25,25,0,7,7,14,15,25,9,14,15,25,9,14,15,9,25,9,14,15,15,15,9,9,9,7,9,59,59,59,60,61,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,0,53,44,44,44,53,44,53,0,53,44,0,44,0,44,44,53,44,49,53,26,44,49,53,26,44,49,53,26,44,49,53,26,26,26,26,26,53,44,53,26,26,44,49,53,26,26,26,26,44,49,53,26,26,26,26,26,26,26,44,49,53,26,26,44,49,53,26,44,49,53,26,44,49,53,26,0,0,0,0,0,0,18,54,2,27,27,27,18,2,27,55,43,18,27,2,27,18,27,43,27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,57,23,18,2,30,47,16,29,24,39,42,40,57,27,55,54,43,23,18,2,30,47,16,29,24,39,42,40,57,27,55,54,43,47,16,42,40,27,55,54,43,27,55,54,43,30,29,30,29,57,27,23,18,2,30,47,16,29,24,39,42,40,57,27,55,54,43,54,57,23,18,2,30,47,16,29,24,39,42,40,57,27,55,54,43,57,27,55,54,43,23,18,2,30,47,16,29,24,39,42,40,57,27,55,54,43,23,18,2,30,47,16,29,24,39,42,40,57,27,55,54,43,23,18,2,30,47,16,29,24,39,42,40,57,27,55,54,43],"f":"```````````````{{bg}{{d{e}}}f{}{{l{c}{{h{{j{e}}}}}}}}`{ce{}{}}0000000{n{{A`{n}}}}{{{Ab{c}}Ad}Af{}}{c{{`{{n{e}}}}}{{Aj{}{{Ah{{A`{n}}}}}}}{}}{AlAl}{AnAn}{{ce}Af{}{}}0{n{{B`{nec}}}{}{{Bb{c}}}}{{{Ab{c}}b}{{Bd{c}}}{}}{{ng}{{`{ng}}}{}{{Bh{Bf}}}{{l{c}{{h{{Bl{{Bj{e{j{e}}}}}}}}}}}}{{nAl}{{Bn{n}}}}`{n{{C`{nc}}}{}}{{}Cb}{{nc}{{`{n}}}{{Bh{Cd}}}}{{{Ab{c}}e}{{Ab{c}}}{}{{Bh{Cd}}}}`{bCf}{AnCh}{b{{`{c}}}{}}{{nc}{{Cj{nc}}}{}}{{{Ab{c}}}{{Ab{c}}}{}}{{ng}{{Cl{cnge}}}{}Cn{{l{}{{h{{D`{ce}}}}}}}}{{AlDb}Dd}{{AnDb}Dd}8{cc{}}{{{Df{b}}}Cb}{{{Dj{Dh}}}Cb}{{{Dj{b}}}Cb}{{{Dj{Bf}}}Cb}{{{Dj{Dl}}}Cb}555?{{neb}{{`{ne}}}{}{{l{c}{{h{Ad}}}}}}?{{{Ab{c}}Cf}{{Ab{c}}}{}}{n{{`{n}}}}0{ce{}{}}000{n{{Dn{n}}}}{b{{d{Af}}}}{bCf}{n{{E`{n}}}}{{ng}{{`{cnge}}}{}{}{{l{c}{{h{e}}}}}}{{{Ab{c}}Eb}{{Ab{c}}}{}}{n{{Ed{n}}}}`{{ni}{{`{cnige}}}{}{}Cn{{l{c}{{h{{D`{eg}}}}}}}}`{b{{Ef{c}}}{}}{{AnEb}Af}{c{{`{c}}}{}}{g{{`{cge}}}{}Cn{{l{}{{h{{D`{ce}}}}}}}}{{{Ab{c}}e}Bf{}{{Bh{Bf}}}}{{{Ab{c}}eEh{j{b}}{j{b}}{j{b}}}Bf{}{{Ej{b}}}}1{{{Ab{c}}}c{}}{nc{}}{{{Ab{c}}e}{{D`{cAn}}}{}{{Bh{Cb}}}}{{CbEb}Cb}{{Cbb}Cb}{ElCf}{{nb}{{En{n}}}}{n{{Ab{c}}}{}}{ce{}{}}0{c{{D`{e}}}{}{}}0000000{{{Ab{c}}}{{D`{cAn}}}{}}{cF`{}}000{AnBf}0{{{Ab{c}}e}{{Ab{c}}}{}{{Bh{Cd}}}}0{{{Ab{c}}Cf}{{Ab{c}}}{}}{{nc}{{`{nc}}}{{l{Fb}{{h{Cd}}}}}}{{{Ab{c}}e}{{Ab{c}}}{}{{l{Cd}{{h{Cd}}}}}}`````````````````````````````````````````````````{{be}{{`{{n{c}}}}}{}{{n{c}}}}{{{Ab{c}}}BfFd}{{CfcCfc}{{`{{n{{j{c}}}}}}}Ff}{{FhFhFh}{{`{{n{Fh}}}}}}{{Eb{Df{c}}}{{`{{n{c}}}}}Ff}``````````````````========{EhEh}{FbFb}{FjFj}{CdCd}{{ce}Af{}{}}000{{}Cd}{{CdCd}Af}0{{Cdb}Af}{{FjFj}Ad}{{EhDb}Dd}{{FjDb}Dd}{{CdDb}Dd}0{cc{}}00{{{Df{{Bj{bFj}}}}}Cd}1{bCd}{{{Dj{{Bj{bFj}}}}}Cd}{ce{}{}}00099{{CdFbAd}Af}{{CdAd}Bf}0;2222{cBf{}}{c{{D`{e}}}{}{}}0000000{cF`{}}000``````{{{Bd{c}}}{{Bd{c}}}{}}{{{Fl{c}}}{{Fl{c}}}{}}{{{d{c}}}{{d{c}}}{}}{{Cfb}{{Fl{c}}}f}{{Cfb}Cf}{{Cfcc}{{Fn{c}}}G`}{{{Bd{c}}e}{{Bd{c}}}{}{{Bh{Cd}}}}{{{d{c}}e}{{d{c}}}{}{{Bh{Cd}}}}{{Cfc}Cf{{Bh{Cd}}}}{{{Fn{c}}e}{{Fn{c}}}{}{{Bh{Cd}}}}{{{Ef{c}}e}{{Ef{c}}}{}{{Bh{Cd}}}}{{{Bd{c}}b}{{Bd{c}}}{}}74{{Cfc}{{`{{n{c}}}}}G`}{{{Bd{c}}El}{{Bd{c}}}{}}{{CfEl}Cf}{{{Ef{c}}}{{Ef{c}}}{}}{Cf{{Fn{Ad}}}}````````````````{{{Gb{c}}}{{`{{Gb{c}}}}}{}}{ce{}{}}0000000000000000000000000000000{{{En{c}}}{{En{c}}}{}}{{{B`{ceg}}}{{B`{ceg}}}{}{}{}}{{{Ed{c}}}{{Ed{c}}}{}}{{{E`{c}}}{{E`{c}}}{}}{CfCf}{{{Fn{c}}}{{Fn{c}}}G`}{{{Fl{c}}}{{Fl{c}}}G`}{{{Ef{c}}}{{Ef{c}}}G`}{{ce}Af{}{}}000{{{Cl{ceig}}}{{Cl{ceig}}}Fd{}{}{{l{}{{h{{D`{cg}}}}}}}}{{{Cj{ce}}}{{Cj{ce}}}{}Fd}{{{Cl{ceig}}}{{Cl{ceig}}}Gd{}{}{{l{}{{h{{D`{cg}}}}}}}}{{{Cj{ce}}}{{Cj{ce}}}{}Gd}`{{CfDb}Dd}{cc{}}000000000000000{{{Fl{c}}e}{{Fl{c}}}{}{{Bh{Cd}}}}`{ce{}{}}000000000000000`0000{c{{D`{e}}}{}{}}0000000000000000000000000000000{cF`{}}000000000000000","c":[105],"p":[[1,"str"],[5,"ParseAny",273],[10,"FromStr",427],[17,"Output"],[6,"Option",428],[10,"Fn",429],[10,"Parser",0],[5,"Box",430],[5,"OptionParser",0],[1,"bool"],[1,"unit"],[17,"Item"],[10,"IntoIterator",431],[6,"ShellComp",0],[6,"ParseFailure",0],[5,"ParseCollect",273],[10,"FromIterator",431],[5,"ParseCommand",273],[5,"String",432],[10,"Into",433],[1,"tuple"],[5,"Vec",434],[5,"ParseCompShell",273],[5,"ParseCount",273],[5,"Args",0],[5,"Doc",171],[5,"NamedArg",273],[1,"i32"],[5,"ParseFallback",273],[5,"ParseFallbackWith",273],[10,"ToString",432],[6,"Result",435],[5,"Formatter",436],[8,"Result",436],[1,"array"],[5,"OsStr",437],[1,"slice"],[5,"OsString",437],[5,"ParseLast",273],[5,"ParseMany",273],[1,"usize"],[5,"ParseOptional",273],[5,"ParsePositional",273],[6,"Section",171],[10,"AsRef",433],[1,"char"],[5,"ParseSome",273],[5,"TypeId",438],[5,"MetaInfo",171],[10,"Debug",436],[10,"Copy",439],[1,"isize"],[6,"Style",171],[5,"ParseArgument",273],[5,"ParseFlag",273],[10,"Clone",440],[5,"ParseCon",273],[10,"Display",436],[15,"Raw",117],[15,"File",117],[15,"Dir",117]],"b":[[52,"impl-From%3C%26%5B%26str;+N%5D%3E-for-Args%3C\'_%3E"],[53,"impl-From%3C%26%5B%26OsStr%5D%3E-for-Args%3C\'a%3E"],[54,"impl-From%3C%26%5B%26str%5D%3E-for-Args%3C\'a%3E"],[55,"impl-From%3C%26%5BString%5D%3E-for-Args%3C\'a%3E"],[56,"impl-From%3C%26%5BOsString%5D%3E-for-Args%3C\'a%3E"],[212,"impl-Display-for-Doc"],[213,"impl-Debug-for-Doc"],[217,"impl-From%3C%26%5B(%26str,+Style);+N%5D%3E-for-Doc"],[219,"impl-From%3C%26str%3E-for-Doc"],[220,"impl-From%3C%26%5B(%26str,+Style)%5D%3E-for-Doc"]]}]\ +]')); +if (typeof exports !== 'undefined') exports.searchIndex = searchIndex; +else if (window.initSearch) window.initSearch(searchIndex); diff --git a/settings.html b/settings.html new file mode 100644 index 00000000..a685b1da --- /dev/null +++ b/settings.html @@ -0,0 +1,2 @@ +Settings +

Rustdoc settings

Back
\ No newline at end of file diff --git a/src-files.js b/src-files.js new file mode 100644 index 00000000..40a23aef --- /dev/null +++ b/src-files.js @@ -0,0 +1,4 @@ +var srcIndex = new Map(JSON.parse('[\ +["bpaf",["",[["buffer",[["manpage",[],["escape.rs","monoid.rs","roff.rs"]]],["console.rs","html.rs","manpage.rs","splitter.rs"]]],["_documentation.rs","arg.rs","args.rs","batteries.rs","buffer.rs","complete_gen.rs","complete_run.rs","complete_shell.rs","doc.rs","error.rs","from_os_str.rs","info.rs","item.rs","lib.rs","meta.rs","meta_help.rs","meta_youmean.rs","params.rs","structs.rs"]]]\ +]')); +createSrcSidebar(); diff --git a/src/bpaf/_documentation.rs.html b/src/bpaf/_documentation.rs.html new file mode 100644 index 00000000..698549c5 --- /dev/null +++ b/src/bpaf/_documentation.rs.html @@ -0,0 +1,6403 @@ +_documentation.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+1988
+1989
+1990
+1991
+1992
+1993
+1994
+1995
+1996
+1997
+1998
+1999
+2000
+2001
+2002
+2003
+2004
+2005
+2006
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+2017
+2018
+2019
+2020
+2021
+2022
+2023
+2024
+2025
+2026
+2027
+2028
+2029
+2030
+2031
+2032
+2033
+2034
+2035
+2036
+2037
+2038
+2039
+2040
+2041
+2042
+2043
+2044
+2045
+2046
+2047
+2048
+2049
+2050
+2051
+2052
+2053
+2054
+2055
+2056
+2057
+2058
+2059
+2060
+2061
+2062
+2063
+2064
+2065
+2066
+2067
+2068
+2069
+2070
+2071
+2072
+2073
+2074
+2075
+2076
+2077
+2078
+2079
+2080
+2081
+2082
+2083
+2084
+2085
+2086
+2087
+2088
+2089
+2090
+2091
+2092
+2093
+2094
+2095
+2096
+2097
+2098
+2099
+2100
+2101
+2102
+2103
+2104
+2105
+2106
+2107
+2108
+2109
+2110
+2111
+2112
+2113
+2114
+2115
+2116
+2117
+2118
+2119
+2120
+2121
+2122
+2123
+2124
+2125
+2126
+2127
+2128
+2129
+2130
+2131
+2132
+2133
+2134
+2135
+2136
+2137
+2138
+2139
+2140
+2141
+2142
+2143
+2144
+2145
+2146
+2147
+2148
+2149
+2150
+2151
+2152
+2153
+2154
+2155
+2156
+2157
+2158
+2159
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2180
+2181
+2182
+2183
+2184
+2185
+2186
+2187
+2188
+2189
+2190
+2191
+2192
+2193
+2194
+2195
+2196
+2197
+2198
+2199
+2200
+2201
+2202
+2203
+2204
+2205
+2206
+2207
+2208
+2209
+2210
+2211
+2212
+2213
+2214
+2215
+2216
+2217
+2218
+2219
+2220
+2221
+2222
+2223
+2224
+2225
+2226
+2227
+2228
+2229
+2230
+2231
+2232
+2233
+2234
+2235
+2236
+2237
+2238
+2239
+2240
+2241
+2242
+2243
+2244
+2245
+2246
+2247
+2248
+2249
+2250
+2251
+2252
+2253
+2254
+2255
+2256
+2257
+2258
+2259
+2260
+2261
+2262
+2263
+2264
+2265
+2266
+2267
+2268
+2269
+2270
+2271
+2272
+2273
+2274
+2275
+2276
+2277
+2278
+2279
+2280
+2281
+2282
+2283
+2284
+2285
+2286
+2287
+2288
+2289
+2290
+2291
+2292
+2293
+2294
+2295
+2296
+2297
+2298
+2299
+2300
+2301
+2302
+2303
+2304
+2305
+2306
+2307
+2308
+2309
+2310
+2311
+2312
+2313
+2314
+2315
+2316
+2317
+2318
+2319
+2320
+2321
+2322
+2323
+2324
+2325
+2326
+2327
+2328
+2329
+2330
+2331
+2332
+2333
+2334
+2335
+2336
+2337
+2338
+2339
+2340
+2341
+2342
+2343
+2344
+2345
+2346
+2347
+2348
+2349
+2350
+2351
+2352
+2353
+2354
+2355
+2356
+2357
+2358
+2359
+2360
+2361
+2362
+2363
+2364
+2365
+2366
+2367
+2368
+2369
+2370
+2371
+2372
+2373
+2374
+2375
+2376
+2377
+2378
+2379
+2380
+2381
+2382
+2383
+2384
+2385
+2386
+2387
+2388
+2389
+2390
+2391
+2392
+2393
+2394
+2395
+2396
+2397
+2398
+2399
+2400
+2401
+2402
+2403
+2404
+2405
+2406
+2407
+2408
+2409
+2410
+2411
+2412
+2413
+2414
+2415
+2416
+2417
+2418
+2419
+2420
+2421
+2422
+2423
+2424
+2425
+2426
+2427
+2428
+2429
+2430
+2431
+2432
+2433
+2434
+2435
+2436
+2437
+2438
+2439
+2440
+2441
+2442
+2443
+2444
+2445
+2446
+2447
+2448
+2449
+2450
+2451
+2452
+2453
+2454
+2455
+2456
+2457
+2458
+2459
+2460
+2461
+2462
+2463
+2464
+2465
+2466
+2467
+2468
+2469
+2470
+2471
+2472
+2473
+2474
+2475
+2476
+2477
+2478
+2479
+2480
+2481
+2482
+2483
+2484
+2485
+2486
+2487
+2488
+2489
+2490
+2491
+2492
+2493
+2494
+2495
+2496
+2497
+2498
+2499
+2500
+2501
+2502
+2503
+2504
+2505
+2506
+2507
+2508
+2509
+2510
+2511
+2512
+2513
+2514
+2515
+2516
+2517
+2518
+2519
+2520
+2521
+2522
+2523
+2524
+2525
+2526
+2527
+2528
+2529
+2530
+2531
+2532
+2533
+2534
+2535
+2536
+2537
+2538
+2539
+2540
+2541
+2542
+2543
+2544
+2545
+2546
+2547
+2548
+2549
+2550
+2551
+2552
+2553
+2554
+2555
+2556
+2557
+2558
+2559
+2560
+2561
+2562
+2563
+2564
+2565
+2566
+2567
+2568
+2569
+2570
+2571
+2572
+2573
+2574
+2575
+2576
+2577
+2578
+2579
+2580
+2581
+2582
+2583
+2584
+2585
+2586
+2587
+2588
+2589
+2590
+2591
+2592
+2593
+2594
+2595
+2596
+2597
+2598
+2599
+2600
+2601
+2602
+2603
+2604
+2605
+2606
+2607
+2608
+2609
+2610
+2611
+2612
+2613
+2614
+2615
+2616
+2617
+2618
+2619
+2620
+2621
+2622
+2623
+2624
+2625
+2626
+2627
+2628
+2629
+2630
+2631
+2632
+2633
+2634
+2635
+2636
+2637
+2638
+2639
+2640
+2641
+2642
+2643
+2644
+2645
+2646
+2647
+2648
+2649
+2650
+2651
+2652
+2653
+2654
+2655
+2656
+2657
+2658
+2659
+2660
+2661
+2662
+2663
+2664
+2665
+2666
+2667
+2668
+2669
+2670
+2671
+2672
+2673
+2674
+2675
+2676
+2677
+2678
+2679
+2680
+2681
+2682
+2683
+2684
+2685
+2686
+2687
+2688
+2689
+2690
+2691
+2692
+2693
+2694
+2695
+2696
+2697
+2698
+2699
+2700
+2701
+2702
+2703
+2704
+2705
+2706
+2707
+2708
+2709
+2710
+2711
+2712
+2713
+2714
+2715
+2716
+2717
+2718
+2719
+2720
+2721
+2722
+2723
+2724
+2725
+2726
+2727
+2728
+2729
+2730
+2731
+2732
+2733
+2734
+2735
+2736
+2737
+2738
+2739
+2740
+2741
+2742
+2743
+2744
+2745
+2746
+2747
+2748
+2749
+2750
+2751
+2752
+2753
+2754
+2755
+2756
+2757
+2758
+2759
+2760
+2761
+2762
+2763
+2764
+2765
+2766
+2767
+2768
+2769
+2770
+2771
+2772
+2773
+2774
+2775
+2776
+2777
+2778
+2779
+2780
+2781
+2782
+2783
+2784
+2785
+2786
+2787
+2788
+2789
+2790
+2791
+2792
+2793
+2794
+2795
+2796
+2797
+2798
+2799
+2800
+2801
+2802
+2803
+2804
+2805
+2806
+2807
+2808
+2809
+2810
+2811
+2812
+2813
+2814
+2815
+2816
+2817
+2818
+2819
+2820
+2821
+2822
+2823
+2824
+2825
+2826
+2827
+2828
+2829
+2830
+2831
+2832
+2833
+2834
+2835
+2836
+2837
+2838
+2839
+2840
+2841
+2842
+2843
+2844
+2845
+2846
+2847
+2848
+2849
+2850
+2851
+2852
+2853
+2854
+2855
+2856
+2857
+2858
+2859
+2860
+2861
+2862
+2863
+2864
+2865
+2866
+2867
+2868
+2869
+2870
+2871
+2872
+2873
+2874
+2875
+2876
+2877
+2878
+2879
+2880
+2881
+2882
+2883
+2884
+2885
+2886
+2887
+2888
+2889
+2890
+2891
+2892
+2893
+2894
+2895
+2896
+2897
+2898
+2899
+2900
+2901
+2902
+2903
+2904
+2905
+2906
+2907
+2908
+2909
+2910
+2911
+2912
+2913
+2914
+2915
+2916
+2917
+2918
+2919
+2920
+2921
+2922
+2923
+2924
+2925
+2926
+2927
+2928
+2929
+2930
+2931
+2932
+2933
+2934
+2935
+2936
+2937
+2938
+2939
+2940
+2941
+2942
+2943
+2944
+2945
+2946
+2947
+2948
+2949
+2950
+2951
+2952
+2953
+2954
+2955
+2956
+2957
+2958
+2959
+2960
+2961
+2962
+2963
+2964
+2965
+2966
+2967
+2968
+2969
+2970
+2971
+2972
+2973
+2974
+2975
+2976
+2977
+2978
+2979
+2980
+2981
+2982
+2983
+2984
+2985
+2986
+2987
+2988
+2989
+2990
+2991
+2992
+2993
+2994
+2995
+2996
+2997
+2998
+2999
+3000
+3001
+3002
+3003
+3004
+3005
+3006
+3007
+3008
+3009
+3010
+3011
+3012
+3013
+3014
+3015
+3016
+3017
+3018
+3019
+3020
+3021
+3022
+3023
+3024
+3025
+3026
+3027
+3028
+3029
+3030
+3031
+3032
+3033
+3034
+3035
+3036
+3037
+3038
+3039
+3040
+3041
+3042
+3043
+3044
+3045
+3046
+3047
+3048
+3049
+3050
+3051
+3052
+3053
+3054
+3055
+3056
+3057
+3058
+3059
+3060
+3061
+3062
+3063
+3064
+3065
+3066
+3067
+3068
+3069
+3070
+3071
+3072
+3073
+3074
+3075
+3076
+3077
+3078
+3079
+3080
+3081
+3082
+3083
+3084
+3085
+3086
+3087
+3088
+3089
+3090
+3091
+3092
+3093
+3094
+3095
+3096
+3097
+3098
+3099
+3100
+3101
+3102
+3103
+3104
+3105
+3106
+3107
+3108
+3109
+3110
+3111
+3112
+3113
+3114
+3115
+3116
+3117
+3118
+3119
+3120
+3121
+3122
+3123
+3124
+3125
+3126
+3127
+3128
+3129
+3130
+3131
+3132
+3133
+3134
+3135
+3136
+3137
+3138
+3139
+3140
+3141
+3142
+3143
+3144
+3145
+3146
+3147
+3148
+3149
+3150
+3151
+3152
+3153
+3154
+3155
+3156
+3157
+3158
+3159
+3160
+3161
+3162
+3163
+3164
+3165
+3166
+3167
+3168
+3169
+3170
+3171
+3172
+3173
+3174
+3175
+3176
+3177
+3178
+3179
+3180
+3181
+3182
+3183
+3184
+3185
+3186
+3187
+3188
+3189
+3190
+3191
+3192
+3193
+3194
+3195
+3196
+3197
+3198
+3199
+3200
+
//! #### Project documentation
+//! 
+//! See [official website](https://pacak.github.io/bpaf/bpaf/_documentation/index.html) for more up to date version.
+//!
+//! - [Introduction and design goals](_0_intro) - A quick intro. What, why and how
+//! - [Tutorials](_1_tutorials) - practical, learning oriented guides
+//! - [HOWTO - practical, oriented to solving problems guides](_2_howto)
+//! - [Parsing cookbook](_3_cookbook) - How to parse less frequent combinations
+//! - [Theory explanation](_4_explanation) - Theoretical information about abstractions used by the library, oriented for understanding
+//!
+    pub mod _0_intro {
+        //! &nbsp;
+        //! 
+        //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+        //!   <td style='width: 33%; text-align: left;'>
+        //!   </td>
+        //!   <td style='width: 34%; text-align: center;'>
+        //! 
+        //! [&uarr; Project documentation &uarr;](super::super::_documentation)
+        //! 
+        //!   </td>
+        //!   <td style='width: 33%; text-align: right;'>
+        //! 
+        //! [Tutorials &rarr;](super::_1_tutorials)
+        //! 
+        //!   </td>
+        //! </tr></table>
+        //! 
+        //! #### Introduction and design goals
+        //! A quick intro. What, why and how
+        //! 
+        //! `bpaf` is a lightweight and flexible command line parser that uses both combinatoric and derive
+        //! style API
+        //! 
+        //! Combinatoric API usually means a bit more typing but no dependency on proc macros and more help
+        //! from the IDE, derive API uses proc macro to save on typing but your IDE will be less likely to
+        //! help you. Picking one API style does not lock you out from using the other style, you can mix
+        //! and match both in a single parser
+        //! 
+        //! # Examples of both styles
+        //! 
+        #![cfg_attr(not(doctest), doc = include_str!("docs2/intro.md"))]
+        //! 
+        //! # Design goals
+        //! 
+        //! ## Parse, don't validate
+        //! 
+        //! `bpaf` tries hard to let you move as many invariants about the user input you are
+        //! trying to parse into rust types: for mutually exclusive options you can get `enum` with
+        //! exclusive items going into separate branches, and you can collect results into types like
+        //! [`BTreeSet`](std::collections::BTreeSet), or whatever custom type you might have with
+        //! custom parsing. Ideas for
+        //! [making invalid states unrepresentable](https://geeklaunch.io/blog/make-invalid-states-unrepresentable/)
+        //! and [using parsing over validation](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/)
+        //! are not new.
+        //! 
+        //! That said you can also validate your inputs if this fits your situation better. If you want to
+        //! ensure that the sum of every numeric field must be divisible by both 3 and 5, but only when it's
+        //! Thursday - you can do that too.
+        //! 
+        //! ## Flexibility
+        //! 
+        //! While aiming to be a general-purpose command line parser `bpaf` offers a few backdoors that
+        //! allow you to parse pretty much anything you want: chained commands, custom blocks of options,
+        //! DOS-style options (`/ofile.pas`), `dd` style options (`if=file of=out`), etc. A similar idea applies
+        //! to what the parser can produce - if your app operates with boxed string slices internally - `bpaf`
+        //! will give you `Box<str>` instead of `String` if you ask it to.
+        //! 
+        //! The only restriction is that you cannot use information from items parsed earlier (but not
+        //! the fact that something was parsed successfully or not) to decide to how to parse further
+        //! options, and even then you can side step this restriction by passing some shared state as a
+        //! parameter to the parsers.
+        //! 
+        //! ## Reusability
+        //! 
+        //! Parsers in `bpaf` are not monolithic and you can share their parts across multiple binaries,
+        //! workspace members or even independent projects. Say you have multiple binaries in a workspace
+        //! that perform different operations on some input. You can declare a parser for the input
+        //! specifically, along with all the validations, help messages or shell dynamic completion
+        //! functions you need and use it across all the binaries alongside the arguments specific to
+        //! those binaries.
+        //! 
+        //! ## Composition, transformation
+        //! 
+        //! Parsers in `bpaf` are not finalized either, say you have a parser that describes a single input
+        //! for your program, it can take multiple arguments or perform extra validations, etc. You can
+        //! always compose this parser with any other parser to produce tuples of both results for example.
+        //! Or to make it so parser runs multiple times and collects results into a `Vec`.
+        //! 
+        //! ## Performance
+        //! 
+        //! While performance is an explicit non-goal - `bpaf` does nothing that would pessimize it either,
+        //! so performance is on par or better compared to other fully featured parsers.
+        //! 
+        //! ## Correctness
+        //! 
+        //! `bpaf` would parse only items it can represent and will reject anything it cannot represent
+        //! in the output. Say your parser accepts both `--intel` and `--att` flags, but encodes the result
+        //! into `enum Style { Intel, Att }`, `bpaf` will accept those flags separately, but not if they
+        //! are used both at once. If the parser later collects multiple styles into a `Vec<Style>` then it
+        //! will accept any combinationof those flags.
+        //! 
+        //! ## User friendly
+        //! 
+        //! `bpaf` tries to provide user-friendly error messages, and suggestions for typos but also scripts
+        //! for shell completion, `man` pages and markdown documentation for the web.
+        //!
+        //!
+        //! &nbsp;
+        //! 
+        //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+        //!   <td style='width: 33%; text-align: left;'>
+        //!   </td>
+        //!   <td style='width: 34%; text-align: center;'>
+        //! 
+        //! [&uarr; Project documentation &uarr;](super::super::_documentation)
+        //! 
+        //!   </td>
+        //!   <td style='width: 33%; text-align: right;'>
+        //! 
+        //! [Tutorials &rarr;](super::_1_tutorials)
+        //! 
+        //!   </td>
+        //! </tr></table>
+        //! 
+    use crate::*;
+    }
+    pub mod _1_tutorials {
+        //! &nbsp;
+        //! 
+        //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+        //!   <td style='width: 33%; text-align: left;'>
+        //! 
+        //! [&larr; Introduction and design goals](super::_0_intro)
+        //! 
+        //!   </td>
+        //!   <td style='width: 34%; text-align: center;'>
+        //! 
+        //! [&uarr; Project documentation &uarr;](super::super::_documentation)
+        //! 
+        //!   </td>
+        //!   <td style='width: 33%; text-align: right;'>
+        //! 
+        //! [HOWTO - practical, oriented to solving problems guides &rarr;](super::_2_howto)
+        //! 
+        //!   </td>
+        //! </tr></table>
+        //! 
+        //! #### Tutorials
+        //! practical, learning oriented guides
+        //!
+        //! - [Types of arguments](_0_types_of_arguments) - common types of line options and conventions
+        //! - [Combinatoric API](_1_combinatoric_api) - Parse arguments without using proc macros
+        //! - [Derive API tutorial](_2_derive_api) - Create a parser by defining a structure
+        //! - [Designing a good datatype](_3_picking_type) - bpaf allows you to reduce the size of legal values to valid ones
+        //!
+        //! &nbsp;
+        //! 
+        //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+        //!   <td style='width: 33%; text-align: left;'>
+        //! 
+        //! [&larr; Introduction and design goals](super::_0_intro)
+        //! 
+        //!   </td>
+        //!   <td style='width: 34%; text-align: center;'>
+        //! 
+        //! [&uarr; Project documentation &uarr;](super::super::_documentation)
+        //! 
+        //!   </td>
+        //!   <td style='width: 33%; text-align: right;'>
+        //! 
+        //! [HOWTO - practical, oriented to solving problems guides &rarr;](super::_2_howto)
+        //! 
+        //!   </td>
+        //! </tr></table>
+        //! 
+        pub mod _0_types_of_arguments {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Tutorials &uarr;](super::super::_1_tutorials)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Combinatoric API &rarr;](super::_1_combinatoric_api)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Types of arguments
+            //! common types of line options and conventions
+            //! 
+            //! This chapter serves as an introduction to available command line options and tries to set the
+            //! terminology. If you are familiar with command line argument parsers in general - feel free to
+            //! skip it.
+            //! 
+            //! If you ever used any software from a command line (say `cargo`) you used command line options.
+            //! Let's recap how you might run tests for a crate in your rust project:
+            //! 
+            //! <div class="code-wrap">
+            //! <pre>
+            //! $ cargo test -p my_project --verbose
+            //! </pre>
+            //! </div>
+            //! 
+            //! `cargo` here is an executable name, everything to the right of it separated by spaces are the
+            //! options.
+            //! 
+            //! Nowadays programs share mostly similar conventions about what a command line argument is, it
+            //! wasn't the case before though. Let's cover the basic types.
+            //!
+            //! - [Options, switches or flags](_0_switch)
+            //! - [Option arguments or arguments](_1_argument)
+            //! - [Operands or positional items](_2_positional)
+            //! - [Commands or subcommands](_3_command)
+            //! - [Exotic schemas](_4_exotic)
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Tutorials &uarr;](super::super::_1_tutorials)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Combinatoric API &rarr;](super::_1_combinatoric_api)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            pub mod _0_switch {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Types of arguments &uarr;](super::super::_0_types_of_arguments)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Option arguments or arguments &rarr;](super::_1_argument)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Options, switches or flags
+                //! 
+                //! Options or flags usually starts with a dash, a single dash for short options and a double dash for
+                //! long one. Several short options can usually be squashed together with a single dash in front of
+                //! them to save on typing: `-vvv` can be parsed the same as `-v -v -v`. Options don't have any
+                //! other information apart from being there or not. Relative position usually does not matter and
+                //! `--alpha --beta` should parse the same as `--beta --alpha`.
+                //! 
+                //! <div class="code-wrap">
+                //! <pre>
+                //! $ cargo <span style="font-weight: bold">--help</span>
+                //! $ ls <span style="font-weight: bold">-la</span>
+                //! $ ls <span style="font-weight: bold">--time --reverse</span>
+                //! </pre>
+                //! </div>
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/switch.md"))]
+                //! 
+                //! For more detailed info see [`NamedArg::switch`] and
+                //! [`NamedArg::flag`]
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Types of arguments &uarr;](super::super::_0_types_of_arguments)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Option arguments or arguments &rarr;](super::_1_argument)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _1_argument {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Options, switches or flags](super::_0_switch)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Types of arguments &uarr;](super::super::_0_types_of_arguments)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Operands or positional items &rarr;](super::_2_positional)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Option arguments or arguments
+                //! 
+                //! Option arguments are similar to regular options but they come with an extra value attached.
+                //! Value can be separated by a space, `=` or directly adjacent to a short name. Same as with
+                //! options - their relative position usually doesn't matter.
+                //! 
+                //! <div class="code-wrap">
+                //! <pre>
+                //! $ cargo build <span style="font-weight: bold">--package bpaf</span>
+                //! $ cargo test <span style="font-weight: bold">-j2</span>
+                //! $ cargo check <span style="font-weight: bold">--bin=megapotato</span>
+                //! </pre>
+                //! </div>
+                //! 
+                //! In the generated help message or documentation they come with a placeholder metavariable,
+                //! usually a short, all-caps word describing what the value means: `NAME`, `AGE`, `SPEC`, and `CODE`
+                //! are all valid examples.
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/argument.md"))]
+                //! 
+                //! For more detailed info see [`NamedArg::argument`]
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Options, switches or flags](super::_0_switch)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Types of arguments &uarr;](super::super::_0_types_of_arguments)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Operands or positional items &rarr;](super::_2_positional)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _2_positional {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Option arguments or arguments](super::_1_argument)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Types of arguments &uarr;](super::super::_0_types_of_arguments)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Commands or subcommands &rarr;](super::_3_command)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Operands or positional items
+                //! 
+                //! Operands are usually items that are present on a command line and not prefixed by a short or
+                //! long name. They are usually used to represent the most important part of the operation:
+                //! `cat Cargo.toml` - display THIS file, `rm -rf target` - remove THIS folder and so on.
+                //! 
+                //! <div class="code-wrap">
+                //! <pre>
+                //! $ cat <span style="font-weight: bold">/etc/passwd</span>
+                //! $ rm -rf <span style="font-weight: bold">target</span>
+                //! $ man <span style="font-weight: bold">gcc</span>
+                //! </pre>
+                //! </div>
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/positional.md"))]
+                //! 
+                //! For more detailed info see [`positional`](crate::positional) and
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Option arguments or arguments](super::_1_argument)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Types of arguments &uarr;](super::super::_0_types_of_arguments)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Commands or subcommands &rarr;](super::_3_command)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _3_command {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Operands or positional items](super::_2_positional)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Types of arguments &uarr;](super::super::_0_types_of_arguments)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Exotic schemas &rarr;](super::_4_exotic)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Commands or subcommands
+                //! 
+                //! Commands are similar to positional items, but instead of representing an item they start
+                //! a whole new parser, usually with its help and other arguments. Commands allow a single
+                //! application to perform multiple different functions. The command parser will be able to parse all
+                //! the command line options to the right of the command name
+                //! 
+                //! <div class="code-wrap">
+                //! <pre>
+                //! $ cargo <span style="font-weight: bold">build --release</span>
+                //! $ cargo <span style="font-weight: bold">clippy</span>
+                //! $ cargo <span style="font-weight: bold">asm --intel --everything</span>
+                //! </pre>
+                //! </div>
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/command.md"))]
+                //! 
+                //! For more detailed info see [`OptionParser::command`]
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Operands or positional items](super::_2_positional)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Types of arguments &uarr;](super::super::_0_types_of_arguments)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Exotic schemas &rarr;](super::_4_exotic)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _4_exotic {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Commands or subcommands](super::_3_command)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Types of arguments &uarr;](super::super::_0_types_of_arguments)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Exotic schemas
+                //! 
+                //! While modern software tends to use just the options listed above you can still encounter
+                //! programs created before those options became the norm and they use something completely different,
+                //! let me give a few examples, see [the parsing cookbook](crate::_documentation::_2_howto)
+                //! about actually parsing them
+                //! 
+                //! `su` takes an option that consists of a single dash `-`
+                //! 
+                //! <div class="code-wrap"><pre>
+                //! $ su <span style="font-weight: bold">-</span>
+                //! </pre></div>
+                //! 
+                //! `find` considers everything between `--exec` and `;` to be a single item.
+                //! this example calls `ls -l` on every file `find` finds.
+                //! 
+                //! <div class="code-wrap"><pre>
+                //! $ find /etc --exec ls -l '{}' \;
+                //! </pre></div>
+                //! 
+                //! `Xorg` and related tools use flag-like items that start with a single `+` to enable a
+                //! feature and with `-` to disable it.
+                //! 
+                //! <div class="code-wrap"><pre>
+                //! $ xorg -backing +xinerama
+                //! </pre></div>
+                //! 
+                //! `dd` takes several key-value pairs, this would create a 100M file
+                //! <div class="code-wrap"><pre>
+                //! $ dd if=/dev/zero of=dummy.bin bs=1M count=100
+                //! </pre></div>
+                //! 
+                //! Most of the command line arguments in Turbo C++ 3.0 start with `/`. For example, option
+                //! `/x` tells it to use all available extended memory, while `/x[=n]` limits it to n kilobytes
+                //! <div class="code-wrap"><pre>
+                //! C:\PROJECT>TC /x=200
+                //! </pre></div>
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Commands or subcommands](super::_3_command)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Types of arguments &uarr;](super::super::_0_types_of_arguments)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+        use crate::*;
+        }
+        pub mod _1_combinatoric_api {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Types of arguments](super::_0_types_of_arguments)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Tutorials &uarr;](super::super::_1_tutorials)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Derive API tutorial &rarr;](super::_2_derive_api)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Combinatoric API
+            //! Parse arguments without using proc macros
+            //! 
+            //! When making a parser in the Combinatoric style API you usually go through those steps
+            //! 
+            //! 1. Design data type your application will receive
+            //! 2. Design command line options user will have to pass
+            //! 3. Create a set of simple parsers
+            //! 4. Combine and transform simple parsers to create the final data type
+            //! 5. Transform the resulting [`Parser`] into [`OptionParser`] and run it
+            //! 
+            //! Let's go through some of them in more detail:
+            //!
+            //! - [Making a simple parser](_0_simple_parser)
+            //! - [Transforming parsers](_1_chaining)
+            //! - [Combining multiple simple parsers](_2_combining)
+            //! - [Subcommand parsers](_3_subcommands)
+            //! - [Improving the user experience](_4_decorating)
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Types of arguments](super::_0_types_of_arguments)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Tutorials &uarr;](super::super::_1_tutorials)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Derive API tutorial &rarr;](super::_2_derive_api)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            pub mod _0_simple_parser {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Combinatoric API &uarr;](super::super::_1_combinatoric_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Transforming parsers &rarr;](super::_1_chaining)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Making a simple parser
+                //! 
+                //! In this chapter we'll go over making a few simple parsers.
+                //!
+                //! - [Switch parser](_0_switch)
+                //! - [Argument parser](_1_argument)
+                //! - [Positional item parser](_2_positional)
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Combinatoric API &uarr;](super::super::_1_combinatoric_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Transforming parsers &rarr;](super::_1_chaining)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                pub mod _0_switch {
+                    //! &nbsp;
+                    //! 
+                    //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                    //!   <td style='width: 33%; text-align: left;'>
+                    //!   </td>
+                    //!   <td style='width: 34%; text-align: center;'>
+                    //! 
+                    //! [&uarr; Making a simple parser &uarr;](super::super::_0_simple_parser)
+                    //! 
+                    //!   </td>
+                    //!   <td style='width: 33%; text-align: right;'>
+                    //! 
+                    //! [Argument parser &rarr;](super::_1_argument)
+                    //! 
+                    //!   </td>
+                    //! </tr></table>
+                    //! 
+                    //! #### Switch parser
+                    //! 
+                    //! Let's start with the simplest possible one - a simple switch that gets parsed into a `bool`.
+                    //! 
+                    //! First of all - the switch needs a name - you can start with [`short`] or [`long`] and add more
+                    //! names if you want: `long("simple")` or `short('s').long("simple")`. This gives something with
+                    //! the type [`NamedArg`]:
+                    //! 
+                    //! ```rust
+                    //! # use bpaf::*;
+                    //! use bpaf::parsers::NamedArg;
+                    //! fn simple_switch() -> NamedArg {
+                    //!     short('s').long("simple")
+                    //! }
+                    //! ```
+                    //! 
+                    //! From `NamedArg` you make a switch parser by calling [`NamedArg::switch`]. Usually, you do it
+                    //! right away without assigning `NamedArg` to a variable.
+                    //! 
+                    //! ```rust
+                    //! # use bpaf::*;
+                    //! fn simple_switch() -> impl Parser<bool> {
+                    //!     short('s').long("simple").switch()
+                    //! }
+                    //! ```
+                    //! 
+                    //! The switch parser we just made implements trait [`Parser`] and to run it you convert it to [`OptionParser`] with
+                    //! [`Parser::to_options`] and run it with [`OptionParser::run`]
+                    //! 
+                    //! Full example with some sample inputs and outputs:
+                    #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_switch.md"))]
+                    //! 
+                    //! 
+                    //! With [`NamedArg::help`] you can attach a help message that will be used in `--help` output.
+                    //!
+                    //!
+                    //! &nbsp;
+                    //! 
+                    //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                    //!   <td style='width: 33%; text-align: left;'>
+                    //!   </td>
+                    //!   <td style='width: 34%; text-align: center;'>
+                    //! 
+                    //! [&uarr; Making a simple parser &uarr;](super::super::_0_simple_parser)
+                    //! 
+                    //!   </td>
+                    //!   <td style='width: 33%; text-align: right;'>
+                    //! 
+                    //! [Argument parser &rarr;](super::_1_argument)
+                    //! 
+                    //!   </td>
+                    //! </tr></table>
+                    //! 
+                use crate::*;
+                }
+                pub mod _1_argument {
+                    //! &nbsp;
+                    //! 
+                    //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                    //!   <td style='width: 33%; text-align: left;'>
+                    //! 
+                    //! [&larr; Switch parser](super::_0_switch)
+                    //! 
+                    //!   </td>
+                    //!   <td style='width: 34%; text-align: center;'>
+                    //! 
+                    //! [&uarr; Making a simple parser &uarr;](super::super::_0_simple_parser)
+                    //! 
+                    //!   </td>
+                    //!   <td style='width: 33%; text-align: right;'>
+                    //! 
+                    //! [Positional item parser &rarr;](super::_2_positional)
+                    //! 
+                    //!   </td>
+                    //! </tr></table>
+                    //! 
+                    //! #### Argument parser
+                    //! 
+                    //! Next in complexity would be a parser to consume a named argument, such as `-p my_crate`. Same
+                    //! as with the switch parser it starts from a `NamedArg` but the next method is [`NamedArg::argument`].
+                    //! This method takes a metavariable name - a short description that will be used in the `--help`
+                    //! output. `rustc` also needs to know the parameter type you are trying to parse, there are
+                    //! several ways to do it:
+                    //! 
+                    //! ```rust
+                    //! # use bpaf::*;
+                    //! # use std::path::PathBuf;
+                    //! fn simple_argument_1() -> impl Parser<u32> {
+                    //!     // rustc figures out the type from returned value
+                    //!     long("number").argument("NUM")
+                    //! }
+                    //! 
+                    //! fn simple_argument_2() -> impl Parser<String> {
+                    //!     // type is specified explicitly with turbofish
+                    //!     long("name").argument::<String>("NAME")
+                    //! }
+                    //! 
+                    //! fn file_parser() -> OptionParser<PathBuf> {
+                    //!     // OptionParser is a type for finalized parser, at this point you can
+                    //!     // start adding extra information to the `--help` message
+                    //!     long("file").argument::<PathBuf>("FILE").to_options()
+                    //! }
+                    //! ```
+                    //! 
+                    //! You can use any type for as long as it implements [`FromStr`]. To parse items that don't
+                    //! implement it you can first parse a `String` or `OsString` and then use [`Parser::parse`], see
+                    //! [the next chapter](super::super::_1_chaining) on how to do that.
+                    //! 
+                    //! Full example with some sample inputs and outputs:
+                    #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_argument.md"))]
+                    //!
+                    //!
+                    //! &nbsp;
+                    //! 
+                    //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                    //!   <td style='width: 33%; text-align: left;'>
+                    //! 
+                    //! [&larr; Switch parser](super::_0_switch)
+                    //! 
+                    //!   </td>
+                    //!   <td style='width: 34%; text-align: center;'>
+                    //! 
+                    //! [&uarr; Making a simple parser &uarr;](super::super::_0_simple_parser)
+                    //! 
+                    //!   </td>
+                    //!   <td style='width: 33%; text-align: right;'>
+                    //! 
+                    //! [Positional item parser &rarr;](super::_2_positional)
+                    //! 
+                    //!   </td>
+                    //! </tr></table>
+                    //! 
+                use crate::*;
+                }
+                pub mod _2_positional {
+                    //! &nbsp;
+                    //! 
+                    //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                    //!   <td style='width: 33%; text-align: left;'>
+                    //! 
+                    //! [&larr; Argument parser](super::_1_argument)
+                    //! 
+                    //!   </td>
+                    //!   <td style='width: 34%; text-align: center;'>
+                    //! 
+                    //! [&uarr; Making a simple parser &uarr;](super::super::_0_simple_parser)
+                    //! 
+                    //!   </td>
+                    //!   <td style='width: 33%; text-align: right;'>
+                    //!   </td>
+                    //! </tr></table>
+                    //! 
+                    //! #### Positional item parser
+                    //! 
+                    //! And the last simple option type is a parser for positional items. Since there's no name you use
+                    //! the [`positional`] function directly. Similar to [`NamedArg::argument`] this method takes
+                    //! a metavariable name and a type parameter in some form. You can also attach the help message
+                    //! thanks to [`ParsePositional::help`]
+                    //! 
+                    //! Full example:
+                    #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_positional.md"))]
+                    //!
+                    //!
+                    //! &nbsp;
+                    //! 
+                    //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                    //!   <td style='width: 33%; text-align: left;'>
+                    //! 
+                    //! [&larr; Argument parser](super::_1_argument)
+                    //! 
+                    //!   </td>
+                    //!   <td style='width: 34%; text-align: center;'>
+                    //! 
+                    //! [&uarr; Making a simple parser &uarr;](super::super::_0_simple_parser)
+                    //! 
+                    //!   </td>
+                    //!   <td style='width: 33%; text-align: right;'>
+                    //!   </td>
+                    //! </tr></table>
+                    //! 
+                use crate::*;
+                }
+            use crate::*;
+            }
+            pub mod _1_chaining {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Making a simple parser](super::_0_simple_parser)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Combinatoric API &uarr;](super::super::_1_combinatoric_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Combining multiple simple parsers &rarr;](super::_2_combining)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Transforming parsers
+                //! 
+                //! Once you have your primitive parsers done you might want to improve them a bit - add fallback
+                //! values, or change them to consume multiple items, etc. Every primitive (or composite) parser
+                //! implements [`Parser`] so most of the transformations are coming from this trait.
+                //! 
+                //! Say you have a parser that takes a crate name as a required argument you want to use in your own
+                //! `cargo test` replacement
+                //! 
+                //! ```rust
+                //! use bpaf::*;
+                //! fn krate() -> impl Parser<String> {
+                //!     long("crate").help("Crate name to process").argument("CRATE")
+                //! }
+                //! ```
+                //! 
+                //! You can turn it into, for example, an optional argument - something that returns
+                //! `Some("my_crate")` if specified or `None` if it wasn't. Or to let the user to pass a multiple
+                //! of them and collect them all into a `Vec`
+                //! 
+                //! 
+                //! ```rust
+                //! use bpaf::*;
+                //! fn maybe_krate() -> impl Parser<Option<String>> {
+                //!     long("crate")
+                //!         .help("Crate name to process")
+                //!         .argument("CRATE")
+                //!         .optional()
+                //! }
+                //! 
+                //! fn krates() -> impl Parser<Vec<String>> {
+                //!     long("crate")
+                //!         .help("Crate name to process")
+                //!         .argument("CRATE")
+                //!         .many()
+                //! }
+                //! ```
+                //! 
+                //! A complete example:
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_many.md"))]
+                //! 
+                //! Transforming a parser with a method from the `Parser` trait usually gives you a new parser back and
+                //! you can chain as many transformations as you need.
+                //! 
+                //! Transformations available in the `Parser` trait things like adding fallback values, making
+                //! the parser optional, making it so it consumes many but at least one value, changing how it is
+                //! being shown in `--help` output, adding additional validation and parsing on top and so on.
+                //! 
+                //! The order of those chained transformations matters and for some operations using the right order
+                //! makes code cleaner. For example, suppose you are trying to write a parser that takes an even
+                //! number and this parser should be optional. There are two ways to write it:
+                //! 
+                //! Validation first:
+                //! 
+                //! ```rust
+                //! # use bpaf::*;
+                //! fn even() -> impl Parser<Option<usize>> {
+                //!     long("even")
+                //!         .argument("N")
+                //!         .guard(|&n| n % 2 == 0, "number must be even")
+                //!         .optional()
+                //! }
+                //! ```
+                //! 
+                //! Optional first:
+                //! 
+                //! ```rust
+                //! # use bpaf::*;
+                //! fn even() -> impl Parser<Option<usize>> {
+                //!     long("even")
+                //!         .argument("N")
+                //!         .optional()
+                //!         .guard(|&n| n.map_or(true, |n| n % 2 == 0), "number must be even")
+                //! }
+                //! ```
+                //! 
+                //! In later case validation function must deal with a possibility where a number is absent, for this
+                //! specific example it makes code less readable.
+                //! 
+                //! One of the important types of transformations you can apply is a set of failing
+                //! transformations. Suppose your application operates with numbers and uses `newtype` pattern to
+                //! keep track of what numbers are odd or even. A parser that consumes an even number can use
+                //! [`Parser::parse`] and may look like this:
+                //! 
+                //! ```rust
+                //! # use bpaf::*;
+                //! pub struct Even(usize);
+                //! 
+                //! fn mk_even(n: usize) -> Result<Even, &'static str> {
+                //!     if n % 2 == 0 {
+                //!         Ok(Even(n))
+                //!     } else {
+                //!         Err("Not an even number")
+                //!     }
+                //! }
+                //! 
+                //! fn even() -> impl Parser<Even> {
+                //!     long("even")
+                //!         .argument::<usize>("N")
+                //!         .parse(mk_even)
+                //! }
+                //! ```
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Making a simple parser](super::_0_simple_parser)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Combinatoric API &uarr;](super::super::_1_combinatoric_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Combining multiple simple parsers &rarr;](super::_2_combining)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _2_combining {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Transforming parsers](super::_1_chaining)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Combinatoric API &uarr;](super::super::_1_combinatoric_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Subcommand parsers &rarr;](super::_3_subcommands)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Combining multiple simple parsers
+                //! 
+                //! A single-item option parser can only get you so far. Fortunately, you can combine multiple
+                //! parsers with [`construct!`] macro.
+                //! 
+                //! For sequential composition (all the fields must be present) you write your code as if you are
+                //! constructing a structure, enum variant or a tuple and wrap it with `construct!`. Both
+                //! a constructor and parsers must be present in the scope. If instead of a parser you have a function
+                //! that creates one - just add `()` after the name:
+                //! 
+                //! ```rust
+                //! # use bpaf::*;
+                //! struct Options {
+                //!     alpha: usize,
+                //!     beta: usize
+                //! }
+                //! 
+                //! fn alpha() -> impl Parser<usize> {
+                //!     long("alpha").argument("ALPHA")
+                //! }
+                //! 
+                //! fn both() -> impl Parser<Options> {
+                //!     let beta = long("beta").argument("BETA");
+                //!     // call `alpha` function, and use result to make parser
+                //!     // for field `alpha`, use parser `beta` for field `beta`
+                //!     construct!(Options { alpha(), beta })
+                //! }
+                //! ```
+                //! 
+                //! Full example:
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_construct.md"))]
+                //! 
+                //! If you are using positional parsers - they must go to the right-most side and will run in
+                //! the order you specify them. For named parsers order affects only the `--help` message.
+                //! 
+                //! The second type of composition `construct!` offers is a parallel composition. You pass multiple
+                //! parsers that produce the same result type in `[]` and `bpaf` selects one that fits best with
+                //! the data user gave.
+                //! 
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_choice.md"))]
+                //! 
+                //! If parsers inside parallel composition can parse the same object - the longest possible match
+                //! should go first since `bpaf` picks an earlier parser if everything else is equal, otherwise it
+                //! does not matter. In this example `construct!([miles, km])` produces the same results as
+                //! `construct!([km, miles])` and only `--help` message is going to be different.
+                //! 
+                //! Parsers created with [`construct!`] still implement the [`Parser`] trait so you can apply more
+                //! transformation on top. For example same as you can make a simple parser optional - you can make
+                //! a composite parser optional. Parser transformed this way will succeed if both `--alpha` and
+                //! `--beta` are present or neither of them:
+                //! 
+                //! ```rust
+                //! # use bpaf::*;
+                //! struct Options {
+                //!     alpha: usize,
+                //!     beta: usize
+                //! }
+                //! 
+                //! fn parser() -> impl Parser<Option<Options>> {
+                //!     let alpha = long("alpha").argument("ALPHA");
+                //!     let beta = long("beta").argument("BETA");
+                //!     construct!(Options { alpha, beta }).optional()
+                //! }
+                //! ```
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Transforming parsers](super::_1_chaining)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Combinatoric API &uarr;](super::super::_1_combinatoric_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Subcommand parsers &rarr;](super::_3_subcommands)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _3_subcommands {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Combining multiple simple parsers](super::_2_combining)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Combinatoric API &uarr;](super::super::_1_combinatoric_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Improving the user experience &rarr;](super::_4_decorating)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Subcommand parsers
+                //! 
+                //! To make a parser for a subcommand you make an `OptionParser` for that subcommand first as if it
+                //! was the only thing your application would parse then turn it into a regular [`Parser`]
+                //! you can further compose with [`OptionParser::command`].
+                //! 
+                //! This gives [`ParseCommand`] back, you can add aliases or tweak the help message if you want to.
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_command.md"))]
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Combining multiple simple parsers](super::_2_combining)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Combinatoric API &uarr;](super::super::_1_combinatoric_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Improving the user experience &rarr;](super::_4_decorating)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _4_decorating {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Subcommand parsers](super::_3_subcommands)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Combinatoric API &uarr;](super::super::_1_combinatoric_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Improving the user experience
+                //! 
+                //! Once you have the final parser done there are still a few ways you can improve user experience.
+                //! [`OptionParser`] comes equipped with a few methods that let you set version number,
+                //! description, help message header and footer and so on.
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_to_options.md"))]
+                //! 
+                //! There are a few other things you can do:
+                //! 
+                //! - group some of the primitive parsers into logical blocks for `--help` message with
+                //!   [`Parser::group_help`]
+                //! - add tests to make sure important combinations are handled the way they are supposed to
+                //!   after any future refactors with [`OptionParser::run_inner`]
+                //! - add a test to make sure that bpaf internal invariants are satisfied with
+                //!   [`OptionParser::check_invariants`]
+                //! - generate user documentation in manpage and markdown formats with
+                //!   [`OptionParser::render_manpage`] and [`OptionParser::render_markdown`]
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Subcommand parsers](super::_3_subcommands)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Combinatoric API &uarr;](super::super::_1_combinatoric_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+        use crate::*;
+        }
+        pub mod _2_derive_api {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Combinatoric API](super::_1_combinatoric_api)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Tutorials &uarr;](super::super::_1_tutorials)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Designing a good datatype &rarr;](super::_3_picking_type)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Derive API tutorial
+            //! Create a parser by defining a structure
+            //! 
+            //! 
+            //! When making a parser using Derive API you should go through approximately following steps:
+            //! 
+            //! 1. Design data type your application will receive
+            //! 2. Design command line options user will have to pass
+            //! 3. Add `#[derive(Bpaf, Debug, Clone)]` on top of your type or types
+            //! 4. Add `#[bpaf(xxx)]` annotations on types and fields
+            //! 5. And `#[bpaf(options)]` to the top type
+            //! 6. Run the resulting parser
+            //! 
+            //! 
+            //! Let’s go through some of them in more detail:
+            //!
+            //! - [Getting started with derive macro](_0_intro)
+            //! - [Customizing flag and argument names](_1_custom_names)
+            //! - [Customizing the consumers](_2_custom_consumers)
+            //! - [Transforming parsed values](_3_postpr)
+            //! - [Parsing structs and enums](_4_enums_and_structs)
+            //! - [What gets generated](_5_generate)
+            //! - [Making nested parsers](_6_nesting)
+            //! - [Parsing subcommands](_7_commands)
+            //! - [Making a cargo command](_8_cargo)
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Combinatoric API](super::_1_combinatoric_api)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Tutorials &uarr;](super::super::_1_tutorials)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Designing a good datatype &rarr;](super::_3_picking_type)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            pub mod _0_intro {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Customizing flag and argument names &rarr;](super::_1_custom_names)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Getting started with derive macro
+                //! 
+                //! Let's take a look at a simple example
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/derive_basic_intro.md"))]
+                //! 
+                //! `bpaf` is trying hard to guess what you are trying to achieve just from the types so it will
+                //! pick up types, doc comments, presence or absence of names, but it is possible to customize all
+                //! of it, add custom transformations, validations and more.
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Customizing flag and argument names &rarr;](super::_1_custom_names)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _1_custom_names {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Getting started with derive macro](super::_0_intro)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Customizing the consumers &rarr;](super::_2_custom_consumers)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Customizing flag and argument names
+                //! 
+                //! By default names for flag names are taken directly from the field names so usually you don't
+                //! have to do anything about it, but you can change it with annotations on the fields themselves:
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/derive_basic_custom_name.md"))]
+                //! 
+                //! Rules for picking the name are:
+                //! 
+                //! 1. With no annotations field name longer than a single character becomes a long name,
+                //!    single character name becomes a short name
+                //! 2. Adding either `long` or `short` disables item 1, so adding `short` disables the long name
+                //! 3. `long` or `short` annotation without a parameter derives a value from a field name
+                //! 4. `long` or `short` with a parameter uses that instead
+                //! 5. You can have multiple `long` and `short` annotations, the first of each type becomes a
+                //!    visible name, remaining are used as hidden aliases
+                //! 
+                //! And if you decide to add names - they should go to the left side of the annotation list
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Getting started with derive macro](super::_0_intro)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Customizing the consumers &rarr;](super::_2_custom_consumers)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _2_custom_consumers {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Customizing flag and argument names](super::_1_custom_names)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Transforming parsed values &rarr;](super::_3_postpr)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Customizing the consumers
+                //! 
+                //! By default, `bpaf` picks parsers depending on a field type according to those rules:
+                //! 
+                //! 1. `bool` fields are converted into switches: [`NamedArg::switch`](crate::parsers::NamedArg::switch)
+                //! 2. `()` (unit) fields, unit variants of an enum or unit structs themselves are handled as
+                //!    [`NamedArg::req_flag`](crate::parsers::NamedArg::req_flag) and thus users must always specify
+                //!    them for the parser to succeed
+                //! 3. All other types with no `Vec`/`Option` are parsed using [`FromStr`](std::str::FromStr), but
+                //!    smartly, so non-utf8 `PathBuf`/`OsString` are working as expected.
+                //! 4. For values wrapped in `Option` or `Vec` bpaf derives the inner parser and then applies
+                //!    applies logic from [`Parser::optional`] and [`Parser::many`] respectively.
+                //! 
+                //! You can change it with annotations like `switch`, `argument` or `positional`
+                //! 
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/derive_basic_custom_consumer.md"))]
+                //! 
+                //! With arguments that consume a value you can specify its type using turbofish-line syntax
+                //! 
+                //! 
+                //! ```no_run
+                //! # use bpaf::*;
+                //! #[derive(Debug, Clone, Bpaf)]
+                //! #[bpaf(options)]
+                //! pub struct Options {
+                //!     /// A custom argument
+                //!     #[bpaf(positional::<usize>("LENGTH"))]
+                //!     argument: usize,
+                //! }
+                //! 
+                //! fn main() {
+                //!     let opts = options().run();
+                //!     println!("{:?}", opts)
+                //! }
+                //! ```
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Customizing flag and argument names](super::_1_custom_names)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Transforming parsed values &rarr;](super::_3_postpr)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _3_postpr {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Customizing the consumers](super::_2_custom_consumers)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Parsing structs and enums &rarr;](super::_4_enums_and_structs)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Transforming parsed values
+                //! 
+                //! Once the field has a consumer you can start applying transformations from the [`Parser`] trait.
+                //! Annotation share the same names and follow the same composition rules as in Combinatoric API.
+                //! 
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/derive_basic_postpr.md"))]
+                //! 
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Customizing the consumers](super::_2_custom_consumers)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Parsing structs and enums &rarr;](super::_4_enums_and_structs)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _4_enums_and_structs {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Transforming parsed values](super::_3_postpr)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [What gets generated &rarr;](super::_5_generate)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Parsing structs and enums
+                //! 
+                //! To produce a struct bpaf needs for all the field parsers to succeed. If you are planning to use
+                //! it for some other purpose as well and want to skip them during parsing you can use [`pure`] to
+                //! fill in values in member fields and `#[bpaf(skip)]` on enum variants you want to ignore, see
+                //! combinatoric example in [`Parser::last`].
+                //! 
+                //! If you use `#[derive(Bpaf)]` on an enum parser will produce a variant for which all the parsers
+                //! succeed.
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/derive_basic_enum.md"))]
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Transforming parsed values](super::_3_postpr)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [What gets generated &rarr;](super::_5_generate)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _5_generate {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Parsing structs and enums](super::_4_enums_and_structs)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Making nested parsers &rarr;](super::_6_nesting)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### What gets generated
+                //! 
+                //! Usually calling derive macro on a type generates code to derive a trait implementation for this
+                //! type. With bpaf it's slightly different. It instead generates a function with a name that
+                //! depends on the name of the type and gives either a composable parser (`Parser`) or option parser
+                //! (`OptionParser`) back.
+                //! 
+                //! You can customize the function name with `generate` annotation at the top level:
+                //! 
+                //! ```no_run
+                //! # use bpaf::*;
+                //! #[derive(Debug, Clone, Bpaf)]
+                //! #[bpaf(options, generate(my_options))]
+                //! pub struct Options {
+                //!     /// A simple switch
+                //!     switch: bool
+                //! }
+                //! 
+                //! 
+                //! fn main() {
+                //!     let opts = my_options().run();
+                //!     println!("{:?}", opts);
+                //! }
+                //! ```
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Parsing structs and enums](super::_4_enums_and_structs)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Making nested parsers &rarr;](super::_6_nesting)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _6_nesting {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; What gets generated](super::_5_generate)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Parsing subcommands &rarr;](super::_7_commands)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Making nested parsers
+                //! 
+                //! Up to this point, we've been looking at cases where fields of a structure are all simple
+                //! parsers, possibly wrapped in `Option` or `Vec`, but it is also possible to nest derived parsers
+                //! too:
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/derive_basic_nesting.md"))]
+                //! 
+                //! 
+                //! `external` takes an optional function name and will call that function to make the parser for
+                //! the field. You can chain more transformations after the `external` and if the name is absent -
+                //! `bpaf` would use the field name instead, so you can also write the example above as
+                //! 
+                //! 
+                //! ```rust
+                //! # use bpaf::*;
+                //! #[derive(Debug, Clone, Bpaf)]
+                //! pub enum Format {
+                //!     /// Produce output in HTML format
+                //!     Html,
+                //!     /// Produce output in Markdown format
+                //!     Markdown,
+                //!     /// Produce output in manpage format
+                //!     Manpage,
+                //! }
+                //! 
+                //! #[derive(Debug, Clone, Bpaf)]
+                //! #[bpaf(options)]
+                //! pub struct Options {
+                //!     /// File to process
+                //!     input: String,
+                //!     #[bpaf(external)]
+                //!     format: Format,
+                //! }
+                //! ```
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; What gets generated](super::_5_generate)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Parsing subcommands &rarr;](super::_7_commands)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _7_commands {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Making nested parsers](super::_6_nesting)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Making a cargo command &rarr;](super::_8_cargo)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Parsing subcommands
+                //! 
+                //! The easiest way to define a group of subcommands is to have them inside the same enum with variant
+                //! constructors annotated with `#[bpaf(command("name"))]` with or without the name
+                //! 
+                //! 
+                #![cfg_attr(not(doctest), doc = include_str!("docs2/derive_basic_commands.md"))]
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Making nested parsers](super::_6_nesting)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //! 
+                //! [Making a cargo command &rarr;](super::_8_cargo)
+                //! 
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+            pub mod _8_cargo {
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Parsing subcommands](super::_7_commands)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //!   </td>
+                //! </tr></table>
+                //! 
+                //! #### Making a cargo command
+                //! 
+                //! To make a cargo command you should pass its name as a parameter to `options`. In this example,
+                //! `bpaf` will parse extra parameter cargo passes and you will be able to use it either directly
+                //! with `cargo run` from the repository, running it by `cargo-asm` name or with `cargo asm` name.
+                //! 
+                //! ```no_run
+                //! # use bpaf::*;
+                //! #[derive(Debug, Clone, Bpaf)]
+                //! #[bpaf(options("asm"))]
+                //! pub struct Options {
+                //!     /// A simple switch
+                //!     switch: bool
+                //! }
+                //! 
+                //! 
+                //! fn main() {
+                //!     let opts = options().run();
+                //!     println!("{:?}", opts);
+                //! }
+                //! ```
+                //!
+                //!
+                //! &nbsp;
+                //! 
+                //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+                //!   <td style='width: 33%; text-align: left;'>
+                //! 
+                //! [&larr; Parsing subcommands](super::_7_commands)
+                //! 
+                //!   </td>
+                //!   <td style='width: 34%; text-align: center;'>
+                //! 
+                //! [&uarr; Derive API tutorial &uarr;](super::super::_2_derive_api)
+                //! 
+                //!   </td>
+                //!   <td style='width: 33%; text-align: right;'>
+                //!   </td>
+                //! </tr></table>
+                //! 
+            use crate::*;
+            }
+        use crate::*;
+        }
+        pub mod _3_picking_type {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Derive API tutorial](super::_2_derive_api)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Tutorials &uarr;](super::super::_1_tutorials)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Designing a good datatype
+            //! bpaf allows you to reduce the size of legal values to valid ones
+            //! 
+            //! Parsing usually starts with deciding what kind of data your application wants to get from the user.
+            //! You should try to take advantage of the Rust type system, try to represent the result such that more
+            //! validation can be done during parsing.
+            //! 
+            //! Data types can represent a set of *legal* states - for example, for u8 this is all the numbers
+            //! from 0 to 255, while your app logic may only operate correctly only on some set of *valid*
+            //! states: if this u8 represents a fill ratio for something in percents - only valid numbers are
+            //! from 0 to 100. You can try to narrow down the set of legal states to valid states with [newtype
+            //! pattern](https://doc.rust-lang.org/rust-by-example/generics/new_types.html). This newtype will
+            //! indicate through the type when you've already done validation. For the fill ratio example you can
+            //! implement a newtype along with `FromStr` implementation to get validation for free during
+            //! parsing.
+            //! 
+            //! 
+            //! ```no_run
+            //! # use std::str::FromStr;
+            //! # use bpaf::*;
+            //! #[derive(Debug, Clone, Copy)]
+            //! pub struct Ratio(u8);
+            //! 
+            //! impl FromStr for Ratio {
+            //!     type Err = &'static str;
+            //! 
+            //!     fn from_str(s: &str) -> Result<Self, Self::Err> {
+            //!         match s.parse() {
+            //!             Ok(n) if n <= 100 => Ok(Ratio(n)),
+            //!             _ => Err("Invalid fill ratio")
+            //!         }
+            //!     }
+            //! }
+            //! 
+            //! #[derive(Debug, Clone, Bpaf)]
+            //! #[bpaf(options)]
+            //! struct Options {
+            //!     /// Fill ratio
+            //!     ratio: Ratio
+            //! }
+            //! 
+            //! fn main() {
+            //!     println!("{:?}", options().run());
+            //! }
+            //! ```
+            //! 
+            //! 
+            //! Try using enums instead of structs for mutually exclusive options:
+            //! 
+            //! ```no_check
+            //! /// Good format selection
+            //! #[derive(Debug, Clone, Bpaf)]
+            //! #[bpaf(options)]
+            //! enum OutputFormat {
+            //!     Intel,
+            //!     Att,
+            //!     Llvm
+            //! }
+            //! 
+            //! fn main() {
+            //!     let format = output_format().run();
+            //! 
+            //!     // `rustc` ensures you handle each case, parser won't try to consume
+            //!     // combinations of flags it can't represent. For example it won't accept
+            //!     // both `--intel` and `--att` at once
+            //!     // (unless it can collect multiple of them in a vector)
+            //!     match format {
+            //!         OutputFormat::Intel => ...,
+            //!         OutputFormat::Att => ...,
+            //!         OutputFormat::Llvm => ...,
+            //!     }
+            //! }
+            //! ```
+            //! 
+            //! While it's easy to see how flags like `--intel` and `--att` maps to each of those bools,
+            //! consuming inside your app is more fragile
+            //! 
+            //! ```no_check
+            //! /// Bad format selection
+            //! #[derive(Debug, Clone, Bpaf)]
+            //! #[bpaf(options)]
+            //! struct OutputFormat {
+            //!     intel: bool,
+            //!     att: bool,
+            //!     llvm: bool,
+            //! }
+            //! 
+            //! fn main() {
+            //!     let format = output_format().run();
+            //!     // what happens when none matches? Or all of them?
+            //!     // What happens when you add a new output format?
+            //!     if format.intel {
+            //!         ...
+            //!     } else if format.att {
+            //!         ...
+            //!     } else if format.llvm {
+            //!         ...
+            //!     } else {
+            //!         // can this branch be reached?
+            //!     }
+            //! }
+            //! ```
+            //! 
+            //! Mutually exclusive things are not limited to just flags. For example if your program can take
+            //! input from several different sources such as file, database or interactive input it's a good
+            //! idea to use enum as well:
+            //! 
+            //! ```no_check
+            //! /// Good input selection
+            //! #[derive(Debug, Clone, Bpaf)]
+            //! enum Input {
+            //!     File {
+            //!         filepath: PathBuf,
+            //!     }
+            //!     Database {
+            //!         user: String,
+            //!         password: String.
+            //!     }
+            //!     Interactive,
+            //! }
+            //! ```
+            //! 
+            //! If your codebase uses newtype pattern - it's a good idea to use it starting from the command
+            //! options:
+            //! 
+            //! ```no_check
+            //! #[derive(Debug, Clone, Bpaf)]
+            //! struct Options {
+            //!     // better than taking a String and parsing internally
+            //!     date: NaiveDate,
+            //!     // f64 might work too, but you can start from some basic sanity checks
+            //!     speed: Speed
+            //! }
+            //! ```
+            //! 
+            //! 
+            //! # More reading
+            //! 
+            //! - <https://fsharpforfunandprofit.com/posts/designing-with-types-making-illegal-states-unrepresentable/>
+            //! - <https://geeklaunch.io/blog/make-invalid-states-unrepresentable/>
+            //! - <https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/>
+            //! - <https://khalilstemmler.com/articles/typescript-domain-driven-design/make-illegal-states-unrepresentable/>
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Derive API tutorial](super::_2_derive_api)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Tutorials &uarr;](super::super::_1_tutorials)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+    use crate::*;
+    }
+    pub mod _2_howto {
+        //! &nbsp;
+        //! 
+        //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+        //!   <td style='width: 33%; text-align: left;'>
+        //! 
+        //! [&larr; Tutorials](super::_1_tutorials)
+        //! 
+        //!   </td>
+        //!   <td style='width: 34%; text-align: center;'>
+        //! 
+        //! [&uarr; Project documentation &uarr;](super::super::_documentation)
+        //! 
+        //!   </td>
+        //!   <td style='width: 33%; text-align: right;'>
+        //! 
+        //! [Parsing cookbook &rarr;](super::_3_cookbook)
+        //! 
+        //!   </td>
+        //! </tr></table>
+        //! 
+        //! #### HOWTO - practical, oriented to solving problems guides
+        //!
+        //! - [Testing your parsers](_0_testing)
+        //! - [Dynamic shell completion](_1_completion)
+        //!
+        //! &nbsp;
+        //! 
+        //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+        //!   <td style='width: 33%; text-align: left;'>
+        //! 
+        //! [&larr; Tutorials](super::_1_tutorials)
+        //! 
+        //!   </td>
+        //!   <td style='width: 34%; text-align: center;'>
+        //! 
+        //! [&uarr; Project documentation &uarr;](super::super::_documentation)
+        //! 
+        //!   </td>
+        //!   <td style='width: 33%; text-align: right;'>
+        //! 
+        //! [Parsing cookbook &rarr;](super::_3_cookbook)
+        //! 
+        //!   </td>
+        //! </tr></table>
+        //! 
+        pub mod _0_testing {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; HOWTO - practical, oriented to solving problems guides &uarr;](super::super::_2_howto)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Dynamic shell completion &rarr;](super::_1_completion)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Testing your parsers
+            //! 
+            //! You can test values your parser produces and expected output
+            //! 
+            //! ```no_run
+            //! # use bpaf::*;
+            //! #[derive(Debug, Clone, Bpaf)]
+            //! #[bpaf(options)]
+            //! pub struct Options {
+            //!     pub user: String
+            //! }
+            //! 
+            //! #[test]
+            //! fn test_my_options() {
+            //!     let help = options()
+            //!         .run_inner(&["--help"])
+            //!         .unwrap_err()
+            //!         .unwrap_stdout();
+            //!     let expected_help = "\
+            //! Usage --user=ARG
+            //! <skip>
+            //! ";
+            //! 
+            //!     assert_eq!(help, expected_help);
+            //! }
+            //! 
+            //! #[test]
+            //! fn test_value() {
+            //!     let value = options()
+            //!          .run_inner(&["--user", "Bob"])
+            //!          .unwrap();
+            //!     assert_eq!(value.user, "Bob");
+            //! }
+            //! ```
+            //! 
+            //! [`OptionParser::run_inner`] takes [`Args`] or anything that can be converted to it, in most
+            //! cases using a static slice with strings is enough.
+            //! 
+            //! Easiest way to consume [`ParseFailure`] for testing purposes is with
+            //! [`ParseFailure::unwrap_stderr`] and [`ParseFailure::unwrap_stdout`] - result will lack any colors
+            //! even with them enabled which makes testing easier.
+            //! 
+            //! Successful result parse produces a value, "failed" parse produces stdout or stderr outputs -
+            //! stdout to print help message or version number and stderr to print the error message.
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; HOWTO - practical, oriented to solving problems guides &uarr;](super::super::_2_howto)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Dynamic shell completion &rarr;](super::_1_completion)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+        pub mod _1_completion {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Testing your parsers](super::_0_testing)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; HOWTO - practical, oriented to solving problems guides &uarr;](super::super::_2_howto)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Dynamic shell completion
+            //! 
+            //! `bpaf` implements shell completion to allow to automatically fill in not only flag and command
+            //! names, but also argument and positional item values.
+            //! 
+            //! 1. Enable `autocomplete` feature:
+            //! 
+            //! 
+            //! 	```toml
+            //! 	bpaf = { version = "0.9", features = ["autocomplete"] }
+            //! 	```
+            //! 
+            //! 2. Decorate [`argument`](crate::parsers::NamedArg::argument) and [`positional`] parsers with
+            //!     [`Parser::complete`] to provide completion functions for arguments
+            //! 
+            //! 
+            //! 3. Depending on your shell generate appropriate completion file and place it to whereever your
+            //!     shell is going to look for it, name of the file should correspond in some way to name of
+            //!     your program. Consult manual for your shell for the location and named conventions:
+            //! 
+            //! 	 1. **bash**
+            //! 		```console
+            //! 		$ your_program --bpaf-complete-style-bash >> ~/.bash_completion
+            //! 		```
+            //! 
+            //! 	 1. **zsh**: note `_` at the beginning of the filename
+            //! 		```console
+            //! 		$ your_program --bpaf-complete-style-zsh > ~/.zsh/_your_program
+            //! 		```
+            //! 
+            //! 	 1. **fish**
+            //! 		```console
+            //! 		$ your_program --bpaf-complete-style-fish > ~/.config/fish/completions/your_program.fish
+            //! 		```
+            //! 
+            //! 	 1. **elvish**
+            //! 		```console
+            //! 		$ your_program --bpaf-complete-style-elvish >> ~/.config/elvish/rc.elv
+            //! 		```
+            //! 
+            //! 4. Restart your shell - you need to done it only once or optionally after bpaf major version
+            //!     upgrade: generated completion files contain only instructions how to ask your program for
+            //!     possible completions and don’t change even if options are different.
+            //! 
+            //! 
+            //! 5. Generated scripts rely on your program being accessible in $PATH
+            //! 
+            //! 
+            //! 
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Testing your parsers](super::_0_testing)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; HOWTO - practical, oriented to solving problems guides &uarr;](super::super::_2_howto)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+    use crate::*;
+    }
+    pub mod _3_cookbook {
+        //! &nbsp;
+        //! 
+        //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+        //!   <td style='width: 33%; text-align: left;'>
+        //! 
+        //! [&larr; HOWTO - practical, oriented to solving problems guides](super::_2_howto)
+        //! 
+        //!   </td>
+        //!   <td style='width: 34%; text-align: center;'>
+        //! 
+        //! [&uarr; Project documentation &uarr;](super::super::_documentation)
+        //! 
+        //!   </td>
+        //!   <td style='width: 33%; text-align: right;'>
+        //! 
+        //! [Theory explanation &rarr;](super::_4_explanation)
+        //! 
+        //!   </td>
+        //! </tr></table>
+        //! 
+        //! #### Parsing cookbook
+        //! How to parse less frequent combinations
+        //! 
+        //! While `bpaf`'s design tries to cover the most common use cases, mostly
+        //! [posix conventions](https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/basedefs/V1_chap12.html),
+        //! it can also handle some more unusual requirements. It might come at the cost of having to write
+        //! more code, more confusing error messages or worse performance, but it will get the job done.
+        //!
+        //! - [`find(1)`: `find -exec commands -flags terminated by \;`](_00_find)
+        //! - [`dd(1)`: `dd if=/dev/zero of=/dev/null bs=1000`](_01_dd)
+        //! - [`Xorg(1)`: `Xorg +xinerama +extension name`](_02_xorg)
+        //! - [Command chaining](_03_command_chaining) - Lets you do things like `setup.py sdist bdist`: [command chaining](https://click.palletsprojects.com/en/7.x/commands/#multi-command-chaining)
+        //! - [Multi-value arguments: `--foo ARG1 ARG2 ARG3`](_04_multi_value)
+        //! - [Structure groups: `--foo --foo-1 ARG1 --foo-2 ARG2 --foo-3 ARG3`](_05_struct_groups)
+        //! - [Multi-value arguments with optional flags: `--foo ARG1 --flag --inner ARG2`](_06_multi_flag)
+        //! - [Skipping optional positional items if parsing or validation fails](_07_skip_positional)
+        //! - [Implementing cargo commands](_08_cargo_helper)
+        //! - [Numeric flags - compression levels like in zip](_09_numeric_flags)
+        //!
+        //! &nbsp;
+        //! 
+        //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+        //!   <td style='width: 33%; text-align: left;'>
+        //! 
+        //! [&larr; HOWTO - practical, oriented to solving problems guides](super::_2_howto)
+        //! 
+        //!   </td>
+        //!   <td style='width: 34%; text-align: center;'>
+        //! 
+        //! [&uarr; Project documentation &uarr;](super::super::_documentation)
+        //! 
+        //!   </td>
+        //!   <td style='width: 33%; text-align: right;'>
+        //! 
+        //! [Theory explanation &rarr;](super::_4_explanation)
+        //! 
+        //!   </td>
+        //! </tr></table>
+        //! 
+        pub mod _00_find {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [`dd(1)`: `dd if=/dev/zero of=/dev/null bs=1000` &rarr;](super::_01_dd)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### `find(1)`: `find -exec commands -flags terminated by \;`
+            //! 
+            //! An Example for `find` shows how to implement 3 different unusual options:
+            //! 
+            //! - an option with a long name but a single dash as a prefix: `-user bob`
+            //! - an option that captures everything until the next fixed character
+            //! - an option that takes a set of characters: `-mode -rw`, `mode /rw`
+            //! 
+            //! In all cases, long name with a single dash is implemented by the [`literal`] with
+            //! [`ParseAny::anywhere`](crate::parsers::ParseAny::anywhere) with some items made `adjacent` to it.
+            //! 
+            //! To parse `-user bob` this is simply literal `-user` adjacent to a positional item with `map` to
+            //! focus on the interesting part.
+            //! 
+            //! For `-exec more things here ;` this is a combination of literal `-exec`, followed by `many`
+            //! items that are not `;` parsed positionally with `any` followed by `;` - again with `any`, but
+            //! `literal` works too.
+            //! 
+            //! And lastly to parse mode - after the tag, we accept `any` to be able to handle a combination of
+            //! modes that may or may not start with `-` and use [`Parser::parse`] to parse them or fail.
+            //! 
+            //! All special cases are made optional with [`Parser::optional`], but [`Parser::fallback`] also
+            //! works.
+            //! 
+            #![cfg_attr(not(doctest), doc = include_str!("docs2/find.md"))]
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [`dd(1)`: `dd if=/dev/zero of=/dev/null bs=1000` &rarr;](super::_01_dd)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+        pub mod _01_dd {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; `find(1)`: `find -exec commands -flags terminated by \;`](super::_00_find)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [`Xorg(1)`: `Xorg +xinerama +extension name` &rarr;](super::_02_xorg)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### `dd(1)`: `dd if=/dev/zero of=/dev/null bs=1000`
+            //! 
+            //! This example implements syntax similar to `dd` command. The main idea is to implement something to
+            //! make it simple to make parsers for `PREFIX=SUFFIX`, where prefix is fixed for each parser - for
+            //! example `if=` or `of=` and suffix is parsed with usual [`FromStr`](std::str::FromStr) trait.
+            //! 
+            //! The function `tag` serves this purpose. It performs the following steps:
+            //! 
+            //! - consume any item that starts with a prefix at any argument position with [`any`] and
+            //!   [`ParseAny::anywhere`]
+            //! - attaches help message and custom metadata to make `--help` friendlier
+            //! - parses suffix with [`Parser::parse`]
+            //! 
+            //! The rest of the parser simply uses `tag` to parse a few of `dd` arguments
+            //! 
+            #![cfg_attr(not(doctest), doc = include_str!("docs2/dd.md"))]
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; `find(1)`: `find -exec commands -flags terminated by \;`](super::_00_find)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [`Xorg(1)`: `Xorg +xinerama +extension name` &rarr;](super::_02_xorg)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+        pub mod _02_xorg {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; `dd(1)`: `dd if=/dev/zero of=/dev/null bs=1000`](super::_01_dd)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Command chaining &rarr;](super::_03_command_chaining)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### `Xorg(1)`: `Xorg +xinerama +extension name`
+            //! 
+            //! This example implements syntax similar to used by `Xorg` or similar programs. As usual with
+            //! strange examples [`any`] serves an important role.
+            //! 
+            //! The example implements the following parsers:
+            //! 
+            //! - enable or disable an extension using `+ext name` and `-ext name` like syntax
+            //! - enable or disable specific extensions with syntax like `-xinerama` or `+backing`
+            //! 
+            //! Both parsers use [`any`] with [`ParseAny::anywhere`]
+            //! 
+            //! 
+            #![cfg_attr(not(doctest), doc = include_str!("docs2/xorg.md"))]
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; `dd(1)`: `dd if=/dev/zero of=/dev/null bs=1000`](super::_01_dd)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Command chaining &rarr;](super::_03_command_chaining)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+        pub mod _03_command_chaining {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; `Xorg(1)`: `Xorg +xinerama +extension name`](super::_02_xorg)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Multi-value arguments: `--foo ARG1 ARG2 ARG3` &rarr;](super::_04_multi_value)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Command chaining
+            //! Lets you do things like `setup.py sdist bdist`: [command chaining](https://click.palletsprojects.com/en/7.x/commands/#multi-command-chaining)
+            //! 
+            //! With [`adjacent`](crate::parsers::ParseCommand::adjacent)
+            //! `bpaf` allows you to have several commands side by side instead of being nested.
+            //! 
+            #![cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_command.md"))]
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; `Xorg(1)`: `Xorg +xinerama +extension name`](super::_02_xorg)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Multi-value arguments: `--foo ARG1 ARG2 ARG3` &rarr;](super::_04_multi_value)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+        pub mod _04_multi_value {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Command chaining](super::_03_command_chaining)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Structure groups: `--foo --foo-1 ARG1 --foo-2 ARG2 --foo-3 ARG3` &rarr;](super::_05_struct_groups)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Multi-value arguments: `--foo ARG1 ARG2 ARG3`
+            //! 
+            //! By default arguments take at most one value, you can create multi value options by using
+            //! [`adjacent`](crate::parsers::ParseCon::adjacent) modifier
+            //! 
+            #![cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_0.md"))]
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Command chaining](super::_03_command_chaining)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Structure groups: `--foo --foo-1 ARG1 --foo-2 ARG2 --foo-3 ARG3` &rarr;](super::_05_struct_groups)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+        pub mod _05_struct_groups {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Multi-value arguments: `--foo ARG1 ARG2 ARG3`](super::_04_multi_value)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Multi-value arguments with optional flags: `--foo ARG1 --flag --inner ARG2` &rarr;](super::_06_multi_flag)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Structure groups: `--foo --foo-1 ARG1 --foo-2 ARG2 --foo-3 ARG3`
+            //! 
+            //! Groups of options that can be specified multiple times. All such groups should be kept without
+            //! overwriting previous one.
+            //! 
+            //! ```console
+            //!  $ prometheus_sensors_exporter \
+            //!      \
+            //!      `# 2 physical sensors located on physycial different i2c bus or address` \
+            //!      --sensor \
+            //!          --sensor-device=tmp102 \
+            //!          --sensor-name="temperature_tmp102_outdoor" \
+            //!          --sensor-i2c-bus=0 \
+            //!          --sensor-i2c-address=0x48 \
+            //!      --sensor \
+            //!          --sensor-device=tmp102 \
+            //!          --sensor-name="temperature_tmp102_indoor" \
+            //!          --sensor-i2c-bus=1 \
+            //!          --sensor-i2c-address=0x49 \
+            //! ```
+            //! 
+            #![cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_1.md"))]
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Multi-value arguments: `--foo ARG1 ARG2 ARG3`](super::_04_multi_value)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Multi-value arguments with optional flags: `--foo ARG1 --flag --inner ARG2` &rarr;](super::_06_multi_flag)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+        pub mod _06_multi_flag {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Structure groups: `--foo --foo-1 ARG1 --foo-2 ARG2 --foo-3 ARG3`](super::_05_struct_groups)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Skipping optional positional items if parsing or validation fails &rarr;](super::_07_skip_positional)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Multi-value arguments with optional flags: `--foo ARG1 --flag --inner ARG2`
+            //! 
+            //! So you can parse things while parsing things. Not sure why you might need this, but you can
+            //! :)
+            //! 
+            #![cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_4.md"))]
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Structure groups: `--foo --foo-1 ARG1 --foo-2 ARG2 --foo-3 ARG3`](super::_05_struct_groups)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Skipping optional positional items if parsing or validation fails &rarr;](super::_07_skip_positional)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+        pub mod _07_skip_positional {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Multi-value arguments with optional flags: `--foo ARG1 --flag --inner ARG2`](super::_06_multi_flag)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Implementing cargo commands &rarr;](super::_08_cargo_helper)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Skipping optional positional items if parsing or validation fails
+            //! 
+            //! Combinations like [`Parser::optional`] and
+            //! [`ParseOptional::catch`](crate::parsers::ParseOptional::catch) allow to try to parse something
+            //! and then handle the error as if pase attempt never existed
+            //! 
+            #![cfg_attr(not(doctest), doc = include_str!("docs2/numeric_prefix.md"))]
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Multi-value arguments with optional flags: `--foo ARG1 --flag --inner ARG2`](super::_06_multi_flag)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Implementing cargo commands &rarr;](super::_08_cargo_helper)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+        pub mod _08_cargo_helper {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Skipping optional positional items if parsing or validation fails](super::_07_skip_positional)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Numeric flags - compression levels like in zip &rarr;](super::_09_numeric_flags)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Implementing cargo commands
+            //! 
+            //! With [`cargo_helper`](crate::batteries::cargo_helper) you can use your application as a `cargo` command.
+            //! You will need to enable `batteries` feature while importing `bpaf`.
+            //! 
+            #![cfg_attr(not(doctest), doc = include_str!("docs2/cargo_helper.md"))]
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Skipping optional positional items if parsing or validation fails](super::_07_skip_positional)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //! 
+            //! [Numeric flags - compression levels like in zip &rarr;](super::_09_numeric_flags)
+            //! 
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+        pub mod _09_numeric_flags {
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Implementing cargo commands](super::_08_cargo_helper)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //!   </td>
+            //! </tr></table>
+            //! 
+            //! #### Numeric flags - compression levels like in zip
+            //! 
+            //! While you can add flags in a usual way for compression levels using `short(1)`, `short(2)`, etc
+            //! combined with `req_flag`, you can also parse all of then using [`any`]
+            //! 
+            //! ```no_run
+            //! use bpaf::{doc::Style, *};
+            //! 
+            //! fn compression() -> impl Parser<usize> {
+            //!     any::<isize, _, _>("COMP", |x: isize| {
+            //!         if (-9..=-1).contains(&x) {
+            //!             Some(x.abs().try_into().unwrap())
+            //!         } else {
+            //!             None
+            //!         }
+            //!     })
+            //!     .metavar(&[
+            //!         ("-1", Style::Literal),
+            //!         (" to ", Style::Text),
+            //!         ("-9", Style::Literal),
+            //!     ])
+            //!     .help("Compression level")
+            //!     .anywhere()
+            //! }
+            //! 
+            //! fn main() {
+            //!     let opts = compression().to_options().run();
+            //! 
+            //!     println!("{:?}", opts);
+            //! }
+            //! ```
+            //!
+            //!
+            //! &nbsp;
+            //! 
+            //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+            //!   <td style='width: 33%; text-align: left;'>
+            //! 
+            //! [&larr; Implementing cargo commands](super::_08_cargo_helper)
+            //! 
+            //!   </td>
+            //!   <td style='width: 34%; text-align: center;'>
+            //! 
+            //! [&uarr; Parsing cookbook &uarr;](super::super::_3_cookbook)
+            //! 
+            //!   </td>
+            //!   <td style='width: 33%; text-align: right;'>
+            //!   </td>
+            //! </tr></table>
+            //! 
+        use crate::*;
+        }
+    use crate::*;
+    }
+    pub mod _4_explanation {
+        //! &nbsp;
+        //! 
+        //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+        //!   <td style='width: 33%; text-align: left;'>
+        //! 
+        //! [&larr; Parsing cookbook](super::_3_cookbook)
+        //! 
+        //!   </td>
+        //!   <td style='width: 34%; text-align: center;'>
+        //! 
+        //! [&uarr; Project documentation &uarr;](super::super::_documentation)
+        //! 
+        //!   </td>
+        //!   <td style='width: 33%; text-align: right;'>
+        //!   </td>
+        //! </tr></table>
+        //! 
+        //! #### Theory explanation
+        //! Theoretical information about abstractions used by the library, oriented for understanding
+        //! 
+        //! 
+        //! # Applicative functors, Category Theory? What is it about?
+        //! 
+        //! You don't need to read/understand this chapter in order to use the library but it might
+        //! help to understand what makes it tick.
+        //! 
+        //! `bpaf` uses ideas from functional proggramming, specifically Functor, Applicative and
+        //! Alternative to create a composable interface. Exposed API and the fact that individual
+        //! components obey certain laws ensures that any composition of parsers is valid even if it
+        //! doesn't make any sense.
+        //! 
+        //! ## Category theory
+        //! 
+        //! Category theory, also called Abstract Nonsense, is a general theory about mathematical
+        //! structures and their relations. *Category* in CT constists of two sorts of abstractions:
+        //! *objects* and *morphisms* along with some extra rules:
+        //! - objects don't expose any information other than the name and only serve as start and end points for morphisms
+        //! - morphisms must compose with associative composition
+        //! - there must be an *identity morphism* for every object that maps the object to itself
+        //! 
+        //! A simple example of a category would be a category where objects are Rust types (here: `u8` ..
+        //! `u64`) and morphisms are functions between those types (here: `a`, `b` and `c`):
+        //! 
+        //! ```rust
+        //! fn a(i: u8) -> u16 {
+        //!     3000 + i as u16
+        //! }
+        //! 
+        //! fn b(i: u16) -> u32 {
+        //!     40000 + i as u32
+        //! }
+        //! 
+        //! fn c(i: u32) -> u64 {
+        //!     40000 + i as u64
+        //! }
+        //! 
+        //! /// Identity morphism
+        //! fn id<T>(i: T) -> T {
+        //!     i
+        //! }
+        //! 
+        //! /// morphism composition:
+        //! /// `comp (a, comp(b, c))` gives the same results as `comp(comp(a, b), c)`
+        //! fn comp<F, G, A, B, C>(f: F, g: G) -> impl Fn(A) -> C
+        //! where
+        //!     F: Fn(A) -> B,
+        //!     G: Fn(B) -> C,
+        //! {
+        //!     move |i| g(f(i))
+        //! }
+        //! ```
+        //! 
+        //! ## Composition and decomposition
+        //! 
+        //! Decomposition is one of the keys to solving big problems - you break down big problem into a
+        //! bunch of small problems, solve them separately and compose back a solution. Decomposition is
+        //! not required by computers but makes it easier to think about a problem: magical number for
+        //! human short term memory is 7 plus minus 2 objects. Category theory, studies relations and
+        //! composition can be a valuable tool: after all decomposition only makes sense when you can
+        //! combine components back into a solution. Imperative algorithms that operate in terms of
+        //! mutating variables are harder decompose - individual pieces need to be aware of the variables,
+        //! functional and declarative approaches make it easier: calculating a sum of all the numbers in a
+        //! vector can be decomposed into running an iterator over it and applying `fold` to it: `fold`
+        //! doesn't need to know about iteration shape, iterator doesn't need to know about how values are
+        //! used.
+        //! 
+        //! In category theory you are not allowed to look inside the objects at all and can distinguish
+        //! between them only by means of the composition so as long as implemented API obeys the
+        //! restrictions set by category theory - it should be very composable.
+        //! 
+        //! ## Functors
+        //! 
+        //! Let's start by talking about what a `Functor` is. Wikipedia defines it as a "design pattern
+        //! that allows for a generic type to apply a function inside without changing the structure of
+        //! the generic type". Sounds scary, but in Rust terms it's a trait that takes a value or values
+        //! in a container (or more general *value in a context* ) such as `Option<A>` and a function
+        //! `fn(A) -> B` and gives you `Option<B>` back.
+        //! 
+        //! Closest analogy in a real code you can write in Rust right now would be modifying an `Option`
+        //! using only `Option::map`:
+        //! ```rust
+        //! fn plus_one(input: Option<u32>) -> Option<u32> {
+        //!     input.map(|i| i + 1)
+        //! }
+        //! 
+        //! let present = Some(10);
+        //! let absent = None;
+        //! 
+        //! assert_eq!(plus_one(present), Some(11));
+        //! assert_eq!(plus_one(absent), None);
+        //! ```
+        //! 
+        //! `Vec`, `Result` and other types that implement `map` are `Functors` as well, but `Functor`
+        //! is not limited just to containers - you don't have to have a value inside to be able to
+        //! manipulate it. In fact a regular rust function is also a `Functor` if you squint hard enough.
+        //! Consider `Reader` that allows you to perform transformations on a *value in a context* `T`
+        //! without having any value until it the execution time:
+        //! 
+        //! ```rust
+        //! struct Reader<T>(Box<dyn Fn(T) -> T>);
+        //! impl<T: 'static> Reader<T> {
+        //!     /// Initialize an new value in a context
+        //!     fn new() -> Self {
+        //!         Self(Box::new(|x| x))
+        //!     }
+        //! 
+        //!     /// Modify a value in a context
+        //!     fn map<F:  Fn(T) -> T + 'static>(self, f: F) -> Self {
+        //!         Self(Box::new(move |x| f((self.0)(x))))
+        //!     }
+        //! 
+        //!     /// Apply the changes by giving it the initial value
+        //!     fn run(self, input: T) -> T {
+        //!         (self.0)(input)
+        //!     }
+        //! }
+        //! 
+        //! let val = Reader::<u32>::new();
+        //! let val = val.map(|x| x + 1);
+        //! let res = val.run(10);
+        //! assert_eq!(res, 11);
+        //! ```
+        //! 
+        //! Not all the collections are `Functors` - by `Functor` laws mapping the *value in context*
+        //! shouldn't change the shape so any collections where shape depends on a value, such as `HashSet`
+        //! or `BTreeSet` are out.
+        //! 
+        //! ## Applicative Functors
+        //! 
+        //! `map` in `Functor` is limited to a single *value in a context*, `Applicative Functor` extends it
+        //! to operations combining multiple values, closest Rust analogy would be doing computations on
+        //! `Option` or `Result` using only `?`, having `Some`/`Ok` around the whole expression and not using `return`.
+        //! ```rust
+        //! fn add_numbers(input_a: Option<u32>, input_b: Option<u32>) -> Option<u32> {
+        //!     Some(input_a? + input_b?)
+        //! }
+        //! 
+        //! let present_1 = Some(10);
+        //! let present_2 = Some(20);
+        //! let absent = None;
+        //! 
+        //! assert_eq!(add_numbers(present_1, present_2), Some(30));
+        //! assert_eq!(add_numbers(present_1, absent), None);
+        //! assert_eq!(add_numbers(absent, absent), None);
+        //! ```
+        //! 
+        //! Similarly to `Functors`, `Applicative Functors` are not limited to containers and can
+        //! represent *a value in an arbitrary context*.
+        //! 
+        //! `Try` trait (`?`) for `Option` and `Result` short circuits when it finds a missing value,
+        //! but `Applicative Functors` in general don't have to - in fact to implement dynamic completion
+        //! `bpaf` needs to check items past the first failure point to collect all the possible
+        //! completions.
+        //! 
+        //! ## Alternative Functors
+        //! 
+        //! So far `Applicative Functors` allow us to create structs containing multiple fields out of
+        //! individual parsers for each field. `Alternative` extends `Applicative` with two extra
+        //! things: one for combining two *values in a context* into one and and an idenity element
+        //! for this operation. In Rust a closest analogy would be `Option::or` and `Option::None`:
+        //! 
+        //! ```rust
+        //! fn pick_number(a: Option<u32>, b: Option<u32>) -> Option<u32> {
+        //!     a.or(b)
+        //! }
+        //! 
+        //! let present_1 = Some(10);
+        //! let present_2 = Some(20);
+        //! let empty = None;
+        //! assert_eq!(pick_number(present_1, present_2), present_1);
+        //! assert_eq!(pick_number(present_1, empty), present_1);
+        //! assert_eq!(pick_number(empty, present_1), present_1);
+        //! assert_eq!(pick_number(empty, empty), empty);
+        //! ```
+        //! 
+        //! ## `Parser` trait and `construct!` macro
+        //! 
+        //! [`Parser`] trait defines a context for values and gives access to `Functor` laws and [`construct!`]
+        //! macro allows to compose several values according to `Applicative` and `Alternative` laws.
+        //! 
+        //! ## So why use `Applicative Functors` then?
+        //! 
+        //! As a user I want to be able to express requirements using full power of Rust algebraic
+        //! datatypes: `struct` for product types and `enum` for sum types. To give an example -
+        //! `cargo-show-asm` asks user to specify what to output - Intel or AT&T asm, LLVM or Rust's MIR
+        //! and opts to represent it as one of four flags: `--intel`, `--att`, `--llvm` and `--mir`. While
+        //! each flag can be though of a boolean value - present/absent - consuming it as an `enum` with four
+        //! possible values is much more convenient compared to a struct-like thing that can have any
+        //! combination of the flags inside:
+        //! 
+        //! ```no_check
+        //! /// Format selection as enum - program needs to deal with just one format
+        //! enum Format {
+        //!     Intel,
+        //!     Att,
+        //!     Llvm,
+        //!     Mir
+        //! }
+        //! 
+        //! /// Format selection as struct - can represent any possible combination of formats
+        //! struct Formats {
+        //!     intel: bool,
+        //!     att: bool,
+        //!     llvm: bool,
+        //!     mir: bool,
+        //! }
+        //! ```
+        //! 
+        //! `Applicative` interface gives just enough power to compose simple parsers as an arbitrary tree
+        //! ready for consumption.
+        //! 
+        //! As a library author I need to be able to extract information from the tree constructed by user
+        //! to generate `--help` information and do command line completion. As long as the tree uses only
+        //! `Applicative` powers - it is possible to evaluate it without giving it any input.
+        //! Adding `Monadic` powers (deciding what to parse next depending on the previous input) would
+        //! make this impossible.
+        //! 
+        //! So `Applicative Functors` sits right in the middle between what users want to express and
+        //! library can consume.
+        //! 
+        //! To recap - all sorts of Functors listed here only define laws to how individual parts are
+        //! composed, how values in context can be transformed and how pure values can be turned into a
+        //! functor, but not how the values are parsed or how they can be extracted.
+        //! 
+        //! ## Putting the values into a context
+        //! 
+        //! Similarly to how `Reader` defined above `bpaf`'s `Parsers` don't actually have values inside
+        //! until they are executed. Instead starting points ([`flag`](NamedArg::flag), [`positional`],
+        //! [`argument`](NamedArg::argument), etc) define what exactly needs to be consumed, various mapping
+        //! functions define transformations, [`construct!`] composes them and defines the relative order
+        //! values should be consumed. Not everything present inside [`Parser`] can be repesented in terms
+        //! of plain applicative functors - specifically [`parse`](Parser::parse) is not and it is best
+        //! though of as a function that takes one applicative and gives a different applicative back.
+        //! The actual values will show up inside once `bpaf` starts running the [`OptionParser`] with
+        //! [`run`](OptionParser::run).
+        //! 
+        //! ## Taking the results out
+        //! 
+        //! The rest of the execution is relatively simple: getting console arguments from OS, doing the
+        //! initial split into short/long flags and standalone words, disambiguating groups of short
+        //! options from short options with attached values and applying all the transformations like
+        //! `Reader::run` above would do.
+        //!
+        //!
+        //! &nbsp;
+        //! 
+        //! <table width='100%' cellspacing='0' style='border: hidden;'><tr>
+        //!   <td style='width: 33%; text-align: left;'>
+        //! 
+        //! [&larr; Parsing cookbook](super::_3_cookbook)
+        //! 
+        //!   </td>
+        //!   <td style='width: 34%; text-align: center;'>
+        //! 
+        //! [&uarr; Project documentation &uarr;](super::super::_documentation)
+        //! 
+        //!   </td>
+        //!   <td style='width: 33%; text-align: right;'>
+        //!   </td>
+        //! </tr></table>
+        //! 
+    use crate::*;
+    }
+use crate::*;
+
\ No newline at end of file diff --git a/src/bpaf/arg.rs.html b/src/bpaf/arg.rs.html new file mode 100644 index 00000000..1f70ac41 --- /dev/null +++ b/src/bpaf/arg.rs.html @@ -0,0 +1,551 @@ +arg.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+
use std::ffi::{OsStr, OsString};
+
+/// Preprocessed command line argument
+///
+/// [`OsString`] in Short/Long correspond to orignal command line item used for errors
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub(crate) enum Arg {
+    /// short flag: `-f`
+    ///
+    /// bool indicates if following item is also part of this Short (created
+    Short(char, bool, OsString),
+
+    /// long flag: `--flag`
+    /// bool tells if it looks like --key=val or not
+    Long(String, bool, OsString),
+
+    /// "val" part of --key=val -k=val -kval
+    ArgWord(OsString),
+
+    /// separate word that can be command, positional or a separate argument to a flag
+    ///
+    /// Can start with `-` or `--`, doesn't have to be valid utf8
+    ///
+    /// `hello`
+    Word(OsString),
+
+    /// separate word that goes after `--`, strictly positional
+    ///
+    /// Can start with `-` or `--`, doesn't have to be valid utf8
+    PosWord(OsString),
+}
+
+impl Arg {
+    pub(crate) fn os_str(&self) -> &OsStr {
+        match self {
+            Arg::Short(_, _, s)
+            | Arg::Long(_, _, s)
+            | Arg::ArgWord(s)
+            | Arg::Word(s)
+            | Arg::PosWord(s) => s.as_ref(),
+        }
+    }
+
+    pub(crate) fn match_short(&self, val: char) -> bool {
+        match self {
+            Arg::Short(s, _, _) => *s == val,
+            Arg::ArgWord(_) | Arg::Long(_, _, _) | Arg::Word(_) | Arg::PosWord(_) => false,
+        }
+    }
+
+    pub(crate) fn match_long(&self, val: &str) -> bool {
+        match self {
+            Arg::Long(s, _, _) => *s == val,
+            Arg::Short(_, _, _) | Arg::ArgWord(_) | Arg::Word(_) | Arg::PosWord(_) => false,
+        }
+    }
+}
+
+// short flag disambiguations:
+//
+// Short flags | short arg
+// No          | No        | no problem
+// Yes         | No        | use flag
+// No          | Yes       | use arg
+// Yes         | Yes       | ask user?
+//
+// -a  - just a regular short flag: "-a"
+// -abc - assuming there are short flags a, b and c: "-a -b -c", assuming utf8 values AND there's no argument -a
+// -abc - assuming there's no -a -b -c: "-a bc"
+// -abc - assuming both short a b c AND there's argument -a - need to disambiguate  on a context level
+//
+// 1. parse argument into ambigous representation that can store both short flags and argument
+// 2. collect short flag/arg when entering the subparsre
+// 3. when reaching ambi
+//
+
+impl std::fmt::Display for Arg {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Arg::Short(s, _, _) => write!(f, "-{}", s),
+            Arg::Long(l, _, _) => write!(f, "--{}", l),
+            Arg::ArgWord(w) | Arg::Word(w) | Arg::PosWord(w) => {
+                write!(f, "{}", w.to_string_lossy())
+            }
+        }
+    }
+}
+
+#[derive(Eq, PartialEq, Debug)]
+pub(crate) enum ArgType {
+    Short,
+    Long,
+}
+
+/// split [`OsString`] into argument specific bits
+///
+/// takes a possibly non-utf8 string looking like "--name=value" and splits it into bits:
+/// "--" - type, "name" - name, must be representable as utf8, "=" - optional, "value" - flag
+///
+/// dashes and equals sign are low codepoint values and - can look for them literally in a string.
+/// This probably means not supporting dashes with diacritics, but that's okay
+///
+/// name must be valid utf8 after conversion and must not include `=`
+///
+/// argument is optional and can be non valid utf8.
+///
+/// The idea is to split the [`OsString`] into opaque parts by looking only at the parts simple parts
+/// and let stdlib to handle the decoding of those parts.
+///
+/// performance wise this (at least on unix) works some small number percentage slower than the
+/// previous version
+///
+///
+/// Notation -fbar is ambigous and could mean either `-f -b -a -r` or `-f=bar`, resolve it into
+/// [`Arg::Ambiguity`] and let subparser disambiguate it later depending on available short flag and
+/// arguments
+pub(crate) fn split_os_argument(input: &std::ffi::OsStr) -> Option<(ArgType, String, Option<Arg>)> {
+    #[cfg(any(unix, windows))]
+    {
+        // OsString are sequences of smaller smaller elements - bytes in unix and
+        // possibly invalid utf16 items on windows
+        #[cfg(unix)]
+        type Elt = u8;
+        #[cfg(windows)]
+        type Elt = u16;
+
+        // reuse allocation on unix, don't reuse allocations on windows
+        // either case - pack a vector of elements back into OsString
+        fn os_from_vec(vec: Vec<Elt>) -> OsString {
+            #[cfg(unix)]
+            {
+                <OsString as std::os::unix::ffi::OsStringExt>::from_vec(vec)
+            }
+            #[cfg(windows)]
+            {
+                <OsString as std::os::windows::ffi::OsStringExt>::from_wide(&vec)
+            }
+        }
+
+        // try to decode elements into a String
+        fn str_from_vec(vec: Vec<Elt>) -> Option<String> {
+            Some(os_from_vec(vec).to_str()?.to_owned())
+        }
+
+        // but in either case dashes and equals are just literal values just with different width
+        const DASH: Elt = b'-' as Elt;
+        const EQUALS: Elt = b'=' as Elt;
+
+        // preallocate something to store the name. oversized but avoids extra allocations/copying
+        let mut name = Vec::with_capacity(input.len());
+
+        let mut items;
+        #[cfg(unix)]
+        {
+            items = std::os::unix::ffi::OsStrExt::as_bytes(input)
+                .iter()
+                .copied();
+        }
+        #[cfg(windows)]
+        {
+            items = std::os::windows::ffi::OsStrExt::encode_wide(input);
+        }
+
+        // first item must be dash, otherwise it's positional or a flag value
+        if items.next()? != DASH {
+            return None;
+        }
+
+        // second item may or may not be, but should be present
+        let ty;
+        match items.next()? {
+            DASH => ty = ArgType::Long,
+            val => {
+                ty = ArgType::Short;
+                name.push(val);
+            }
+        }
+
+        // keep collecting until = or the end of the input
+        loop {
+            match items.next() {
+                Some(EQUALS) => {
+                    if ty == ArgType::Short && name.len() > 1 {
+                        let mut body = name.drain(1..).collect::<Vec<_>>();
+                        body.push(EQUALS);
+                        body.extend(items);
+                        name.truncate(1);
+                        let os = Arg::ArgWord(os_from_vec(body));
+                        return Some((ty, str_from_vec(name)?, Some(os)));
+                    }
+                    break;
+                }
+                Some(val) => name.push(val),
+                None => {
+                    if name.is_empty() {
+                        return None;
+                    }
+                    return Some((ty, str_from_vec(name)?, None));
+                }
+            }
+        }
+
+        let name = str_from_vec(name)?;
+        let word = {
+            let os = os_from_vec(items.collect());
+            Arg::ArgWord(os)
+        };
+        Some((ty, name, Some(word)))
+    }
+    #[cfg(not(any(unix, windows)))]
+    {
+        split_os_argument_fallback(input)
+    }
+}
+
+/// similar to [`split_os_argument`] but only works for utf8 values, used as a fallback function
+/// on non windows/unix OSes
+#[cfg(any(all(not(windows), not(unix)), test))]
+pub(crate) fn split_os_argument_fallback(
+    input: &std::ffi::OsStr,
+) -> Option<(ArgType, String, Option<Arg>)> {
+    // fallback supports only valid utf8 os strings, matches old behavior
+    let string = input.to_str()?;
+
+    let mut chars = string.chars();
+    let mut name = String::with_capacity(string.len());
+
+    // first character must be dash, otherwise it's positional or a flag value
+    if chars.next()? != '-' {
+        return None;
+    }
+
+    // second character may or may not be
+    let ty;
+    match chars.next()? {
+        '-' => ty = ArgType::Long,
+        val => {
+            ty = ArgType::Short;
+            name.push(val);
+        }
+    }
+
+    // collect the argument's name up to '=' or until the end
+    // if it's a flag
+    loop {
+        match chars.next() {
+            Some('=') => {
+                if ty == ArgType::Short && name.len() > 1 {
+                    let mut body = name.drain(1..).collect::<String>();
+                    body.push('=');
+                    body.extend(chars);
+                    name.truncate(1);
+                    let os = Arg::ArgWord(OsString::from(body));
+                    return Some((ty, name, Some(os)));
+                }
+                break;
+            }
+
+            Some(val) => name.push(val),
+            None => {
+                if name.is_empty() {
+                    return None;
+                }
+                return Some((ty, name, None));
+            }
+        }
+    }
+
+    Some((
+        ty,
+        name,
+        Some(Arg::ArgWord(OsString::from(chars.collect::<String>()))),
+    ))
+}
+
\ No newline at end of file diff --git a/src/bpaf/args.rs.html b/src/bpaf/args.rs.html new file mode 100644 index 00000000..5fc2ba9d --- /dev/null +++ b/src/bpaf/args.rs.html @@ -0,0 +1,1891 @@ +args.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+
use std::ffi::OsString;
+
+pub(crate) use crate::arg::*;
+use crate::{
+    error::{Message, MissingItem},
+    item::Item,
+    meta_help::Metavar,
+    parsers::NamedArg,
+    Error,
+};
+
+/// All currently present command line parameters with some extra metainfo
+///
+/// Use it for unit tests and manual parsing. For production use you would want to replace the
+/// program name with [`set_name`](Args::set_name), but for tests passing a slice of strings to
+/// [`run_inner`](crate::OptionParser::run_inner) is usually more convenient.
+///
+///
+/// The easiest way to create `Args` is by using its `From` instance.
+/// ```rust
+/// # use bpaf::*;
+/// let parser = short('f')
+///     .switch()
+///     .to_options();
+/// let value = parser
+///     .run_inner(Args::from(&["-f"]))
+///     .unwrap();
+/// assert!(value);
+///
+/// // this also works
+/// let value = parser.run_inner(&["-f"])
+///     .unwrap();
+/// assert!(value);
+/// ```
+pub struct Args<'a> {
+    items: Box<dyn ExactSizeIterator<Item = OsString> + 'a>,
+    name: Option<String>,
+    #[cfg(feature = "autocomplete")]
+    c_rev: Option<usize>,
+}
+
+impl Args<'_> {
+    /// Enable completions with custom output revision style
+    ///
+    /// Use revision 0 if you want to test completion mechanism
+    ///
+    /// ```rust
+    /// # use bpaf::*;
+    /// let parser = short('f').switch().to_options();
+    /// // ask bpaf to produce more input from "-", for
+    /// // suggesting new items use "" at the end
+    /// let r = parser.run_inner(Args::from(&["-"])
+    ///     .set_comp(0))
+    ///     .unwrap_err()
+    ///     .unwrap_stdout();
+    /// assert_eq!(r, "-f");
+    /// ```
+    #[cfg(feature = "autocomplete")]
+    #[must_use]
+    pub fn set_comp(mut self, rev: usize) -> Self {
+        self.c_rev = Some(rev);
+        self
+    }
+
+    /// Add an application name for args created from custom input
+    /// ```rust
+    /// # use bpaf::*;
+    /// let parser = short('f').switch().to_options();
+    /// let r = parser
+    ///     .run_inner(Args::from(&["--help"]).set_name("my_app"))
+    ///     .unwrap_err()
+    ///     .unwrap_stdout();
+    /// # drop(r);
+    /// ```
+    #[must_use]
+    pub fn set_name(mut self, name: &str) -> Self {
+        self.name = Some(name.to_owned());
+        self
+    }
+}
+
+impl<const N: usize> From<&'static [&'static str; N]> for Args<'_> {
+    fn from(value: &'static [&'static str; N]) -> Self {
+        Self {
+            items: Box::new(value.iter().map(OsString::from)),
+            #[cfg(feature = "autocomplete")]
+            c_rev: None,
+            name: None,
+        }
+    }
+}
+
+impl<'a> From<&'a [&'a std::ffi::OsStr]> for Args<'a> {
+    fn from(value: &'a [&'a std::ffi::OsStr]) -> Self {
+        Self {
+            items: Box::new(value.iter().map(OsString::from)),
+            #[cfg(feature = "autocomplete")]
+            c_rev: None,
+            name: None,
+        }
+    }
+}
+
+impl<'a> From<&'a [&'a str]> for Args<'a> {
+    fn from(value: &'a [&'a str]) -> Self {
+        Self {
+            items: Box::new(value.iter().map(OsString::from)),
+            #[cfg(feature = "autocomplete")]
+            c_rev: None,
+            name: None,
+        }
+    }
+}
+
+impl<'a> From<&'a [String]> for Args<'a> {
+    fn from(value: &'a [String]) -> Self {
+        Self {
+            items: Box::new(value.iter().map(OsString::from)),
+            #[cfg(feature = "autocomplete")]
+            c_rev: None,
+            name: None,
+        }
+    }
+}
+
+impl<'a> From<&'a [OsString]> for Args<'a> {
+    fn from(value: &'a [OsString]) -> Self {
+        Self {
+            items: Box::new(value.iter().map(OsString::from)),
+            #[cfg(feature = "autocomplete")]
+            c_rev: None,
+            name: None,
+        }
+    }
+}
+
+impl Args<'_> {
+    /// Get a list of command line arguments from OS
+    #[must_use]
+    pub fn current_args() -> Self {
+        let mut value = std::env::args_os();
+        let name = value.next().and_then(|n| {
+            let path = std::path::PathBuf::from(n);
+            let file_name = path.file_name()?;
+            let s = file_name.to_str()?;
+            Some(s.to_owned())
+        });
+        Self {
+            items: Box::new(value),
+            #[cfg(feature = "autocomplete")]
+            c_rev: None,
+            name,
+        }
+    }
+}
+
+/// Shows which branch of [`ParseOrElse`] parsed the argument
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub(crate) enum ItemState {
+    /// Value is yet to be parsed
+    Unparsed,
+    /// Both branches succeeded, first parser was taken in favor of the second one
+    Conflict(usize),
+    /// Value was parsed
+    Parsed,
+}
+
+impl ItemState {
+    pub(crate) fn parsed(&self) -> bool {
+        match self {
+            ItemState::Unparsed | ItemState::Conflict(_) => false,
+            ItemState::Parsed => true,
+        }
+    }
+    pub(crate) fn present(&self) -> bool {
+        match self {
+            ItemState::Unparsed | ItemState::Conflict(_) => true,
+            ItemState::Parsed => false,
+        }
+    }
+}
+
+fn disambiguate_short(
+    mut os: OsString,
+    short: String,
+    short_flags: &[char],
+    short_args: &[char],
+    items: &mut Vec<Arg>,
+) -> Option<Message> {
+    // block can start with 0 or more short flags
+    // followed by zero or one short argument, possibly with a body
+
+    // keep the old length around so we can trimp items to it and push a Arg::Word
+    // if we decide to give up
+    let original = items.len();
+
+    // first flag contains the original os string for error message and anywhere purposes
+    let mut first_flag = os.clone();
+
+    for (ix, c) in short.char_indices() {
+        let tail_ix = ix + c.len_utf8();
+        let rest = &short[tail_ix..];
+
+        // shortcircuit single character short options
+        if ix == 0 && rest.is_empty() {
+            items.push(Arg::Short(c, false, std::mem::take(&mut first_flag)));
+            return None;
+        }
+        match (short_flags.contains(&c), short_args.contains(&c)) {
+            // short name that can be flag
+            (true, false) => {
+                items.push(Arg::Short(c, false, std::mem::take(&mut first_flag)));
+            }
+
+            // short name that can be argument
+            (false, true) => {
+                let adjacent_body = !rest.is_empty();
+                items.push(Arg::Short(c, adjacent_body, std::mem::take(&mut os)));
+                if adjacent_body {
+                    items.push(Arg::Word(rest.into()));
+                }
+                return None;
+            }
+
+            // neither is valid and there's more than one character. fallback to using it as a Word
+            (false, false) => {
+                items.truncate(original);
+                items.push(Arg::Word(os));
+                return None;
+            }
+
+            // ambiguity, this is bad
+            (true, true) => {
+                let msg = Message::Ambiguity(items.len(), short);
+                items.push(Arg::Word(std::mem::take(&mut os)));
+                return Some(msg);
+            }
+        }
+    }
+    None
+}
+
+pub use inner::State;
+/// Hides [`State`] internal implementation
+mod inner {
+    use std::{ops::Range, rc::Rc};
+
+    use crate::{error::Message, item::Item, Args};
+
+    use super::{split_os_argument, Arg, ArgType, ItemState};
+    #[derive(Clone, Debug)]
+    #[doc(hidden)]
+    pub struct State {
+        /// list of all available command line arguments, in `Rc` for cheap cloning
+        pub(crate) items: Rc<[Arg]>,
+
+        item_state: Vec<ItemState>,
+
+        /// performance optimization mostly - tracks removed item and gives cheap is_empty and len
+        remaining: usize,
+
+        #[doc(hidden)]
+        /// Used to render an error message for [`parse`][crate::Parser::parse]
+        /// contains an index of a currently consumed item if we are parsing a single
+        /// item
+        pub current: Option<usize>,
+
+        /// path to current command, "deeper" parser should win in or_else branches
+        pub(crate) path: Vec<String>,
+
+        #[cfg(feature = "autocomplete")]
+        comp: Option<crate::complete_gen::Complete>,
+
+        //        /// A way to customize behavior for --help and error handling
+        //        pub(crate) improve_error: super::Improve,
+        /// Describes scope current parser will be consuming elements from. Usually it will be
+        /// considering the whole sequence of (unconsumed) arguments, but for "adjacent"
+        /// scope starts on the right of the first consumed item and might end before the end
+        /// of the list, similarly for "commands"
+        scope: Range<usize>,
+    }
+
+    impl State {
+        /// Check if item at ixth position is still present (was not parsed)
+        pub(crate) fn present(&self, ix: usize) -> Option<bool> {
+            Some(self.item_state.get(ix)?.present())
+        }
+
+        pub(crate) fn depth(&self) -> usize {
+            self.path.len()
+        }
+    }
+
+    pub(crate) struct ArgsIter<'a> {
+        args: &'a State,
+        cur: usize,
+    }
+
+    impl State {
+        #[cfg(feature = "autocomplete")]
+        pub(crate) fn check_no_pos_ahead(&self) -> bool {
+            self.comp.as_ref().map_or(false, |c| c.no_pos_ahead)
+        }
+
+        #[cfg(feature = "autocomplete")]
+        pub(crate) fn set_no_pos_ahead(&mut self) {
+            if let Some(comp) = &mut self.comp {
+                comp.no_pos_ahead = true;
+            }
+        }
+
+        #[allow(clippy::too_many_lines)] // it's relatively simple.
+        pub(crate) fn construct(
+            args: Args,
+            short_flags: &[char],
+            short_args: &[char],
+            err: &mut Option<Message>,
+        ) -> State {
+            let mut items = Vec::new();
+            let mut pos_only = false;
+            let mut double_dash_marker = None;
+
+            #[cfg(feature = "autocomplete")]
+            let mut comp_scanner = crate::complete_run::ArgScanner {
+                revision: args.c_rev,
+                name: args.name.as_deref(),
+            };
+
+            for os in args.items {
+                if pos_only {
+                    items.push(Arg::PosWord(os));
+                    continue;
+                }
+
+                #[cfg(feature = "autocomplete")]
+                if comp_scanner.check_next(&os) {
+                    continue;
+                }
+
+                match split_os_argument(&os) {
+                    // -f and -fbar, but also -vvvvv
+                    Some((ArgType::Short, short, None)) => {
+                        if let Some(msg) = super::disambiguate_short(
+                            os,
+                            short,
+                            short_flags,
+                            short_args,
+                            &mut items,
+                        ) {
+                            *err = Some(msg);
+                            break;
+                        }
+                    }
+                    Some((ArgType::Short, short, Some(arg))) => {
+                        let mut chars = short.chars();
+                        items.push(Arg::Short(chars.next().unwrap(), true, os));
+                        items.push(arg);
+                    }
+                    // --key and --key=val
+                    Some((ArgType::Long, long, arg)) => {
+                        items.push(Arg::Long(long, arg.is_some(), os));
+                        if let Some(arg) = arg {
+                            items.push(arg);
+                        }
+                    }
+                    // something that is not a short or long flag, keep them as positionals
+                    // handle "--" specifically as "end of flags" marker
+                    None => {
+                        if os == "--" {
+                            double_dash_marker = Some(items.len());
+                            pos_only = true;
+                        }
+                        items.push(if pos_only {
+                            Arg::PosWord(os)
+                        } else {
+                            Arg::Word(os)
+                        });
+                    }
+                }
+            }
+
+            let mut item_state = vec![ItemState::Unparsed; items.len()];
+            let mut remaining = items.len();
+            if let Some(ix) = double_dash_marker {
+                item_state[ix] = ItemState::Parsed;
+                remaining -= 1;
+
+                #[cfg(feature = "autocomplete")]
+                if comp_scanner.revision.is_some() && ix == items.len() - 1 {
+                    remaining += 1;
+                    item_state[ix] = ItemState::Unparsed;
+                }
+            }
+
+            let mut path = Vec::new();
+
+            #[cfg(feature = "autocomplete")]
+            let comp = comp_scanner.done();
+
+            if let Some(name) = args.name {
+                path.push(name);
+            }
+            State {
+                item_state,
+                remaining,
+                scope: 0..items.len(),
+                items: items.into(),
+                current: None,
+                path,
+                #[cfg(feature = "autocomplete")]
+                comp,
+            }
+        }
+    }
+
+    impl<'a> State {
+        /// creates iterator over remaining elements
+        pub(crate) fn items_iter(&'a self) -> ArgsIter<'a> {
+            ArgsIter {
+                args: self,
+                cur: self.scope.start,
+            }
+        }
+
+        pub(crate) fn remove(&mut self, index: usize) {
+            if self.scope.contains(&index) && self.item_state[index].present() {
+                self.current = Some(index);
+                self.remaining -= 1;
+                self.item_state[index] = ItemState::Parsed;
+            }
+        }
+
+        pub(crate) fn pick_winner(&self, other: &Self) -> (bool, Option<usize>) {
+            for (ix, (me, other)) in self
+                .item_state
+                .iter()
+                .zip(other.item_state.iter())
+                .enumerate()
+            {
+                if me.parsed() ^ other.parsed() {
+                    return (me.parsed(), Some(ix));
+                }
+            }
+            (true, None)
+        }
+
+        /// find first saved conflict
+        pub(crate) fn conflict(&self) -> Option<(usize, usize)> {
+            let (ix, _item) = self.items_iter().next()?;
+            if let ItemState::Conflict(other) = self.item_state.get(ix)? {
+                Some((ix, *other))
+            } else {
+                None
+            }
+        }
+
+        pub(crate) fn save_conflicts(&mut self, loser: &State, win: usize) {
+            for (winner, loser) in self.item_state.iter_mut().zip(loser.item_state.iter()) {
+                if winner.present() && loser.parsed() {
+                    *winner = ItemState::Conflict(win);
+                }
+            }
+        }
+
+        #[allow(dead_code)]
+        // it is in use when autocomplete is enabled
+        pub(crate) fn is_empty(&self) -> bool {
+            self.remaining == 0
+        }
+
+        pub(crate) fn len(&self) -> usize {
+            self.remaining
+        }
+
+        /// Get an argument from a scope that was not consumed yet
+        pub(crate) fn get(&self, ix: usize) -> Option<&Arg> {
+            if self.scope.contains(&ix) && self.item_state.get(ix)?.present() {
+                Some(self.items.get(ix)?)
+            } else {
+                None
+            }
+        }
+
+        #[cfg(feature = "autocomplete")]
+        /// Check if parser performs autocompletion
+        ///
+        /// used by construct macro
+        #[must_use]
+        pub fn is_comp(&self) -> bool {
+            self.comp.is_some()
+        }
+
+        /// Narrow down scope of &self to adjacently consumed values compared to original.
+        pub(crate) fn adjacent_scope(&self, original: &State) -> Option<Range<usize>> {
+            if self.items.is_empty() {
+                return None;
+            }
+
+            // starting at the beginning of the scope look for the first mismatch
+            let start = self.scope().start;
+            for (mut offset, (this, orig)) in self.item_state[start..]
+                .iter()
+                .zip(original.item_state[start..].iter())
+                .enumerate()
+            {
+                offset += start;
+                // once there's a mismatch we have the scope we are looking for:
+                // all the adjacent items consumed in this. It doesn't make sense to remove it if
+                // it matches the original scope though...
+                if this.present() && orig.present() {
+                    let proposed_scope = start..offset;
+                    return if self.scope() == proposed_scope {
+                        None
+                    } else {
+                        Some(proposed_scope)
+                    };
+                }
+            }
+            None
+        }
+
+        /// Get a scope for an adjacently available block of item starting at start
+        pub(crate) fn adjacently_available_from(&self, start: usize) -> Range<usize> {
+            let span_size = self
+                .item_state
+                .iter()
+                .copied()
+                .skip(start)
+                .take_while(ItemState::present)
+                .count();
+            start..start + span_size
+        }
+
+        pub(crate) fn ranges(&'a self, item: &'a Item) -> ArgRangesIter<'a> {
+            let width = match item {
+                Item::Any { .. }
+                | Item::Positional { .. }
+                | Item::Command { .. }
+                | Item::Flag { .. } => 1,
+                Item::Argument { .. } => 2,
+            };
+            ArgRangesIter {
+                args: self,
+                cur: 0,
+                width,
+            }
+        }
+
+        pub(crate) fn scope(&self) -> Range<usize> {
+            self.scope.clone()
+        }
+
+        /// Mark everything outside of `range` as removed
+        pub(crate) fn set_scope(&mut self, scope: Range<usize>) {
+            self.scope = scope;
+            self.remaining = self.item_state[self.scope()]
+                .iter()
+                .copied()
+                .filter(ItemState::present)
+                .count();
+        }
+
+        #[cfg(feature = "autocomplete")]
+        /// check if bpaf tries to complete last consumed element
+        pub(crate) fn touching_last_remove(&self) -> bool {
+            self.comp.is_some() && self.items.len() - 1 == self.current.unwrap_or(usize::MAX)
+        }
+
+        #[cfg(feature = "autocomplete")]
+        pub(crate) fn comp_mut(&mut self) -> Option<&mut crate::complete_gen::Complete> {
+            self.comp.as_mut()
+        }
+
+        #[cfg(feature = "autocomplete")]
+        pub(crate) fn comp_ref(&self) -> Option<&crate::complete_gen::Complete> {
+            self.comp.as_ref()
+        }
+
+        #[cfg(feature = "autocomplete")]
+        pub(crate) fn swap_comps(&mut self, other: &mut Self) {
+            std::mem::swap(&mut self.comp, &mut other.comp);
+        }
+    }
+
+    pub(crate) struct ArgRangesIter<'a> {
+        args: &'a State,
+        width: usize,
+        cur: usize,
+    }
+    impl<'a> Iterator for ArgRangesIter<'a> {
+        type Item = (
+            /* start offset */ usize,
+            /* width of the first item */ usize,
+            State,
+        );
+
+        fn next(&mut self) -> Option<Self::Item> {
+            loop {
+                let cur = self.cur;
+                if cur > self.args.scope.end {
+                    return None;
+                }
+                self.cur += 1;
+                if !self.args.present(cur)? {
+                    continue;
+                }
+                if cur + self.width > self.args.items.len() {
+                    return None;
+                }
+                // It should be possible to optimize this code a bit
+                // by checking if first item can possibly
+                let mut args = self.args.clone();
+                args.set_scope(cur..self.args.items.len());
+                return Some((cur, self.width, args));
+            }
+        }
+    }
+
+    impl<'a> Iterator for ArgsIter<'a> {
+        type Item = (usize, &'a Arg);
+
+        fn next(&mut self) -> Option<Self::Item> {
+            loop {
+                let ix = self.cur;
+                if !self.args.scope.contains(&ix) {
+                    return None;
+                }
+                self.cur += 1;
+                if self.args.item_state.get(ix)?.present() {
+                    return Some((ix, &self.args.items[ix]));
+                }
+            }
+        }
+    }
+}
+
+impl State {
+    #[inline(never)]
+    #[cfg(feature = "autocomplete")]
+    pub(crate) fn swap_comps_with(&mut self, comps: &mut Vec<crate::complete_gen::Comp>) {
+        if let Some(comp) = self.comp_mut() {
+            comp.swap_comps(comps);
+        }
+    }
+
+    /// Get a short or long flag: `-f` / `--flag`
+    ///
+    /// Returns false if value isn't present
+    pub(crate) fn take_flag(&mut self, named: &NamedArg) -> bool {
+        if let Some((ix, _)) = self
+            .items_iter()
+            .find(|arg| named.matches_arg(arg.1, false))
+        {
+            self.remove(ix);
+            true
+        } else {
+            false
+        }
+    }
+
+    /// get a short or long arguments
+    ///
+    /// Returns Ok(None) if flag isn't present
+    /// Returns Err if flag is present but value is either missing or strange.
+    pub(crate) fn take_arg(
+        &mut self,
+        named: &NamedArg,
+        adjacent: bool,
+        metavar: Metavar,
+    ) -> Result<Option<OsString>, Error> {
+        let (key_ix, _arg) = match self
+            .items_iter()
+            .find(|arg| named.matches_arg(arg.1, adjacent))
+        {
+            Some(v) => v,
+            None => return Ok(None),
+        };
+
+        let val_ix = key_ix + 1;
+        let val = match self.get(val_ix) {
+            Some(Arg::Word(w) | Arg::ArgWord(w)) => w,
+            _ => return Err(Error(Message::NoArgument(key_ix, metavar))),
+        };
+        let val = val.clone();
+        self.current = Some(val_ix);
+        self.remove(key_ix);
+        self.remove(val_ix);
+        Ok(Some(val))
+    }
+
+    /// gets first positional argument present
+    ///
+    /// returns Ok(None) if input is empty
+    /// returns Err if first positional argument is a flag
+    pub(crate) fn take_positional_word(
+        &mut self,
+        metavar: Metavar,
+    ) -> Result<(usize, bool, OsString), Error> {
+        match self.items_iter().find_map(|(ix, arg)| match arg {
+            Arg::Word(w) => Some((ix, false, w)),
+            Arg::PosWord(w) => Some((ix, true, w)),
+            _ => None,
+        }) {
+            Some((ix, strict, w)) => {
+                let w = w.clone();
+                self.current = Some(ix);
+                self.remove(ix);
+                Ok((ix, strict, w))
+            }
+            None => {
+                let scope = self.scope();
+                let missing = MissingItem {
+                    item: Item::Positional {
+                        help: None,
+                        metavar,
+                    },
+                    position: scope.start,
+                    scope,
+                };
+                Err(Error(Message::Missing(vec![missing])))
+            }
+        }
+    }
+
+    /// take a static string argument from the first present argument
+    pub(crate) fn take_cmd(&mut self, word: &str) -> bool {
+        if let Some((ix, Arg::Word(w) | Arg::Short(_, _, w) | Arg::Long(_, false, w))) =
+            self.items_iter().next()
+        {
+            if w == word {
+                self.remove(ix);
+                self.current = Some(ix);
+                return true;
+            }
+        }
+        self.current = None;
+        false
+    }
+
+    #[cfg(test)]
+    pub(crate) fn peek(&self) -> Option<&Arg> {
+        self.items_iter().next().map(|x| x.1)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::meta_help::Metavar;
+    use crate::{long, short};
+    const M: Metavar = Metavar("M");
+
+    #[allow(clippy::fallible_impl_from)] // this is for tests only, panic is okay
+    impl<const N: usize> From<&'static [&'static str; N]> for State {
+        fn from(value: &'static [&'static str; N]) -> Self {
+            let args = Args::from(value);
+            let mut msg = None;
+            let res = State::construct(args, &[], &[], &mut msg);
+            if let Some(err) = &msg {
+                panic!("Couldn't construct state: {:?}/{:?}", err, res);
+            }
+            res
+        }
+    }
+
+    #[test]
+    fn long_arg() {
+        let mut a = State::from(&["--speed", "12"]);
+        let s = a.take_arg(&long("speed"), false, M).unwrap().unwrap();
+        assert_eq!(s, "12");
+        assert!(a.is_empty());
+    }
+    #[test]
+    fn long_flag_and_positional() {
+        let mut a = State::from(&["--speed", "12"]);
+        let flag = a.take_flag(&long("speed"));
+        assert!(flag);
+        assert!(!a.is_empty());
+        let s = a.take_positional_word(M).unwrap();
+        assert_eq!(s.2, "12");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn multiple_short_flags() {
+        let args = Args::from(&["-vvv"]);
+        let mut err = None;
+        let mut a = State::construct(args, &['v'], &[], &mut err);
+        assert!(a.take_flag(&short('v')));
+        assert!(a.take_flag(&short('v')));
+        assert!(a.take_flag(&short('v')));
+        assert!(!a.take_flag(&short('v')));
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn long_arg_with_equality() {
+        let mut a = State::from(&["--speed=12"]);
+        let s = a.take_arg(&long("speed"), false, M).unwrap().unwrap();
+        assert_eq!(s, "12");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn long_arg_with_equality_and_minus() {
+        let mut a = State::from(&["--speed=-12"]);
+        let s = a.take_arg(&long("speed"), true, M).unwrap().unwrap();
+        assert_eq!(s, "-12");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn short_arg_with_equality() {
+        let mut a = State::from(&["-s=12"]);
+        let s = a.take_arg(&short('s'), false, M).unwrap().unwrap();
+        assert_eq!(s, "12");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn short_arg_with_equality_and_minus() {
+        let mut a = State::from(&["-s=-12"]);
+        let s = a.take_arg(&short('s'), false, M).unwrap().unwrap();
+        assert_eq!(s, "-12");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn short_arg_with_equality_and_minus_is_adjacent() {
+        let mut a = State::from(&["-s=-12"]);
+        let s = a.take_arg(&short('s'), true, M).unwrap().unwrap();
+        assert_eq!(s, "-12");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn short_arg_without_equality() {
+        let mut a = State::from(&["-s", "12"]);
+        let s = a.take_arg(&short('s'), false, M).unwrap().unwrap();
+        assert_eq!(s, "12");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn two_short_flags() {
+        let mut a = State::from(&["-s", "-v"]);
+        assert!(a.take_flag(&short('s')));
+        assert!(a.take_flag(&short('v')));
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn two_short_flags2() {
+        let mut a = State::from(&["-s", "-v"]);
+        assert!(a.take_flag(&short('v')));
+        assert!(!a.take_flag(&short('v')));
+        assert!(a.take_flag(&short('s')));
+        assert!(!a.take_flag(&short('s')));
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn command_with_flags() {
+        let mut a = State::from(&["cmd", "-s", "v"]);
+        assert!(a.take_cmd("cmd"));
+        let s = a.take_arg(&short('s'), false, M).unwrap().unwrap();
+        assert_eq!(s, "v");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn command_and_positional() {
+        let mut a = State::from(&["cmd", "pos"]);
+        assert!(a.take_cmd("cmd"));
+        let w = a.take_positional_word(M).unwrap();
+        assert_eq!(w.2, "pos");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn positionals_after_double_dash1() {
+        let mut a = State::from(&["-v", "--", "-x"]);
+        assert!(a.take_flag(&short('v')));
+        let w = a.take_positional_word(M).unwrap();
+        assert_eq!(w.2, "-x");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn positionals_after_double_dash2() {
+        let mut a = State::from(&["-v", "--", "-x"]);
+        assert!(a.take_flag(&short('v')));
+        let w = a.take_positional_word(M).unwrap();
+        assert_eq!(w.2, "-x");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn positionals_after_double_dash3() {
+        let mut a = State::from(&["-v", "12", "--", "-x"]);
+        let w = a.take_arg(&short('v'), false, M).unwrap().unwrap();
+        assert_eq!(w, "12");
+        let w = a.take_positional_word(M).unwrap();
+        assert_eq!(w.2, "-x");
+        assert!(a.is_empty());
+    }
+
+    #[test]
+    fn ambiguity_towards_flag() {
+        let args = Args::from(&["-abc"]);
+        let mut err = None;
+        let mut a = State::construct(args, &['a', 'b', 'c'], &[], &mut err);
+
+        assert!(a.take_flag(&short('a')));
+        assert!(a.take_flag(&short('b')));
+        assert!(a.take_flag(&short('c')));
+    }
+
+    #[test]
+    fn ambiguity_towards_argument() {
+        let args = Args::from(&["-abc"]);
+        let mut err = None;
+        let mut a = State::construct(args, &[], &['a'], &mut err);
+
+        let r = a.take_arg(&short('a'), false, M).unwrap().unwrap();
+        assert_eq!(r, "bc");
+    }
+
+    #[test]
+    fn ambiguity_towards_error() {
+        let args = Args::from(&["-abc"]);
+        let mut err = None;
+        let _a = State::construct(args, &['a', 'b', 'c'], &['a'], &mut err);
+        assert!(err.is_some());
+    }
+
+    #[test]
+    fn ambiguity_towards_default() {
+        // AKA unresolved
+        let a = State::from(&["-abc"]);
+        let is_ambig = matches!(a.peek(), Some(Arg::Word(_)));
+        assert!(is_ambig);
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/batteries.rs.html b/src/bpaf/batteries.rs.html new file mode 100644 index 00000000..a55100af --- /dev/null +++ b/src/bpaf/batteries.rs.html @@ -0,0 +1,375 @@ +batteries.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+
//! # Batteries included - helpful parsers that use only public API
+//!
+//! `bpaf` comes with a few extra functions that use only public API in their implementation. You
+//! might find them useful either for your code or as an inspiration source
+//!
+//! **To use anything in this module you need to enable `batteries` cargo feature.**
+//!
+//! Examples contain combinatoric usage, for derive usage you should create a parser function and
+//! use `external` annotation.
+
+use crate::{construct, literal, parsers::NamedArg, short, Parser};
+
+/// `--verbose` and `--quiet` flags with results encoded as number
+///
+/// Parameters specify the offset and minimal/maximal values. Parser accepts many `-v | --verbose` and
+/// `-q | --quiet` to increase and decrease verbosity respectively
+///
+/// # Usage
+///
+/// ```rust
+/// # use bpaf::*;
+/// use bpaf::batteries::*;
+/// fn verbose() -> impl Parser<usize> {
+///     verbose_and_quiet_by_number(2, 0, 5).map(|v| v as usize)
+/// }
+/// ```
+#[must_use]
+pub fn verbose_and_quiet_by_number(offset: isize, min: isize, max: isize) -> impl Parser<isize> {
+    #![allow(clippy::cast_possible_wrap)]
+    let verbose = short('v')
+        .long("verbose")
+        .help("Increase output verbosity, can be used several times")
+        .req_flag(())
+        .many()
+        .map(|v| v.len() as isize);
+
+    let quiet = short('q')
+        .long("quiet")
+        .help("Decrease output verbosity, can be used several times")
+        .req_flag(())
+        .many()
+        .map(|v| v.len() as isize);
+
+    construct!(verbose, quiet).map(move |(v, q)| (v - q + offset).clamp(min, max))
+}
+
+/// `--verbose` and `--quiet` flags with results choosen from a slice of values
+///
+/// Parameters specify an array of possible values and a default index
+///
+/// # Usage
+/// ```rust
+/// # use bpaf::*;
+/// use bpaf::batteries::*;
+///
+/// #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+/// enum Level {
+///    Error,
+///    Warning,
+///    Info,
+///    Debug,
+///    Trace,
+/// }
+///
+/// fn verbose() -> impl Parser<Level> {
+///     use Level::*;
+///     verbose_by_slice(2, [Error, Warning, Info, Debug, Trace])
+/// }
+/// # let parser = verbose().to_options();
+/// # let res = parser.run_inner(&[]).unwrap();
+/// # assert_eq!(Level::Info, res);
+/// # let res = parser.run_inner(&["-q"]).unwrap();
+/// # assert_eq!(Level::Warning, res);
+/// # let res = parser.run_inner(&["-qqq"]).unwrap();
+/// # assert_eq!(Level::Error, res);
+/// # let res = parser.run_inner(&["-qqqq"]).unwrap();
+/// # assert_eq!(Level::Error, res);
+/// # let res = parser.run_inner(&["-vvvvq"]).unwrap();
+/// # assert_eq!(Level::Trace, res);
+/// ```
+#[must_use]
+pub fn verbose_by_slice<T: Copy + 'static, const N: usize>(
+    offset: usize,
+    items: [T; N],
+) -> impl Parser<T> {
+    #![allow(clippy::cast_possible_wrap)]
+    #![allow(clippy::cast_sign_loss)]
+    verbose_and_quiet_by_number(offset as isize, 0, items.len() as isize - 1)
+        .map(move |i| items[i as usize])
+}
+
+/// Pick last passed value between two different flags
+///
+/// Usually `bpaf` only allows to parse a single instance for every invocation unless
+/// you specify [`many`](Parser::many) or [`some`](Parser::some). `toggle_flag` would consume
+/// multiple instances of two different flags and returns last specified value.
+///
+/// This function relies on a fact that selection between two different parsers prefers left most
+/// value. This helps to preserve relative order of parsrs.
+/// You can use similar approach to combine multiple flags accounting for their relative order.
+///
+/// Parser returns `Optional<T>` value, you can add a fallback with [`map`](Parser::map) or turn
+/// missing value info failure with a custom error message with [`parse`](Parser::parse).
+///
+/// # Example
+/// ```console
+/// $ app --banana --no-banana --banana --banana
+/// Some(Banana)
+/// $ app
+/// None
+/// ```
+///
+/// # Usage
+/// ```rust
+/// # use bpaf::*;
+/// use bpaf::batteries::toggle_flag;
+///
+/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+/// enum Select {
+///     Banana,
+///     NoBanana,
+/// }
+///
+/// fn pick() -> impl Parser<Option<Select>> {
+///     toggle_flag(long("banana"), Select::Banana, long("no-banana"), Select::NoBanana)
+/// }
+/// ```
+pub fn toggle_flag<T: Copy + 'static>(
+    a: NamedArg,
+    val_a: T,
+    b: NamedArg,
+    val_b: T,
+) -> impl Parser<Option<T>> {
+    let a = a.req_flag(val_a);
+    let b = b.req_flag(val_b);
+    construct!([a, b]).many().map(|xs| xs.into_iter().last())
+}
+
+/// Strip a command name if present at the front when used as a `cargo` command
+///
+/// When implementing a cargo subcommand parser needs to be able to skip the first argument which
+/// is always the same as the executable name without `cargo-` prefix. For example if executable name is
+/// `cargo-cmd` so first argument would be `cmd`. `cargo_helper` helps to support both invocations:
+/// with name present when used via cargo and without it when used locally.
+///
+/// You can read the code of this function as this approximate sequence of statements:
+/// 1. Try to parse a string literal that corresponds to a command name
+/// 2. It's okay if it's missing
+/// 3. And don't show anything to the user in `--help` or completion
+/// 4. Parse this word and then everything else as a tuple, return that second item.
+///
+#[cfg_attr(not(doctest), doc = include_str!("docs2/cargo_helper.md"))]
+///
+#[must_use]
+pub fn cargo_helper<P, T>(cmd: &'static str, parser: P) -> impl Parser<T>
+where
+    P: Parser<T>,
+{
+    let skip = literal(cmd).optional().hide();
+    construct!(skip, parser).map(|x| x.1)
+}
+
+/// Get usage for a parser
+///
+/// In some cases you might want to print usage if user gave no command line options, in this case
+/// you should add an enum variant to a top level enum, make it hidden with `#[bpaf(hide)]`, make
+/// it default for the top level parser with something like `#[bpaf(fallback(Arg::Help))]`.
+///
+/// When handling cases you can do something like this for `Help` variant:
+///
+/// ```ignore
+///     ...
+///     Arg::Help => {
+///         println!("{}", get_usage(parser()));
+///         std::process::exit(0);
+///     }
+///     ...
+/// ```
+#[allow(clippy::needless_pass_by_value)]
+#[must_use]
+pub fn get_usage<T>(parser: crate::OptionParser<T>) -> String
+where
+    T: std::fmt::Debug,
+{
+    parser.run_inner(&["--help"]).unwrap_err().unwrap_stdout()
+}
+
\ No newline at end of file diff --git a/src/bpaf/buffer.rs.html b/src/bpaf/buffer.rs.html new file mode 100644 index 00000000..a1d6917f --- /dev/null +++ b/src/bpaf/buffer.rs.html @@ -0,0 +1,999 @@ +buffer.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+
#[cfg(feature = "docgen")]
+use crate::{
+    info::Info,
+    meta_help::{HelpItem, HelpItems},
+};
+use crate::{
+    item::{Item, ShortLong},
+    Meta,
+};
+
+mod console;
+mod html;
+#[cfg(feature = "docgen")]
+mod manpage;
+mod splitter;
+
+pub(crate) use self::console::Color;
+use self::console::MAX_WIDTH;
+
+#[cfg(feature = "docgen")]
+pub use manpage::Section;
+
+impl From<&[(&str, Style)]> for Doc {
+    fn from(val: &[(&str, Style)]) -> Self {
+        let mut res = Doc::default();
+        for (text, style) in val {
+            res.write_str(text, *style);
+        }
+        res
+    }
+}
+
+impl<const N: usize> From<&'static [(&'static str, Style); N]> for Doc {
+    fn from(val: &'static [(&'static str, Style); N]) -> Self {
+        let mut res = Doc::default();
+        for (text, style) in val {
+            res.write_str(text, *style);
+        }
+        res
+    }
+}
+
+/// Parser metainformation
+///
+///
+/// This is a newtype around internal parser metainfo representation, generated
+/// with [`Parser::with_group_help`](crate::Parser::with_group_help) and consumed by
+/// [`Doc::meta`](Doc::meta)
+#[derive(Copy, Clone)]
+pub struct MetaInfo<'a>(pub(crate) &'a Meta);
+
+impl Doc {
+    #[inline]
+    /// Append a fragment of plain text to [`Doc`]
+    ///
+    /// See [`Doc`] for usage examples
+    pub fn text(&mut self, text: &str) {
+        self.write_str(text, Style::Text);
+    }
+
+    #[inline]
+    /// Append a fragment of literal text to [`Doc`]
+    ///
+    /// See [`Doc`] for usage examples
+    pub fn literal(&mut self, text: &str) {
+        self.write_str(text, Style::Literal);
+    }
+
+    #[inline]
+    /// Append a fragment of text with emphasis to [`Doc`]
+    ///
+    /// See [`Doc`] for usage examples
+    pub fn emphasis(&mut self, text: &str) {
+        self.write_str(text, Style::Emphasis);
+    }
+
+    #[inline]
+    /// Append a fragment of unexpected user input to [`Doc`]
+    ///
+    /// See [`Doc`] for usage examples
+    pub fn invalid(&mut self, text: &str) {
+        self.write_str(text, Style::Invalid);
+    }
+
+    /// Append a fragment of parser metadata to [`Doc`]
+    ///
+    /// See [`Doc`] for usage examples
+    pub fn meta(&mut self, meta: MetaInfo, for_usage: bool) {
+        self.write_meta(meta.0, for_usage);
+    }
+
+    /// Append a `Doc` to [`Doc`]
+    ///
+    /// See [`Doc`] for usage examples
+    pub fn doc(&mut self, buf: &Doc) {
+        self.tokens.push(Token::BlockStart(Block::InlineBlock));
+        self.tokens.extend(&buf.tokens);
+        self.payload.push_str(&buf.payload);
+        self.tokens.push(Token::BlockEnd(Block::InlineBlock));
+    }
+
+    /// Append a `Doc` to [`Doc`] for plaintext documents try to format
+    /// first line as a help section header
+    pub fn em_doc(&mut self, buf: &Doc) {
+        self.tokens.push(Token::BlockStart(Block::InlineBlock));
+        if let Some(Token::Text {
+            bytes,
+            style: Style::Text,
+        }) = buf.tokens.first().copied()
+        {
+            let prefix = &buf.payload[0..bytes];
+            if let Some((a, b)) = prefix.split_once('\n') {
+                self.emphasis(a);
+                self.tokens.push(Token::BlockStart(Block::Section3));
+                self.text(b);
+
+                if buf.tokens.len() > 1 {
+                    self.tokens.extend(&buf.tokens[1..]);
+                    self.payload.push_str(&buf.payload[bytes..]);
+                }
+                self.tokens.push(Token::BlockEnd(Block::Section3));
+            } else {
+                self.emphasis(prefix);
+            }
+        } else {
+            self.tokens.extend(&buf.tokens);
+            self.payload.push_str(&buf.payload);
+        }
+
+        self.tokens.push(Token::BlockEnd(Block::InlineBlock));
+    }
+}
+
+impl Doc {
+    pub(crate) fn write_shortlong(&mut self, name: &ShortLong) {
+        match name {
+            ShortLong::Short(s) => {
+                self.write_char('-', Style::Literal);
+                self.write_char(*s, Style::Literal);
+            }
+            ShortLong::Long(l) | ShortLong::Both(_, l) => {
+                self.write_str("--", Style::Literal);
+                self.write_str(l, Style::Literal);
+            }
+        }
+    }
+
+    pub(crate) fn write_item(&mut self, item: &Item) {
+        match item {
+            Item::Positional { metavar, help: _ } => {
+                self.metavar(*metavar);
+            }
+            Item::Command {
+                name: _,
+                short: _,
+                help: _,
+                meta: _,
+                info: _,
+            } => {
+                self.write_str("COMMAND ...", Style::Metavar);
+            }
+            Item::Flag {
+                name,
+                shorts: _,
+                env: _,
+                help: _,
+            } => self.write_shortlong(name),
+            Item::Argument {
+                name,
+                shorts: _,
+                metavar,
+                env: _,
+                help: _,
+            } => {
+                self.write_shortlong(name);
+                self.write_char('=', Style::Text);
+                self.metavar(*metavar);
+            }
+            Item::Any {
+                metavar,
+                anywhere: _,
+                help: _,
+            } => {
+                self.doc(metavar);
+            }
+        }
+    }
+
+    pub(crate) fn write_meta(&mut self, meta: &Meta, for_usage: bool) {
+        fn go(meta: &Meta, f: &mut Doc) {
+            match meta {
+                Meta::And(xs) => {
+                    for (ix, x) in xs.iter().enumerate() {
+                        if ix != 0 {
+                            f.write_str(" ", Style::Text);
+                        }
+                        go(x, f);
+                    }
+                }
+                Meta::Or(xs) => {
+                    for (ix, x) in xs.iter().enumerate() {
+                        if ix != 0 {
+                            f.write_str(" | ", Style::Text);
+                        }
+                        go(x, f);
+                    }
+                }
+                Meta::Optional(m) => {
+                    f.write_str("[", Style::Text);
+                    go(m, f);
+                    f.write_str("]", Style::Text);
+                }
+                Meta::Required(m) => {
+                    f.write_str("(", Style::Text);
+                    go(m, f);
+                    f.write_str(")", Style::Text);
+                }
+                Meta::Item(i) => f.write_item(i),
+                Meta::Many(m) => {
+                    go(m, f);
+                    f.write_str("...", Style::Text);
+                }
+
+                Meta::Adjacent(m) | Meta::Subsection(m, _) | Meta::Suffix(m, _) => {
+                    go(m, f);
+                }
+                Meta::Skip => {} // => f.write_str("no parameters expected", Style::Text),
+                Meta::CustomUsage(_, u) => {
+                    f.doc(u);
+                }
+                Meta::Strict(m) => {
+                    f.write_str("--", Style::Literal);
+                    f.write_str(" ", Style::Text);
+                    go(m, f);
+                }
+            }
+        }
+
+        let meta = meta.normalized(for_usage);
+        self.token(Token::BlockStart(Block::Mono));
+        go(&meta, self);
+        self.token(Token::BlockEnd(Block::Mono));
+    }
+}
+
+/// Style of a text fragment inside of [`Doc`]
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[non_exhaustive]
+pub enum Style {
+    /// Plain text, no decorations
+    Text,
+
+    /// Word with emphasis - things like "Usage", "Available options", etc
+    Emphasis,
+
+    /// Something user needs to type literally - command names, etc
+    Literal,
+
+    /// Metavavar placeholder - something user needs to replace with own input
+    Metavar,
+
+    /// Invalid input given by user - used to display invalid parts of the input
+    Invalid,
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[allow(dead_code)]
+pub(crate) enum Block {
+    /// level 1 section header, block for separate command inside manpage, not used in --help
+    Header,
+
+    Section2,
+
+    // 2 margin
+    /// level 3 section header, "group_help" header, etc.
+    Section3,
+
+    // inline, 4 margin, no nesting
+    /// -h, --help
+    ItemTerm,
+
+    // widest term up below 20 margin margin plus two, but at least 4.
+    /// print usage information, but also items inside Numbered/Unnumbered lists
+    ItemBody,
+
+    // 0 margin
+    /// Definition list,
+    DefinitionList,
+
+    /// block of text, blocks are separated by a blank line in man or help
+    /// can contain headers or other items inside
+    Block,
+
+    /// inserted when block is written into a block. single blank line in the input
+    /// fast forward until the end of current inline block
+    InlineBlock,
+
+    // inline
+    /// displayed with `` in monochrome or not when rendered with colors.
+    /// In markdown this becomes a link to a term if one is defined
+    TermRef,
+
+    /// Surrounds metavars block in manpage
+    ///
+    /// used only inside render_manpage at the moment
+    Meta,
+
+    /// Monospaced font that goes around [`Meta`]
+    Mono,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum Token {
+    Text { bytes: usize, style: Style },
+    BlockStart(Block),
+    BlockEnd(Block),
+}
+
+#[derive(Debug, Clone, Default)]
+/// String with styled segments.
+///
+/// You can add style information to generated documentation and help messages
+/// For simpliest possible results you can also pass a string slice in all the places
+/// that require `impl Into<Doc>`
+pub struct Doc {
+    /// string info saved here
+    payload: String,
+
+    /// string meta info tokens
+    tokens: Vec<Token>,
+}
+
+impl std::fmt::Display for Doc {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let width = f.width().unwrap_or(MAX_WIDTH);
+        f.write_str(&self.render_console(true, Color::Monochrome, width))
+    }
+}
+
+#[derive(Debug, Clone, Copy, Default)]
+struct Skip(usize);
+impl Skip {
+    fn enabled(self) -> bool {
+        self.0 > 0
+    }
+    fn enable(&mut self) {
+        self.0 = 1;
+    }
+    fn push(&mut self) {
+        if self.0 > 0 {
+            self.0 += 1;
+        }
+    }
+    fn pop(&mut self) {
+        self.0 = self.0.saturating_sub(1);
+    }
+}
+
+impl Doc {
+    pub(crate) fn is_empty(&self) -> bool {
+        self.tokens.is_empty()
+    }
+
+    pub(crate) fn first_line(&self) -> Option<Doc> {
+        if self.tokens.is_empty() {
+            return None;
+        }
+
+        let mut res = Doc::default();
+        let mut cur = 0;
+
+        for &t in &self.tokens {
+            match t {
+                Token::Text { bytes, style } => {
+                    let payload = &self.payload[cur..cur + bytes];
+                    if let Some((first, _)) = payload.split_once('\n') {
+                        res.tokens.push(Token::Text {
+                            bytes: first.len(),
+                            style,
+                        });
+                        res.payload.push_str(first);
+                    } else {
+                        res.tokens.push(t);
+                        res.payload.push_str(&self.payload[cur..cur + bytes]);
+                        cur += bytes;
+                    }
+                }
+                _ => break,
+            }
+        }
+        Some(res)
+    }
+
+    #[cfg(feature = "autocomplete")]
+    pub(crate) fn to_completion(&self) -> Option<String> {
+        let mut s = self.first_line()?.monochrome(false);
+        s.truncate(s.trim_end().len());
+        Some(s)
+    }
+}
+
+impl From<&str> for Doc {
+    fn from(value: &str) -> Self {
+        let mut buf = Doc::default();
+        buf.write_str(value, Style::Text);
+        buf
+    }
+}
+
+impl Doc {
+    //    #[cfg(test)]
+    //    pub(crate) fn clear(&mut self) {
+    //        self.payload.clear();
+    //        self.tokens.clear();
+    //    }
+
+    #[inline(never)]
+    pub(crate) fn token(&mut self, token: Token) {
+        self.tokens.push(token);
+    }
+
+    pub(crate) fn write<T>(&mut self, input: T, style: Style)
+    where
+        T: std::fmt::Display,
+    {
+        use std::fmt::Write;
+        let old_len = self.payload.len();
+        let _ = write!(self.payload, "{}", input);
+        self.set_style(self.payload.len() - old_len, style);
+    }
+
+    #[inline(never)]
+    fn set_style(&mut self, len: usize, style: Style) {
+        // buffer chunks are unified with previous chunks of the same type
+        // [metavar]"foo" + [metavar]"bar" => [metavar]"foobar"
+        match self.tokens.last_mut() {
+            Some(Token::Text {
+                bytes: prev_bytes,
+                style: prev_style,
+            }) if *prev_style == style => {
+                *prev_bytes += len;
+            }
+            _ => {
+                self.tokens.push(Token::Text { bytes: len, style });
+            }
+        }
+    }
+
+    #[inline(never)]
+    pub(crate) fn write_str(&mut self, input: &str, style: Style) {
+        self.payload.push_str(input);
+        self.set_style(input.len(), style);
+    }
+
+    #[inline(never)]
+    pub(crate) fn write_char(&mut self, c: char, style: Style) {
+        self.write_str(c.encode_utf8(&mut [0; 4]), style);
+    }
+}
+
+#[cfg(feature = "docgen")]
+#[derive(Debug, Clone)]
+struct DocSection<'a> {
+    /// Path name to the command name starting from the application
+    path: Vec<String>,
+    info: &'a Info,
+    meta: &'a Meta,
+}
+
+#[cfg(feature = "docgen")]
+fn extract_sections<'a>(
+    meta: &'a Meta,
+    info: &'a Info,
+    path: &mut Vec<String>,
+    sections: &mut Vec<DocSection<'a>>,
+) {
+    sections.push(DocSection {
+        path: path.clone(),
+        info,
+        meta,
+    });
+    let mut hi = HelpItems::default();
+    hi.append_meta(meta);
+    for item in &hi.items {
+        if let HelpItem::Command {
+            name,
+            short: _,
+            help: _,
+            meta,
+            info,
+        } = item
+        {
+            path.push((*name).to_string());
+            extract_sections(meta, info, path, sections);
+            path.pop();
+        }
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/buffer/console.rs.html b/src/bpaf/buffer/console.rs.html new file mode 100644 index 00000000..687cfd2a --- /dev/null +++ b/src/bpaf/buffer/console.rs.html @@ -0,0 +1,1045 @@ +console.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+
// help needs to support following features:
+// - linebreak - insert linebreak whenever
+// - newline - start text on a new line, don't start a new line if not already at one
+// - margin - start text at some offset at a new line
+// - tabstop - all tabstops are aligned within a section
+// - section title - "usage", "available options", "available positionals", etc. starts a new
+//         section - resets tabstops
+// - literal text user needs to type - flags, command names, etc.
+// - metavar - meta placehoder user needs to write something
+// - subsection title - two spaces + text, used for adjacent groups
+
+// help might want to render it:
+// - monochrome - default mode
+// - bright/dull/custom colors
+// - export to markdown and groff
+//
+// monochrome and colors are rendered with different widths so tabstops are out of buffer rendering
+
+// text formatting rules:
+//
+// want to be able to produce both brief and full versions of the documentation, it only makes
+// sense to look for that in the plain text...
+// - "\n " => hard line break, inserted always
+// - "\n\n" => paragraphs are separated by this, only the first one in inserted unless in "full" mode
+// // - "\n" => converted to spaces, text flows to the current margin value
+//
+// tabstops are aligned the same position within a section, tabstop sets a temporary margin for all
+// the soft linebreaks, tabstop
+//
+// margin sets the minimal offset for any new text and retained until new margin is set:
+// "hello" [margin 8] "world" is rendered as "hello   world"
+
+use super::{
+    splitter::{split, Chunk},
+    Block, Doc, Skip, Token,
+};
+
+#[cfg(feature = "color")]
+use super::Style;
+
+const MAX_TAB: usize = 24;
+pub(crate) const MAX_WIDTH: usize = 100;
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+/// Default to dull color if colors are enabled,
+#[allow(dead_code)] // not fully used in without colors
+pub(crate) enum Color {
+    Monochrome,
+    #[cfg(feature = "color")]
+    Dull,
+    #[cfg(feature = "color")]
+    Bright,
+}
+
+impl Default for Color {
+    fn default() -> Self {
+        #![allow(clippy::let_and_return)]
+        #![allow(unused_mut)]
+        #![allow(unused_assignments)]
+        let mut res;
+        #[cfg(not(feature = "color"))]
+        {
+            res = Color::Monochrome;
+        }
+
+        #[cfg(feature = "color")]
+        {
+            res = Color::Dull;
+        }
+
+        #[cfg(feature = "bright-color")]
+        {
+            res = Color::Bright;
+        }
+
+        #[cfg(feature = "dull-color")]
+        {
+            res = Color::Dull;
+        }
+
+        #[cfg(feature = "color")]
+        {
+            use supports_color::{on, Stream};
+            if !(on(Stream::Stdout).is_some() && on(Stream::Stderr).is_some()) {
+                res = Color::Monochrome;
+            }
+        }
+        res
+    }
+}
+
+#[cfg(feature = "color")]
+impl Color {
+    pub(crate) fn push_str(self, style: Style, res: &mut String, item: &str) {
+        use owo_colors::OwoColorize;
+        use std::fmt::Write;
+        match self {
+            Color::Monochrome => {
+                res.push_str(item);
+                Ok(())
+            }
+            Color::Dull => match style {
+                Style::Text => {
+                    res.push_str(item);
+                    Ok(())
+                }
+                Style::Emphasis => write!(res, "{}", item.underline().bold()),
+                Style::Literal => write!(res, "{}", item.bold()),
+                Style::Metavar => write!(res, "{}", item.underline()),
+                Style::Invalid => write!(res, "{}", item.bold().red()),
+            },
+            Color::Bright => match style {
+                Style::Text => {
+                    res.push_str(item);
+                    Ok(())
+                }
+                Style::Emphasis => write!(res, "{}", item.yellow().bold()),
+                Style::Literal => write!(res, "{}", item.green().bold()),
+                Style::Metavar => write!(res, "{}", item.blue().bold()),
+                Style::Invalid => write!(res, "{}", item.red().bold()),
+            },
+        }
+        .unwrap();
+    }
+}
+
+const PADDING: &str = "                                                  ";
+
+impl Doc {
+    /// Render a monochrome version of the document
+    ///
+    /// `full` indicates if full message should be rendered, this makes
+    /// difference for rendered help message, otherwise you can pass `true`.
+    #[must_use]
+    pub fn monochrome(&self, full: bool) -> String {
+        self.render_console(full, Color::Monochrome, MAX_WIDTH)
+    }
+
+    #[allow(clippy::too_many_lines)] // it's a big ass match statement
+    pub(crate) fn render_console(&self, full: bool, color: Color, max_width: usize) -> String {
+        let mut res = String::new();
+        let mut tabstop = 0;
+        let mut byte_pos = 0;
+        {
+            let mut current = 0;
+            let mut in_term = false;
+            // looking for widest term below MAX_TAB
+            for token in self.tokens.iter().copied() {
+                match token {
+                    Token::Text { bytes, style: _ } => {
+                        if in_term {
+                            current += self.payload[byte_pos..byte_pos + bytes].chars().count();
+                        }
+                        byte_pos += bytes;
+                    }
+                    Token::BlockStart(Block::ItemTerm) => {
+                        in_term = true;
+                        current = 0;
+                    }
+                    Token::BlockEnd(Block::ItemTerm) => {
+                        in_term = false;
+                        if current > tabstop && current <= MAX_TAB {
+                            tabstop = current;
+                        }
+                    }
+                    _ => {}
+                }
+            }
+            byte_pos = 0;
+        }
+        let tabstop = tabstop + 4;
+
+        #[cfg(test)]
+        let mut stack = Vec::new();
+        let mut skip = Skip::default();
+        let mut char_pos = 0;
+
+        let mut margins: Vec<usize> = Vec::new();
+
+        // a single new line, unless one exists
+        let mut pending_newline = false;
+        // a double newline, unless one exists
+        let mut pending_blank_line = false;
+
+        let mut pending_margin = false;
+
+        for token in self.tokens.iter().copied() {
+            match token {
+                Token::Text { bytes, style } => {
+                    let input = &self.payload[byte_pos..byte_pos + bytes];
+                    byte_pos += bytes;
+
+                    if skip.enabled() {
+                        continue;
+                    }
+
+                    for chunk in split(input) {
+                        match chunk {
+                            Chunk::Raw(s, w) => {
+                                let margin = margins.last().copied().unwrap_or(0usize);
+                                if !res.is_empty() {
+                                    if (pending_newline || pending_blank_line)
+                                        && !res.ends_with('\n')
+                                    {
+                                        char_pos = 0;
+                                        res.push('\n');
+                                    }
+                                    if pending_blank_line && !res.ends_with("\n\n") {
+                                        res.push('\n');
+                                    }
+                                    if char_pos + s.len() > max_width {
+                                        char_pos = 0;
+                                        res.truncate(res.trim_end().len());
+                                        res.push('\n');
+                                        if s == " " {
+                                            continue;
+                                        }
+                                    }
+                                }
+
+                                let mut pushed = 0;
+                                if let Some(missing) = margin.checked_sub(char_pos) {
+                                    res.push_str(&PADDING[..missing]);
+                                    char_pos = margin;
+                                    pushed = missing;
+                                }
+                                if pending_margin && char_pos >= MAX_TAB + 4 && pushed < 2 {
+                                    let missing = 2 - pushed;
+                                    res.push_str(&PADDING[..missing]);
+                                    char_pos += missing;
+                                }
+
+                                pending_newline = false;
+                                pending_blank_line = false;
+                                pending_margin = false;
+
+                                #[cfg(feature = "color")]
+                                {
+                                    color.push_str(style, &mut res, s);
+                                }
+                                #[cfg(not(feature = "color"))]
+                                {
+                                    let _ = style;
+                                    let _ = color;
+                                    res.push_str(s);
+                                }
+                                char_pos += w;
+                            }
+                            Chunk::Paragraph => {
+                                res.push('\n');
+                                char_pos = 0;
+                                if !full {
+                                    skip.enable();
+                                    break;
+                                }
+                            }
+                            Chunk::LineBreak => {
+                                res.push('\n');
+                                char_pos = 0;
+                            }
+                        }
+                    }
+                }
+                Token::BlockStart(block) => {
+                    #[cfg(test)]
+                    stack.push(block);
+                    let margin = margins.last().copied().unwrap_or(0usize);
+
+                    match block {
+                        Block::Header | Block::Section2 => {
+                            pending_newline = true;
+                            margins.push(margin);
+                        }
+                        Block::Section3 => {
+                            pending_newline = true;
+                            margins.push(margin + 2);
+                        }
+                        Block::ItemTerm => {
+                            pending_newline = true;
+                            margins.push(margin + 4);
+                        }
+                        Block::ItemBody => {
+                            margins.push(margin + tabstop + 2);
+                            pending_margin = true;
+                        }
+                        Block::InlineBlock => {
+                            skip.push();
+                        }
+                        Block::Block => {
+                            margins.push(margin);
+                        }
+                        Block::DefinitionList | Block::Meta | Block::Mono => {}
+                        Block::TermRef => {
+                            if color == Color::Monochrome {
+                                res.push('`');
+                                char_pos += 1;
+                            }
+                        }
+                    }
+                }
+                Token::BlockEnd(block) => {
+                    #[cfg(test)]
+                    assert_eq!(stack.pop(), Some(block));
+
+                    margins.pop();
+                    match block {
+                        Block::ItemBody => {
+                            pending_margin = false;
+                        }
+                        Block::Header
+                        | Block::Section2
+                        | Block::Section3
+                        | Block::ItemTerm
+                        | Block::DefinitionList
+                        | Block::Meta
+                        | Block::Mono => {}
+                        Block::InlineBlock => {
+                            skip.pop();
+                        }
+                        Block::Block => {
+                            pending_blank_line = true;
+                        }
+                        Block::TermRef => {
+                            if color == Color::Monochrome {
+                                res.push('`');
+                                char_pos += 1;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if pending_newline || pending_blank_line {
+            res.push('\n');
+        }
+        #[cfg(test)]
+        assert_eq!(stack, &[]);
+        res
+    }
+}
+
+/*
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn tabstop_works() {
+        // tabstop followed by newline
+        let mut m = Buffer::default();
+        m.token(Token::TermStart);
+        m.text("aa");
+        m.token(Token::TermStop);
+        m.token(Token::LineBreak);
+
+        m.token(Token::TermStart);
+        m.text("b");
+        m.token(Token::TermStop);
+        m.text("c");
+        m.token(Token::LineBreak);
+        assert_eq!(m.monochrome(true), "    aa\n    b   c\n");
+        m.clear();
+
+        // plain, narrow first
+        m.token(Token::TermStart);
+        m.text("1");
+        m.token(Token::TermStop);
+        m.text("22");
+        m.token(Token::LineBreak);
+
+        m.token(Token::TermStart);
+        m.text("33");
+        m.token(Token::TermStop);
+        m.text("4");
+        m.token(Token::LineBreak);
+        assert_eq!(m.monochrome(true), "    1   22\n    33  4\n");
+        m.clear();
+
+        // plain, wide first
+        m.token(Token::TermStart);
+        m.text("aa");
+        m.token(Token::TermStop);
+
+        m.text("b");
+        m.token(Token::LineBreak);
+
+        m.token(Token::TermStart);
+        m.text("c");
+        m.token(Token::TermStop);
+
+        m.text("dd");
+        m.token(Token::LineBreak);
+        assert_eq!(m.monochrome(true), "    aa  b\n    c   dd\n");
+        m.clear();
+
+        // two different styles first
+        m.token(Token::TermStart);
+        m.text("a");
+        m.literal("b");
+        m.token(Token::TermStop);
+
+        m.literal("c");
+        m.token(Token::LineBreak);
+        m.token(Token::TermStart);
+        m.text("d");
+        m.token(Token::TermStop);
+
+        m.literal("e");
+        m.token(Token::LineBreak);
+        assert_eq!(m.monochrome(true), "    ab  c\n    d   e\n");
+    }
+
+    #[test]
+    fn linewrap_works() {
+        let mut m = Buffer::default();
+        m.token(Token::TermStart);
+        m.write_str("--hello", Style::Literal);
+        m.token(Token::TermStop);
+        for i in 0..25 {
+            m.write_str(&format!("and word{i} "), Style::Text)
+        }
+        m.write_str("and last word", Style::Text);
+        m.token(Token::LineBreak);
+
+        let expected =
+"    --hello  and word0 and word1 and word2 and word3 and word4 and word5 and word6 and word7 and word8
+             and word9 and word10 and word11 and word12 and word13 and word14 and word15 and word16 and
+             word17 and word18 and word19 and word20 and word21 and word22 and word23 and word24 and last
+             word
+";
+
+        assert_eq!(m.monochrome(true), expected);
+    }
+
+    #[test]
+    fn very_long_tabstop() {
+        let mut m = Buffer::default();
+        m.token(Token::TermStart);
+        m.write_str(
+            "--this-is-a-very-long-option <DON'T DO THIS AT HOME>",
+            Style::Literal,
+        );
+        m.token(Token::TermStop);
+        for i in 0..15 {
+            m.write_str(&format!("and word{i} "), Style::Text)
+        }
+        m.write_str("and last word", Style::Text);
+        m.token(Token::LineBreak);
+
+        let expected =
+"    --this-is-a-very-long-option <DON'T DO THIS AT HOME>  and word0 and word1 and word2 and word3 and word4
+      and word5 and word6 and word7 and word8 and word9 and word10 and word11 and word12 and word13 and
+      word14 and last word
+";
+
+        assert_eq!(m.monochrome(true), expected);
+    }
+
+    #[test]
+    fn line_breaking_rules() {
+        let mut buffer = Buffer::default();
+        buffer.write_str("hello ", Style::Text);
+        assert_eq!(buffer.monochrome(true), "hello ");
+        buffer.clear();
+
+        buffer.write_str("hello\n world\n", Style::Text);
+        assert_eq!(buffer.monochrome(true), "hello\nworld ");
+        buffer.clear();
+
+        buffer.write_str("hello\nworld", Style::Text);
+        assert_eq!(buffer.monochrome(true), "hello world");
+        buffer.clear();
+
+        buffer.write_str("hello\nworld\n", Style::Text);
+        assert_eq!(buffer.monochrome(true), "hello world ");
+        buffer.clear();
+
+        buffer.write_str("hello\n\nworld", Style::Text);
+        assert_eq!(buffer.monochrome(false), "hello\n");
+        buffer.clear();
+
+        buffer.write_str("hello\n\nworld", Style::Text);
+        assert_eq!(buffer.monochrome(true), "hello\nworld");
+        buffer.clear();
+    }
+
+    #[test]
+    fn splitter_works() {
+        assert_eq!(
+            split("hello ").collect::<Vec<_>>(),
+            [Chunk::Raw("hello", 5), Chunk::Raw(" ", 1)]
+        );
+
+        assert_eq!(
+            split("hello\nworld").collect::<Vec<_>>(),
+            [
+                Chunk::Raw("hello", 5),
+                Chunk::Raw(" ", 1),
+                Chunk::Raw("world", 5)
+            ]
+        );
+
+        assert_eq!(
+            split("hello\n world").collect::<Vec<_>>(),
+            [
+                Chunk::Raw("hello", 5),
+                Chunk::HardLineBreak,
+                Chunk::Raw("world", 5)
+            ]
+        );
+
+        assert_eq!(
+            split("hello\n\nworld").collect::<Vec<_>>(),
+            [
+                Chunk::Raw("hello", 5),
+                Chunk::SoftLineBreak,
+                Chunk::Raw("world", 5)
+            ]
+        );
+    }
+}*/
+
\ No newline at end of file diff --git a/src/bpaf/buffer/html.rs.html b/src/bpaf/buffer/html.rs.html new file mode 100644 index 00000000..7f17d7bc --- /dev/null +++ b/src/bpaf/buffer/html.rs.html @@ -0,0 +1,961 @@ +html.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+
use crate::{
+    buffer::{
+        splitter::{split, Chunk},
+        Block, Skip, Style, Token,
+    },
+    Doc, OptionParser,
+};
+
+#[cfg(feature = "docgen")]
+use crate::{
+    buffer::{extract_sections, Info, Meta},
+    meta_help::render_help,
+    Parser,
+};
+
+#[inline(never)]
+#[cfg(feature = "docgen")]
+fn collect_html(app: String, meta: &Meta, info: &Info) -> Doc {
+    let mut sections = Vec::new();
+    let root = meta;
+    let mut path = vec![app];
+    extract_sections(root, info, &mut path, &mut sections);
+
+    let mut buf = Doc::default();
+
+    if sections.len() > 1 {
+        buf.token(Token::BlockStart(Block::Block));
+        buf.token(Token::BlockStart(Block::Header));
+        buf.text("Command summary");
+        buf.token(Token::BlockEnd(Block::Header));
+        buf.token(Token::BlockEnd(Block::Block));
+
+        // TODO - this defines forward references to sections which are rendered differently
+        // between html and markdown and never used in console...
+        for section in &sections {
+            buf.token(Token::BlockStart(Block::ItemBody));
+            buf.text(&format!(
+                "* [`{}`↴](#{})",
+                section.path.join(" "),
+                section.path.join("-").to_lowercase().replace(' ', "-"),
+            ));
+            buf.token(Token::BlockEnd(Block::ItemBody));
+        }
+    }
+
+    for section in sections {
+        buf.token(Token::BlockStart(Block::Header));
+        buf.text(&section.path.join(" ").to_string());
+        buf.token(Token::BlockEnd(Block::Header));
+
+        let b = render_help(
+            &section.path,
+            section.info,
+            section.meta,
+            &section.info.meta(),
+            false,
+        );
+        buf.doc(&b);
+    }
+    buf
+}
+
+impl<T> OptionParser<T> {
+    /// Render command line documentation for the app into html/markdown mix
+    #[cfg(feature = "docgen")]
+    pub fn render_html(&self, app: impl Into<String>) -> String {
+        collect_html(app.into(), &self.inner.meta(), &self.info).render_html(true, false)
+    }
+
+    /// Render command line documentation for the app into Markdown
+    #[cfg(feature = "docgen")]
+    pub fn render_markdown(&self, app: impl Into<String>) -> String {
+        collect_html(app.into(), &self.inner.meta(), &self.info).render_markdown(true)
+    }
+}
+
+#[derive(Copy, Clone, Default)]
+pub(crate) struct Styles {
+    mono: bool,
+    bold: bool,
+    italic: bool,
+}
+impl From<Style> for Styles {
+    fn from(f: Style) -> Self {
+        match f {
+            Style::Literal => Styles {
+                bold: true,
+                mono: true,
+                italic: false,
+            },
+            Style::Metavar => Styles {
+                bold: false,
+                mono: true,
+                italic: true,
+            },
+            Style::Text => Styles {
+                bold: false,
+                mono: false,
+                italic: false,
+            },
+            Style::Emphasis | Style::Invalid => Styles {
+                mono: false,
+                bold: true,
+                italic: false,
+            },
+        }
+    }
+}
+
+fn change_style(res: &mut String, cur: &mut Styles, new: Styles) {
+    if cur.italic {
+        res.push_str("</i>");
+    }
+    if cur.bold {
+        res.push_str("</b>");
+    }
+    if cur.mono {
+        res.push_str("</tt>");
+    }
+    if new.mono {
+        res.push_str("<tt>");
+    }
+    if new.bold {
+        res.push_str("<b>");
+    }
+    if new.italic {
+        res.push_str("<i>");
+    }
+    *cur = new;
+}
+
+fn change_to_markdown_style(res: &mut String, cur: &mut Styles, new: Styles) {
+    if cur.mono {
+        res.push('`');
+    }
+
+    if cur.bold {
+        res.push_str("**");
+    }
+    if cur.italic {
+        res.push('_');
+    }
+    if new.italic {
+        res.push('_');
+    }
+    if new.bold {
+        res.push_str("**");
+    }
+    if new.mono {
+        res.push('`');
+    }
+    *cur = new;
+}
+
+/// Make it so new text is separated by an empty line
+fn blank_html_line(res: &mut String) {
+    if !(res.is_empty() || res.ends_with("<br>\n")) {
+        res.push_str("<br>\n");
+    }
+}
+
+/// Make it so new text is separated by an empty line
+fn blank_markdown_line(res: &mut String) {
+    if !(res.is_empty() || res.ends_with("\n\n")) {
+        res.push_str("\n\n");
+    }
+}
+
+/// Make it so new text is separated by an empty line
+fn new_markdown_line(res: &mut String) {
+    if !(res.is_empty() || res.ends_with('\n')) {
+        res.push('\n');
+    }
+}
+
+const CSS: &str = "
+<style>
+div.bpaf-doc {
+    padding: 14px;
+    background-color:var(--code-block-background-color);
+    font-family: \"Source Code Pro\", monospace;
+    margin-bottom: 0.75em;
+}
+div.bpaf-doc dt { margin-left: 1em; }
+div.bpaf-doc dd { margin-left: 3em; }
+div.bpaf-doc dl { margin-top: 0; padding-left: 1em; }
+div.bpaf-doc  { padding-left: 1em; }
+</style>";
+
+impl Doc {
+    #[doc(hidden)]
+    /// Render doc into html page, used by documentation sample generator
+    #[must_use]
+    pub fn render_html(&self, full: bool, include_css: bool) -> String {
+        let mut res = String::new();
+        let mut byte_pos = 0;
+        let mut cur_style = Styles::default();
+
+        // skip tracks text paragraphs, paragraphs starting from the section
+        // one are only shown when full is set to true
+        let mut skip = Skip::default();
+
+        // stack keeps track of the AST tree, mostly to be able to tell
+        // if we are rendering definition list or item list
+        let mut stack = Vec::new();
+
+        for token in self.tokens.iter().copied() {
+            match token {
+                Token::Text { bytes, style } => {
+                    let input = &self.payload[byte_pos..byte_pos + bytes];
+                    byte_pos += bytes;
+
+                    if skip.enabled() {
+                        continue;
+                    }
+
+                    change_style(&mut res, &mut cur_style, Styles::from(style));
+
+                    for chunk in split(input) {
+                        match chunk {
+                            Chunk::Raw(input, _) => {
+                                let input = input.replace('<', "&lt;").replace('>', "&gt;");
+                                res.push_str(&input);
+                            }
+                            Chunk::Paragraph => {
+                                if full {
+                                    res.push_str("<br>\n");
+                                } else {
+                                    skip.enable();
+                                    break;
+                                }
+                            }
+                            Chunk::LineBreak => res.push_str("<br>\n"),
+                        }
+                    }
+                }
+                Token::BlockStart(b) => {
+                    change_style(&mut res, &mut cur_style, Styles::default());
+                    match b {
+                        Block::Header => {
+                            blank_html_line(&mut res);
+                            res.push_str("# ");
+                        }
+                        Block::Section2 => {
+                            res.push_str("<div>\n");
+                        }
+                        Block::ItemTerm => res.push_str("<dt>"),
+                        Block::ItemBody => {
+                            if stack.last().copied() == Some(Block::DefinitionList) {
+                                res.push_str("<dd>");
+                            } else {
+                                res.push_str("<li>");
+                            }
+                        }
+                        Block::DefinitionList => {
+                            res.push_str("<dl>");
+                        }
+                        Block::Block => {
+                            res.push_str("<p>");
+                        }
+                        Block::Meta => todo!(),
+                        Block::Section3 => res.push_str("<div style='padding-left: 0.5em'>"),
+                        Block::Mono | Block::TermRef => {}
+                        Block::InlineBlock => {
+                            skip.push();
+                        }
+                    }
+                    stack.push(b);
+                }
+                Token::BlockEnd(b) => {
+                    change_style(&mut res, &mut cur_style, Styles::default());
+                    stack.pop();
+                    match b {
+                        Block::Header => {
+                            blank_html_line(&mut res);
+                        }
+                        Block::Section2 => {
+                            res.push_str("</div>");
+                        }
+
+                        Block::InlineBlock => {
+                            skip.pop();
+                        }
+                        Block::ItemTerm => res.push_str("</dt>\n"),
+                        Block::ItemBody => {
+                            if stack.last().copied() == Some(Block::DefinitionList) {
+                                res.push_str("</dd>\n");
+                            } else {
+                                res.push_str("</li>\n");
+                            }
+                        }
+                        Block::DefinitionList => res.push_str("</dl>\n"),
+                        Block::Block => {
+                            res.push_str("</p>");
+                        }
+                        Block::Mono | Block::TermRef => {}
+                        Block::Section3 => res.push_str("</div>"),
+                        Block::Meta => todo!(),
+                    }
+                }
+            }
+        }
+        change_style(&mut res, &mut cur_style, Styles::default());
+        if include_css {
+            res.push_str(CSS);
+        }
+        res
+    }
+
+    /// Render doc into markdown document, used by documentation sample generator
+    #[must_use]
+    pub fn render_markdown(&self, full: bool) -> String {
+        let mut res = String::new();
+        let mut byte_pos = 0;
+        let mut cur_style = Styles::default();
+
+        let mut skip = Skip::default();
+        let mut empty_term = false;
+        let mut mono = 0;
+        let mut def_list = false;
+        let mut code_block = false;
+        let mut app_name_seen = false;
+        for (ix, token) in self.tokens.iter().copied().enumerate() {
+            match token {
+                Token::Text { bytes, style } => {
+                    let input = &self.payload[byte_pos..byte_pos + bytes];
+                    byte_pos += bytes;
+                    if skip.enabled() {
+                        continue;
+                    }
+
+                    change_to_markdown_style(&mut res, &mut cur_style, Styles::from(style));
+
+                    for chunk in split(input) {
+                        match chunk {
+                            Chunk::Raw(input, w) => {
+                                if w == Chunk::TICKED_CODE {
+                                    new_markdown_line(&mut res);
+                                    res.push_str("  ");
+                                    res.push_str(input);
+                                    res.push('\n');
+                                } else if w == Chunk::CODE {
+                                    if !code_block {
+                                        res.push_str("\n\n  ```text\n");
+                                    }
+                                    code_block = true;
+                                    res.push_str("  ");
+                                    res.push_str(input);
+                                    res.push('\n');
+                                } else {
+                                    if code_block {
+                                        res.push_str("\n  ```\n");
+                                        code_block = false;
+                                    }
+                                    if mono > 0 {
+                                        let input = input.replace('[', "\\[").replace(']', "\\]");
+                                        res.push_str(&input);
+                                    } else {
+                                        res.push_str(input);
+                                    }
+                                }
+                            }
+                            Chunk::Paragraph => {
+                                if full {
+                                    res.push_str("\n\n");
+                                    if def_list {
+                                        res.push_str("  ");
+                                    }
+                                } else {
+                                    skip.enable();
+                                    break;
+                                }
+                            }
+                            Chunk::LineBreak => res.push('\n'),
+                        }
+                    }
+
+                    if code_block {
+                        res.push_str("  ```\n");
+                        code_block = false;
+                    }
+                }
+                Token::BlockStart(b) => {
+                    change_to_markdown_style(&mut res, &mut cur_style, Styles::default());
+                    match b {
+                        Block::Header => {
+                            blank_markdown_line(&mut res);
+                            if app_name_seen {
+                                res.push_str("## ");
+                            } else {
+                                res.push_str("# ");
+                                app_name_seen = true;
+                            }
+                        }
+                        Block::Section2 => {
+                            res.push_str("");
+                        }
+                        Block::ItemTerm => {
+                            new_markdown_line(&mut res);
+                            empty_term = matches!(
+                                self.tokens.get(ix + 1),
+                                Some(Token::BlockEnd(Block::ItemTerm))
+                            );
+                            res.push_str(if empty_term { "  " } else { "- " });
+                        }
+                        Block::ItemBody => {
+                            if def_list {
+                                res.push_str(if empty_term { " " } else { " &mdash; " });
+                            }
+                            new_markdown_line(&mut res);
+                            res.push_str("  ");
+                        }
+                        Block::DefinitionList => {
+                            def_list = true;
+                            res.push_str("");
+                        }
+                        Block::Block => {
+                            res.push('\n');
+                        }
+                        Block::Meta => todo!(),
+                        Block::Mono => {
+                            mono += 1;
+                        }
+                        Block::Section3 => res.push_str("### "),
+                        Block::TermRef => {}
+                        Block::InlineBlock => {
+                            skip.push();
+                        }
+                    }
+                }
+                Token::BlockEnd(b) => {
+                    change_to_markdown_style(&mut res, &mut cur_style, Styles::default());
+                    match b {
+                        Block::Header | Block::Block | Block::Section3 | Block::Section2 => {
+                            res.push('\n');
+                        }
+
+                        Block::InlineBlock => {
+                            skip.pop();
+                        }
+                        Block::ItemTerm | Block::TermRef => {}
+                        Block::ItemBody => {
+                            if def_list {
+                                res.push('\n');
+                            }
+                        }
+                        Block::DefinitionList => {
+                            def_list = false;
+                            res.push('\n');
+                        }
+                        Block::Mono => {
+                            mono -= 1;
+                        }
+                        Block::Meta => todo!(),
+                    }
+                }
+            }
+        }
+        change_to_markdown_style(&mut res, &mut cur_style, Styles::default());
+        res
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn transitions_are_okay() {
+        let mut doc = Doc::default();
+
+        doc.emphasis("Usage: "); // bold
+        doc.literal("my_program"); // bold + tt
+
+        let r = doc.render_html(true, false);
+
+        assert_eq!(r, "<b>Usage: </b><tt><b>my_program</b></tt>")
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/buffer/manpage.rs.html b/src/bpaf/buffer/manpage.rs.html new file mode 100644 index 00000000..4b25f1f3 --- /dev/null +++ b/src/bpaf/buffer/manpage.rs.html @@ -0,0 +1,493 @@ +manpage.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+
use crate::{
+    buffer::{extract_sections, manpage::escape::Apostrophes, Block, HelpItems, Style, Token},
+    Doc, OptionParser, Parser,
+};
+
+mod escape;
+mod monoid;
+mod roff;
+
+use roff::{Font, Roff};
+
+#[derive(Debug, Clone, Copy)]
+/// Manual page section
+pub enum Section<'a> {
+    /// General commands
+    General,
+    /// System calls
+    SystemCall,
+    /// Library functions such as C standard library functions
+    LibraryFunction,
+    /// Special files (usually devices in /dev) and drivers
+    SpecialFile,
+    /// File formats and conventions
+    FileFormat,
+    /// Games and screensavers
+    Game,
+    /// Miscellaneous
+    Misc,
+    /// System administration commands and daemons
+    Sysadmin,
+    /// Custom section
+    Custom(&'a str),
+}
+impl Section<'_> {
+    fn as_str(&self) -> &str {
+        match self {
+            Section::General => "1",
+            Section::SystemCall => "2",
+            Section::LibraryFunction => "3",
+            Section::SpecialFile => "4",
+            Section::FileFormat => "5",
+            Section::Game => "6",
+            Section::Misc => "7",
+            Section::Sysadmin => "8",
+            Section::Custom(s) => s,
+        }
+    }
+}
+
+impl<T> OptionParser<T> {
+    /// Render command line documentation for the app into a manpage
+    pub fn render_manpage(
+        &self,
+        app: impl AsRef<str>,
+        section: Section,
+        last_update_date: Option<&str>,
+        vendor: Option<&str>,
+        application_title: Option<&str>,
+    ) -> String {
+        let mut sections = Vec::new();
+        let root = self.inner.meta();
+        let mut path = vec![app.as_ref().to_string()];
+
+        extract_sections(&root, &self.info, &mut path, &mut sections);
+
+        let mut buf = Doc::default();
+
+        if sections.len() > 1 {
+            buf.token(Token::BlockStart(Block::Block));
+            buf.token(Token::BlockStart(Block::Header));
+            buf.text("SYNOPSIS");
+            buf.token(Token::BlockEnd(Block::Header));
+            buf.token(Token::BlockEnd(Block::Block));
+
+            buf.token(Token::BlockStart(Block::Meta));
+            for section in &sections {
+                for p in &section.path {
+                    buf.literal(p);
+                    buf.text(" ");
+                }
+
+                buf.write_meta(section.meta, true);
+                buf.text("\n");
+            }
+            buf.token(Token::BlockEnd(Block::Meta));
+        }
+
+        // NAME
+        // SYNOPSIS
+        // DESCRIPTION
+        // EXIT STATUS
+        // REPORTING BUGS
+        // EXAMPLES
+        // SEE ALSO
+
+        for section in &sections {
+            if sections.len() > 1 {
+                buf.token(Token::BlockStart(Block::Header));
+                buf.write_path(&section.path);
+                buf.token(Token::BlockEnd(Block::Header));
+            }
+
+            if let Some(descr) = &section.info.descr {
+                buf.token(Token::BlockStart(Block::Header));
+                buf.text("NAME");
+                buf.token(Token::BlockEnd(Block::Header));
+
+                buf.text(app.as_ref());
+                buf.text(" - ");
+                buf.doc(descr);
+            }
+
+            buf.token(Token::BlockStart(Block::Header));
+            buf.text("SYNOPSIS");
+            buf.token(Token::BlockEnd(Block::Header));
+            buf.write_path(&section.path);
+            buf.write_meta(section.meta, true);
+
+            if let Some(t) = &section.info.header {
+                buf.token(Token::BlockStart(Block::Block));
+                buf.doc(t);
+                buf.token(Token::BlockEnd(Block::Block));
+            }
+
+            let mut items = HelpItems::default();
+            items.append_meta(section.meta);
+            let help_meta = section.info.meta();
+            items.append_meta(&help_meta);
+            buf.write_help_item_groups(items, false);
+
+            if let Some(footer) = &section.info.footer {
+                buf.token(Token::BlockStart(Block::Block));
+                buf.doc(footer);
+                buf.token(Token::BlockEnd(Block::Block));
+            }
+        }
+
+        let mut manpage = Roff::new();
+        manpage.control(
+            "TH",
+            [
+                app.as_ref(),
+                section.as_str(),
+                last_update_date.unwrap_or("-"),
+                vendor.unwrap_or("-"),
+                application_title.unwrap_or(""),
+            ]
+            .iter()
+            .copied(),
+        );
+
+        buf.render_roff(manpage)
+    }
+}
+
+impl From<Style> for Font {
+    fn from(value: Style) -> Self {
+        match value {
+            Style::Text => Font::Roman,
+            Style::Emphasis | Style::Literal => Font::Bold,
+            Style::Metavar | Style::Invalid => Font::Italic,
+        }
+    }
+}
+
+impl Doc {
+    pub(crate) fn render_roff(&self, mut roff: Roff) -> String {
+        // sections and subsections are implemented with .SH and .SS
+        // control messages and it is easier to provide them right away
+        // We also strip styling from them and change sections to all caps
+        let mut capture = (String::new(), false);
+
+        let mut byte_pos = 0;
+        for token in self.tokens.iter().copied() {
+            match token {
+                Token::Text { bytes, style } => {
+                    let input = &self.payload[byte_pos..byte_pos + bytes];
+                    byte_pos += bytes;
+
+                    if capture.1 {
+                        capture.0.push_str(input);
+                        continue;
+                    } else {
+                        if style == Style::Emphasis {
+                            roff.control0("SS");
+                        }
+                        roff.text(&[(Font::from(style), input)]);
+                    }
+                }
+                Token::BlockStart(block) => {
+                    //
+                    match block {
+                        Block::Header | Block::Section2 | Block::Section3 => {
+                            capture.1 = true;
+                        }
+                        Block::ItemTerm => {
+                            roff.control0("TP").strip_newlines(true);
+                        }
+                        Block::Mono
+                        | Block::ItemBody
+                        | Block::DefinitionList
+                        | Block::InlineBlock => {}
+                        Block::Block => {
+                            roff.control0("PP");
+                        }
+                        Block::Meta => {
+                            roff.control0("nf");
+                        }
+
+                        Block::TermRef => todo!(),
+                    }
+                }
+                Token::BlockEnd(block) => {
+                    //
+                    match block {
+                        Block::Header => {
+                            capture.1 = false;
+                            roff.control("SH", [capture.0.to_uppercase()]);
+                            capture.0.clear();
+                        }
+                        Block::Section2 | Block::Section3 => {
+                            capture.1 = false;
+                            roff.control("SS", [capture.0.to_uppercase()]);
+                            capture.0.clear();
+                        }
+                        Block::ItemTerm => {
+                            roff.roff_linebreak().strip_newlines(false);
+                        }
+                        Block::ItemBody => {
+                            roff.control0("PP").strip_newlines(false);
+                        }
+                        Block::Mono | Block::DefinitionList | Block::Block | Block::InlineBlock => {
+                        }
+                        Block::Meta => {
+                            roff.control0("fi");
+                        }
+                        Block::TermRef => todo!(),
+                    }
+                }
+            }
+        }
+
+        roff.render(Apostrophes::Handle)
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/buffer/manpage/escape.rs.html b/src/bpaf/buffer/manpage/escape.rs.html new file mode 100644 index 00000000..eb86871a --- /dev/null +++ b/src/bpaf/buffer/manpage/escape.rs.html @@ -0,0 +1,289 @@ +escape.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+
//! Escape and concatenate string slices according to Roff Escape rules
+
+/// Apostrophes handling configuration
+///
+/// To generate manpages you most likely want to have this in `Handle` state.
+/// See <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=507673#65> for more details
+#[derive(Eq, PartialEq, Copy, Clone)]
+#[allow(dead_code)] // it is used in the test
+pub enum Apostrophes {
+    /// Replace apostrophes with special code that
+    Handle,
+    /// Leave apostrophes as is
+    DontHandle,
+}
+
+/// Replacement for apostrophes, if active
+///
+/// <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=507673#65>
+const APOSTROPHE: &str = "\\*(Aq";
+
+#[allow(clippy::doc_markdown)]
+/// A preamble added to the start of rendered output.
+///
+/// This defines a string variable that contains an apostrophe. For
+/// historical reasons, there seems to be no other portable way to
+/// represent apostrophes across various implementations of the ROFF
+/// language. In implementations that produce output like PostScript
+/// or PDF, an apostrophe gets typeset as a right single quote, which
+/// looks different from an apostrophe. For terminal output ("ASCII"),
+/// such as when using nroff, an apostrophe looks indistinguishable
+/// from a right single quote. For manual pages, and similar content,
+/// an apostrophe is more generally desired than the right single
+/// quote, so we convert all apostrophe characters in input text into
+/// a use of the string variable defined in the preamble.
+///
+/// Used when apostrophe handle is enabled.
+///
+/// See: <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=507673#65>
+pub(crate) const APOSTROPHE_PREABMLE: &str = r#".ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+"#;
+
+/// Escaping rules
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub(crate) enum Escape {
+    /// Insert a newline character unless on a new line already
+    UnescapedAtNewline,
+
+    /// Escape space characters (`' '`) and newlines (`'\n'`)
+    /// This escape is used for control sequence arguments
+    Spaces,
+
+    /// Escape characters roff considers special:
+    /// - `' '`, `'.'` and `'\''` at the beginning of the line,
+    /// - `'-'` and `'\\'` when inside the body
+    /// - replace `'\''` with APOSTROPHE if Apostrophes handling is enabled
+    Special,
+
+    /// Similar to [`Special`](Escape::Special) but also replaces `'\n'` with `' '`
+    SpecialNoNewline,
+
+    /// Input is written as is
+    Unescaped,
+}
+
+#[cfg(test)]
+/// Escape a sequence of string slices according to escaping rules and store results to `String`
+///
+/// See also [`escape`] if it is desired to reuse existing storage capacity
+pub(crate) fn escape_to_string<'a, I>(items: I, ap: Apostrophes) -> String
+where
+    I: IntoIterator<Item = (&'a Escape, &'a str)>,
+{
+    let mut res = Vec::new();
+    escape(items, &mut res, ap);
+    String::from_utf8(res).expect("Output should be utf8 by construction")
+}
+
+/// Escape a sequence of string slices according to escaping rules
+///
+/// Writes results to `out`, result should be a valid utf8 string as long as `out` starts empty or
+/// contains a valid utf8 sequence
+pub(crate) fn escape<'a, I>(items: I, out: &mut Vec<u8>, ap: Apostrophes)
+where
+    I: IntoIterator<Item = (&'a Escape, &'a str)>,
+{
+    let mut at_line_start = true;
+    for (&meta, payload) in items {
+        if !at_line_start && meta == Escape::UnescapedAtNewline {
+            out.push(b'\n');
+            at_line_start = true;
+        }
+        for &c in payload.as_bytes() {
+            match meta {
+                Escape::Spaces => {
+                    if c == b' ' || c == b'\n' {
+                        out.extend_from_slice(b"\\ ");
+                    } else {
+                        out.push(c);
+                    }
+                }
+                Escape::Special | Escape::SpecialNoNewline => {
+                    if at_line_start && (c == b'.' || c == b'\'') {
+                        out.extend_from_slice(b"\\&");
+                    }
+                    if c == b'\\' || c == b'-' {
+                        out.push(b'\\');
+                    }
+                    if ap == Apostrophes::Handle && c == b'\'' {
+                        out.extend_from_slice(APOSTROPHE.as_bytes());
+                    } else if meta == Escape::SpecialNoNewline && c == b'\n' {
+                        out.push(b' ');
+                        at_line_start = false;
+                        continue;
+                    } else {
+                        out.push(c);
+                    }
+                }
+                Escape::Unescaped | Escape::UnescapedAtNewline => {
+                    out.push(c);
+                }
+            }
+            at_line_start = c == b'\n';
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::{escape_to_string, Apostrophes, Escape};
+
+    #[test]
+    fn sample() {
+        let ap = Apostrophes::Handle;
+        let items: &[(Escape, &str)] = &[
+            (Escape::Unescaped, "\\fI"),
+            (Escape::Special, "test"),
+            (Escape::Unescaped, "\\fP"),
+        ];
+        let output = escape_to_string(items.iter().map(|p| (&p.0, p.1)), ap);
+        assert_eq!("\\fItest\\fP", output);
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/buffer/manpage/monoid.rs.html b/src/bpaf/buffer/manpage/monoid.rs.html new file mode 100644 index 00000000..974824c4 --- /dev/null +++ b/src/bpaf/buffer/manpage/monoid.rs.html @@ -0,0 +1,327 @@ +monoid.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+
//! Free monoid on a set of annotated strings
+//!
+//! This module implements a free monoid on a set of annotated string slices along with some extra
+//! tools to operate on it. For typical usage you can check `typical_usage` function since
+//! abstractions used here are scary, not exposed to the end user and hidden from the doctest.
+
+#[test]
+fn typical_usage() {
+    let mut m = FreeMonoid::<char>::default();
+    m.push_str('a', "string ")
+        .push_str('b', "more string")
+        .push('d', '!');
+
+    let mut r = String::new();
+    for (a, slice) in &m {
+        r += &format!("{}: {:?}; ", a, slice);
+    }
+    assert_eq!("a: \"string \"; b: \"more string\"; d: \"!\"; ", r);
+}
+
+/// A Free Monoid on set of annotated string slices
+///
+/// Where identity element is `FreeMonoid::default` and binary operation is `+`
+#[derive(Debug, Clone, Eq, PartialEq)]
+#[allow(clippy::module_name_repetitions)] // FreeMonoid is a thing, Free is not
+pub struct FreeMonoid<T> {
+    payload: String,
+    labels: Vec<(std::ops::Range<usize>, T)>,
+    /// Merge adjacent fields with the same metadata together during insertion
+    pub squash: bool,
+}
+
+impl<T> Default for FreeMonoid<T> {
+    fn default() -> Self {
+        Self {
+            payload: String::new(),
+            labels: Vec::new(),
+            squash: false,
+        }
+    }
+}
+
+impl<T> FreeMonoid<T> {
+    /// Length of stored text in bytes
+    ///
+    /// Does not account for space required to render the annotations
+    pub(crate) fn payload_size(&self) -> usize {
+        self.payload.len()
+    }
+
+    /// Append an annotated string slice
+    pub(crate) fn push_str(&mut self, meta: T, payload: &str) -> &mut Self
+    where
+        T: PartialEq,
+    {
+        let r = self.payload.len();
+        self.payload.push_str(payload);
+        if let Some((prev_range, prev_meta)) = self.labels.last_mut() {
+            if self.squash && prev_meta == &meta {
+                prev_range.end = self.payload.len();
+                return self;
+            }
+        }
+        self.labels.push((r..self.payload.len(), meta));
+        self
+    }
+
+    /// Append an annotated char slice
+    pub(crate) fn push(&mut self, meta: T, payload: char) -> &mut Self
+    where
+        T: PartialEq,
+    {
+        let r = self.payload.len();
+        self.payload.push(payload);
+        if let Some((prev_range, prev_meta)) = self.labels.last_mut() {
+            if self.squash && prev_meta == &meta {
+                prev_range.end = self.payload.len();
+                return self;
+            }
+        }
+        self.labels.push((r..self.payload.len(), meta));
+        self
+    }
+
+    /// Iterate over annotated fragments
+    pub(crate) fn iter(&self) -> AnnotatedSlicesIter<T> {
+        AnnotatedSlicesIter {
+            current: 0,
+            items: self,
+        }
+    }
+}
+
+impl<'a, T> Extend<(T, &'a str)> for FreeMonoid<T>
+where
+    T: PartialEq,
+{
+    fn extend<I: IntoIterator<Item = (T, &'a str)>>(&mut self, iter: I) {
+        for (k, v) in iter {
+            self.push_str(k, v);
+        }
+    }
+}
+
+impl<'a, T> IntoIterator for &'a FreeMonoid<T> {
+    type Item = (&'a T, &'a str);
+    type IntoIter = AnnotatedSlicesIter<'a, T>;
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+impl<T: Clone> std::ops::Add<&Self> for FreeMonoid<T> {
+    type Output = Self;
+
+    fn add(mut self, rhs: &Self) -> Self::Output {
+        self += rhs;
+        self
+    }
+}
+
+impl<T: Clone> std::ops::AddAssign<&Self> for FreeMonoid<T> {
+    fn add_assign(&mut self, rhs: &Self) {
+        self.payload.push_str(&rhs.payload);
+        let len = self.payload.len();
+        self.labels.extend(
+            rhs.labels
+                .iter()
+                .map(|(range, label)| (range.start + len..range.end + len, label.clone())),
+        );
+    }
+}
+
+impl<T: PartialEq> std::ops::AddAssign<(T, &str)> for FreeMonoid<T> {
+    fn add_assign(&mut self, rhs: (T, &str)) {
+        self.push_str(rhs.0, rhs.1);
+    }
+}
+
+impl<T: PartialEq> std::ops::AddAssign<(T, char)> for FreeMonoid<T> {
+    fn add_assign(&mut self, rhs: (T, char)) {
+        self.push(rhs.0, rhs.1);
+    }
+}
+
+/// Iterate over annotated string slices contained in a [`FreeMonoid`].
+///
+/// Create with [`FreeMonoid::iter`]
+pub struct AnnotatedSlicesIter<'a, T> {
+    current: usize,
+    items: &'a FreeMonoid<T>,
+}
+
+impl<'a, T> Iterator for AnnotatedSlicesIter<'a, T> {
+    type Item = (&'a T, &'a str);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let (range, label) = self.items.labels.get(self.current)?;
+        self.current += 1;
+        Some((label, &self.items.payload[range.clone()]))
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/buffer/manpage/roff.rs.html b/src/bpaf/buffer/manpage/roff.rs.html new file mode 100644 index 00000000..5e2228c6 --- /dev/null +++ b/src/bpaf/buffer/manpage/roff.rs.html @@ -0,0 +1,665 @@ +roff.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+
//! Roff document composer
+//!
+//! [ROFF] is a family of Unix text-formatting languages, implemented
+//! by the `nroff`, `troff`, and `groff` programs, among others. See
+//! [groff(7)] for a description of the language. This structure is an
+//! abstract representation of a document in ROFF format. It is meant
+//! for writing code to generate ROFF documents, such as manual pages.
+//!
+//!
+//! For purposes of generating manpages you can use one of few available macro packages:
+//! - [man(7)] — legacy formatting language for manual pages
+//! - [mdoc(7)] - semantic markup language for formatting manual pages
+//!
+//! With more detailed information available <http://mandoc.bsd.lv>
+//!
+//! [man(7)]: http://mandoc.bsd.lv/man/man.7.html
+//! [mdoc(7)]: http://mandoc.bsd.lv/man/mdoc.7.html
+//! [groff(7)]: https://manpages.debian.org/bullseye/groff/groff.7.en.html
+//! [ROFF]: https://en.wikipedia.org/wiki/Roff_(software)
+
+use super::{
+    escape::{Apostrophes, Escape},
+    monoid::FreeMonoid,
+};
+use std::ops::{Add, AddAssign};
+
+/// You can concatenate multiple `Roff` documents with `+` or `+=`.
+#[derive(Debug, Default, Clone)]
+pub(crate) struct Roff {
+    payload: FreeMonoid<Escape>,
+    /// keep or strip newlines from inserted text
+    pub strip_newlines: bool,
+}
+
+/// Font selector
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub(crate) enum Font {
+    /// Roman font - regular font that should be used for most of the text
+    Roman,
+
+    /// Bold font
+    Bold,
+
+    /// Italic font
+    Italic,
+}
+
+/// Escape code used to return to the previous font
+pub(crate) const RESTORE_FONT: &str = "\\fP";
+
+impl Font {
+    /// Escape sequence needed to set this font, None for default font
+    ///
+    pub(crate) fn escape(self) -> &'static str {
+        match self {
+            Font::Bold => "\\fB",
+            Font::Italic => "\\fI",
+            Font::Roman => "\\fR",
+        }
+    }
+}
+
+impl Roff {
+    /// Create new raw Roff document
+    #[must_use]
+    pub(crate) fn new() -> Self {
+        Self::default()
+    }
+
+    /// Chainable setter for `strip_newlines` field
+    ///
+    /// `strip_newlines` specifies if [`render`](Self::render) should keep all the newline characters
+    /// inside added text newlines can come with a special meaning, for example adding a section
+    /// header relies, newlines are automatically stripped from [`control`](Self::control) arguments.
+    pub(crate) fn strip_newlines(&mut self, state: bool) -> &mut Self {
+        self.strip_newlines = state;
+        self
+    }
+
+    /// Insert a raw control sequence
+    ///
+    /// `name` should not contain initial `'.'`.
+    /// Arguments are taken from an iterator and escaped accordingly
+    pub(crate) fn control<S, I>(&mut self, name: &str, args: I) -> &mut Self
+    where
+        S: AsRef<str>,
+        I: IntoIterator<Item = S>,
+    {
+        self.payload.push_str(Escape::UnescapedAtNewline, ".");
+        self.payload.push_str(Escape::Unescaped, name);
+        for arg in args {
+            // empty macro argument can be specified as "", mostly useful for TH macro
+            // which takes several arguments positionally
+            let mut s = arg.as_ref();
+            if s.is_empty() {
+                s = "\"\"";
+            }
+            self.payload
+                .push_str(Escape::Unescaped, " ")
+                .push_str(Escape::Spaces, s);
+        }
+        self.payload.push_str(Escape::UnescapedAtNewline, "");
+        self
+    }
+
+    /// A variant of control that takes no parameters
+    pub(crate) fn control0(&mut self, name: &str) -> &mut Self {
+        self.payload.push_str(Escape::UnescapedAtNewline, ".");
+        self.payload.push_str(Escape::Unescaped, name);
+        self.payload.push_str(Escape::UnescapedAtNewline, "");
+        self
+    }
+
+    /// Insert a line break in the Roff document source
+    ///
+    /// This will not show up in the output of the roff program.
+    pub(crate) fn roff_linebreak(&mut self) -> &mut Self {
+        self.payload.push_str(Escape::UnescapedAtNewline, "");
+        self
+    }
+
+    /// Insert raw escape sequence
+    ///
+    /// You can use all the notations for the escapes, they will be copied into the output stream
+    /// as is without extra checks or escapes.
+    pub(crate) fn escape(&mut self, arg: &str) -> &mut Self {
+        self.payload.push_str(Escape::Unescaped, arg);
+        self
+    }
+
+    /// Insert a plain text string, special characters are escaped
+    ///
+    pub(crate) fn plaintext(&mut self, text: &str) -> &mut Self {
+        if self.strip_newlines {
+            self.payload.push_str(Escape::SpecialNoNewline, text);
+        } else {
+            self.payload.push_str(Escape::Special, text);
+        }
+        self
+    }
+
+    /// Insert one or more string slices using custom font for each one
+    pub(crate) fn text(&mut self, text: &[(Font, &str)]) -> &mut Self {
+        let mut prev_font = None;
+        for (font, item) in text {
+            if prev_font == Some(font) {
+                self.plaintext(item.as_ref());
+            } else {
+                let escape = font.escape();
+                self.escape(escape).plaintext(item.as_ref());
+                prev_font = Some(font);
+            }
+        }
+        if prev_font.is_some() {
+            self.escape(RESTORE_FONT);
+        }
+        self
+    }
+
+    /// Render Roff document to `String`
+    ///
+    /// This method creates a valid ROFF document which can be fed to a ROFF implementation
+    #[must_use]
+    pub(crate) fn render(&self, ap: Apostrophes) -> String {
+        let mut res = Vec::with_capacity(self.payload.payload_size() * 2);
+        if ap == Apostrophes::Handle {
+            res.extend(super::escape::APOSTROPHE_PREABMLE.as_bytes());
+        }
+        super::escape::escape(&self.payload, &mut res, ap);
+        String::from_utf8(res).expect("Should be valid utf8 by construction")
+    }
+}
+
+impl AddAssign<&Roff> for Roff {
+    fn add_assign(&mut self, rhs: &Roff) {
+        self.payload += &rhs.payload;
+        self.strip_newlines = rhs.strip_newlines;
+    }
+}
+
+impl Add<&Roff> for Roff {
+    type Output = Self;
+
+    fn add(mut self, rhs: &Roff) -> Self::Output {
+        self += rhs;
+        self
+    }
+}
+
+impl<'a> Extend<&'a Roff> for Roff {
+    fn extend<I: IntoIterator<Item = &'a Roff>>(&mut self, iter: I) {
+        for i in iter {
+            *self += i;
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::{Apostrophes, Font, Roff};
+    const NO_AP: Apostrophes = Apostrophes::DontHandle;
+
+    #[test]
+    fn escape_dash_in_plaintext() {
+        let text = Roff::default().plaintext("-").render(NO_AP);
+        assert_eq!(r"\-", text);
+    }
+
+    #[test]
+    fn escape_backslash_in_plaintext() {
+        let text = Roff::default().plaintext(r"\x").render(NO_AP);
+        assert_eq!(r"\\x", text);
+    }
+
+    #[test]
+    fn escape_backslash_and_dash_in_plaintext() {
+        let text = Roff::default().plaintext(r"\-").render(NO_AP);
+        assert_eq!(r"\\\-", text);
+    }
+
+    #[test]
+    fn escapes_leading_control_chars_and_space_in_plaintext() {
+        let text = Roff::default()
+            .plaintext("foo\n.bar\n'yo\n hmm")
+            .render(NO_AP);
+        assert_eq!("foo\n\\&.bar\n\\&'yo\n hmm", text);
+    }
+
+    #[test]
+    fn escape_plain_in_plaintext() {
+        let text = Roff::default().plaintext("abc").render(NO_AP);
+        assert_eq!("abc", text);
+    }
+
+    #[test]
+    fn render_dash_in_plaintext() {
+        let text = Roff::default().plaintext("foo-bar").render(NO_AP);
+        assert_eq!("foo\\-bar", text);
+    }
+
+    #[test]
+    fn render_dash_in_font() {
+        let text = Roff::default()
+            .text(&[(Font::Roman, "foo-bar")])
+            .render(NO_AP);
+        assert_eq!(text, "\\fRfoo\\-bar\\fP");
+    }
+
+    #[test]
+    fn render_roman() {
+        let text = Roff::default().text(&[(Font::Roman, "foo")]).render(NO_AP);
+        assert_eq!("\\fRfoo\\fP", text);
+    }
+
+    #[test]
+    fn render_italic() {
+        let text = Roff::default().text(&[(Font::Italic, "foo")]).render(NO_AP);
+        assert_eq!("\\fIfoo\\fP", text);
+    }
+
+    #[test]
+    fn render_bold() {
+        let text = Roff::default().text(&[(Font::Bold, "foo")]).render(NO_AP);
+        assert_eq!("\\fBfoo\\fP", text);
+    }
+
+    #[test]
+    fn render_text_roman() {
+        let text = Roff::default()
+            .text(&[(Font::Roman, "roman")])
+            .render(NO_AP);
+        assert_eq!("\\fRroman\\fP", text);
+    }
+
+    #[test]
+    fn render_text_with_leading_period() {
+        let text = Roff::default()
+            .text(&[(Font::Roman, ".roman")])
+            .render(NO_AP);
+        assert_eq!("\\fR.roman\\fP", text);
+    }
+
+    #[test]
+    fn render_text_with_newline_period() {
+        let text = Roff::default()
+            .text(&[(Font::Roman, "foo\n.roman")])
+            .render(NO_AP);
+        assert_eq!(text, "\\fRfoo\n\\&.roman\\fP");
+    }
+
+    #[test]
+    fn render_line_break() {
+        let text = Roff::default()
+            .text(&[(Font::Roman, "roman\n")])
+            .control("br", None::<&str>)
+            .text(&[(Font::Roman, "more\n")])
+            .render(NO_AP);
+        assert_eq!(text, "\\fRroman\n\\fP\n.br\n\\fRmore\n\\fP");
+    }
+
+    #[test]
+    fn render_control() {
+        let text = Roff::default()
+            .control("foo", ["bar", "foo and bar"])
+            .render(NO_AP);
+        assert_eq!(".foo bar foo\\ and\\ bar\n", text);
+    }
+
+    #[test]
+    fn twice_bold() {
+        let text = Roff::default()
+            .text(&[
+                (Font::Bold, "bold,"),
+                (Font::Roman, " more bold"),
+                (Font::Bold, " and more bold"),
+            ])
+            .render(NO_AP);
+
+        assert_eq!(text, "\\fBbold,\\fR more bold\\fB and more bold\\fP");
+    }
+
+    #[test]
+    fn multiple_controls() {
+        let text = Roff::default()
+            .control("br", None::<&str>)
+            .control0("br")
+            .control("br", None::<&str>)
+            .render(NO_AP);
+        assert_eq!(".br\n.br\n.br\n", text);
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/buffer/splitter.rs.html b/src/bpaf/buffer/splitter.rs.html new file mode 100644 index 00000000..36ba2c7d --- /dev/null +++ b/src/bpaf/buffer/splitter.rs.html @@ -0,0 +1,363 @@ +splitter.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+
pub(super) struct Splitter<'a> {
+    input: &'a str,
+
+    #[cfg(feature = "docgen")]
+    code: Code,
+}
+
+#[cfg(feature = "docgen")]
+enum Code {
+    No,
+    First,
+    Rest,
+}
+
+/// Split payload into chunks annotated with character width and containing no newlines according
+/// to text formatting rules
+pub(super) fn split(input: &str) -> Splitter {
+    Splitter {
+        input,
+        #[cfg(feature = "docgen")]
+        code: Code::No,
+    }
+}
+
+#[cfg_attr(test, derive(Debug, Clone, Copy, Eq, PartialEq))]
+pub(super) enum Chunk<'a> {
+    Raw(&'a str, usize),
+    Paragraph,
+    LineBreak,
+}
+
+impl Chunk<'_> {
+    pub(crate) const CODE: usize = 1_000_000;
+    pub(crate) const TICKED_CODE: usize = 1_000_001;
+}
+
+impl<'a> Iterator for Splitter<'a> {
+    type Item = Chunk<'a>;
+
+    // 1. paragraphs are separated by a blank line.
+    // 2. code blocks are aligned by 4 spaces and are kept intact
+    // 3. linebreaks followed by space are preserved
+    // 4. leftovers are fed word by word
+    // 5. everything between "^```" is passed as is
+
+    // 1. "\n\n" = Paragraph
+    // 2. "\n " = LineBreak
+    // 3. "\n" = " "
+    // 4. "\n    " = code block
+    // 5. take next word
+    //
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.input.is_empty() {
+            return None;
+        }
+
+        #[cfg(feature = "docgen")]
+        if matches!(self.code, Code::First | Code::Rest) {
+            if matches!(self.code, Code::Rest) && self.input.starts_with("```") {
+                self.code = Code::No;
+            }
+            if matches!(self.code, Code::First) {
+                self.code = Code::Rest;
+            }
+
+            let tail = self.input;
+            let code = if let Some((code, rest)) = self.input.split_once('\n') {
+                let tail = &tail[code.len()..];
+                if tail.starts_with("\n\n") && matches!(self.code, Code::No) {
+                    self.input = tail;
+                } else {
+                    self.input = rest;
+                }
+                code
+            } else {
+                self.input = "";
+                tail
+            };
+            return Some(Chunk::Raw(code, Chunk::TICKED_CODE));
+        }
+
+        if let Some(tail) = self.input.strip_prefix('\n') {
+            if let Some(tail) = tail.strip_prefix("    ") {
+                let code = if let Some((code, _rest)) = tail.split_once('\n') {
+                    self.input = &tail[code.len()..];
+                    code
+                } else {
+                    self.input = "";
+                    tail
+                };
+                Some(Chunk::Raw(code, Chunk::CODE))
+            } else if tail.starts_with("\n```") {
+                #[cfg(feature = "docgen")]
+                {
+                    self.code = Code::First;
+                }
+                self.input = &tail[1..];
+                Some(Chunk::Paragraph)
+            } else if tail.starts_with("\n    ") {
+                self.input = tail;
+                Some(Chunk::Paragraph)
+            } else if let Some(tail) = tail.strip_prefix('\n') {
+                self.input = tail;
+                Some(Chunk::Paragraph)
+            } else if let Some(tail) = tail.strip_prefix(' ') {
+                self.input = tail;
+                Some(Chunk::LineBreak)
+            } else {
+                self.input = tail;
+                Some(Chunk::Raw(" ", 1))
+            }
+        } else if let Some(tail) = self.input.strip_prefix(' ') {
+            self.input = tail;
+            Some(Chunk::Raw(" ", 1))
+        } else {
+            let mut char_ix = 0;
+
+            // there's iterator position but it won't give me character length of the rest of the input
+            for (byte_ix, chr) in self.input.char_indices() {
+                if chr == '\n' || chr == ' ' {
+                    let head = &self.input[..byte_ix];
+                    let tail = &self.input[byte_ix..];
+                    self.input = tail;
+                    return Some(Chunk::Raw(head, char_ix));
+                }
+                char_ix += 1;
+            }
+            let head = self.input;
+            self.input = "";
+            Some(Chunk::Raw(head, char_ix))
+        }
+    }
+}
+
+#[test]
+fn space_code_block() {
+    use Chunk::*;
+    let xs = split("a\n\n    a\n    b\n\ndf\n\n    c\n    d\n").collect::<Vec<_>>();
+    assert_eq!(
+        xs,
+        [
+            Raw("a", 1),
+            Paragraph,
+            Raw("a", 1000000),
+            Raw("b", 1000000),
+            Paragraph,
+            Raw("df", 2),
+            Paragraph,
+            Raw("c", 1000000),
+            Raw("d", 1000000),
+            Raw(" ", 1),
+        ]
+    );
+}
+
+#[test]
+fn ticks_code_block() {
+    use Chunk::*;
+    let a = "a\n\n```text\na\nb\n```\n\ndf\n\n```\nc\nd\n```\n";
+    let xs = split(a).collect::<Vec<_>>();
+    assert_eq!(
+        xs,
+        [
+            Raw("a", 1),
+            Paragraph,
+            Raw("```text", Chunk::TICKED_CODE),
+            Raw("a", Chunk::TICKED_CODE),
+            Raw("b", Chunk::TICKED_CODE),
+            Raw("```", Chunk::TICKED_CODE),
+            Paragraph,
+            Raw("df", 2),
+            Paragraph,
+            Raw("```", Chunk::TICKED_CODE),
+            Raw("c", Chunk::TICKED_CODE),
+            Raw("d", Chunk::TICKED_CODE),
+            Raw("```", Chunk::TICKED_CODE),
+        ],
+    );
+}
+
\ No newline at end of file diff --git a/src/bpaf/complete_gen.rs.html b/src/bpaf/complete_gen.rs.html new file mode 100644 index 00000000..7f5e5540 --- /dev/null +++ b/src/bpaf/complete_gen.rs.html @@ -0,0 +1,1199 @@ +complete_gen.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+
// completion:
+// static: flag names, command names
+// dynamic: argument values, positional item values
+//
+// for static when running collect any parser that fails
+//
+// OR: combine completions
+// AND: usual logic without shortcircuits
+//
+// for static completion it's enough to collect items
+// for argument completion - only one argument(Comp::Meta) should be active at once
+//
+// for rendering prefer longer version of names
+//
+// complete short names to long names if possible
+
+use crate::{
+    args::{Arg, State},
+    complete_shell::{render_bash, render_fish, render_simple, render_test, render_zsh},
+    item::ShortLong,
+    parsers::NamedArg,
+    Doc, ShellComp,
+};
+use std::ffi::OsStr;
+
+#[derive(Clone, Debug)]
+pub(crate) struct Complete {
+    /// completions accumulated so far
+    comps: Vec<Comp>,
+    pub(crate) output_rev: usize,
+
+    /// don't try to suggest any more positional items after there's a positional item failure
+    /// or parsing in progress
+    pub(crate) no_pos_ahead: bool,
+}
+
+impl Complete {
+    pub(crate) fn new(output_rev: usize) -> Self {
+        Self {
+            comps: Vec::new(),
+            output_rev,
+            no_pos_ahead: false,
+        }
+    }
+}
+
+impl State {
+    /// Add a new completion hint for flag, if needed
+    pub(crate) fn push_flag(&mut self, named: &NamedArg) {
+        let depth = self.depth();
+        if let Some(comp) = self.comp_mut() {
+            if let Ok(name) = ShortLong::try_from(named) {
+                comp.comps.push(Comp::Flag {
+                    extra: CompExtra {
+                        depth,
+                        group: None,
+                        help: named.help.as_ref().and_then(Doc::to_completion),
+                    },
+                    name,
+                });
+            }
+        }
+    }
+
+    /// Add a new completion hint for an argument, if needed
+    pub(crate) fn push_argument(&mut self, named: &NamedArg, metavar: &'static str) {
+        let depth = self.depth();
+        if let Some(comp) = self.comp_mut() {
+            if let Ok(name) = ShortLong::try_from(named) {
+                comp.comps.push(Comp::Argument {
+                    extra: CompExtra {
+                        depth,
+                        group: None,
+                        help: named.help.as_ref().and_then(Doc::to_completion),
+                    },
+                    metavar,
+                    name,
+                });
+            }
+        }
+    }
+
+    /// Add a new completion hint for metadata, if needed
+    ///
+    /// `is_argument` is set to true when we are trying to parse the value and false if
+    /// when meta
+    pub(crate) fn push_metavar(
+        &mut self,
+        meta: &'static str,
+        help: &Option<Doc>,
+        is_argument: bool,
+    ) {
+        let depth = self.depth();
+        if let Some(comp) = self.comp_mut() {
+            let extra = CompExtra {
+                depth,
+                group: None,
+                help: help.as_ref().and_then(Doc::to_completion),
+            };
+
+            comp.comps.push(Comp::Metavariable {
+                extra,
+                meta,
+                is_argument,
+            });
+        }
+    }
+
+    /// Add a new completion hint for command, if needed
+    pub(crate) fn push_command(
+        &mut self,
+        name: &'static str,
+        short: Option<char>,
+        help: &Option<Doc>,
+    ) {
+        let depth = self.depth();
+        if let Some(comp) = self.comp_mut() {
+            comp.comps.push(Comp::Command {
+                extra: CompExtra {
+                    depth,
+                    group: None,
+                    help: help.as_ref().and_then(Doc::to_completion),
+                },
+                name,
+                short,
+            });
+        }
+    }
+
+    /// Clear collected completions if enabled
+    pub(crate) fn clear_comps(&mut self) {
+        if let Some(comp) = self.comp_mut() {
+            comp.comps.clear();
+        }
+    }
+
+    /// Insert a literal value with some description for completion
+    ///
+    /// In practice it's "--"
+    pub(crate) fn push_pos_sep(&mut self) {
+        let depth = self.depth();
+        if let Some(comp) = self.comp_mut() {
+            comp.comps.push(Comp::Value {
+                extra: CompExtra {
+                    depth,
+                    group: None,
+                    help: Some("Positional only items after this token".to_owned()),
+                },
+                body: "--".to_owned(),
+                is_argument: false,
+            });
+        }
+    }
+
+    /// Insert a bunch of items
+    pub(crate) fn push_with_group(&mut self, group: &Option<String>, comps: &mut Vec<Comp>) {
+        if let Some(comp) = self.comp_mut() {
+            for mut item in comps.drain(..) {
+                if let Some(group) = group.as_ref() {
+                    item.set_group(group.clone());
+                }
+                comp.comps.push(item);
+            }
+        }
+    }
+}
+
+impl Complete {
+    pub(crate) fn push_shell(&mut self, op: ShellComp, depth: usize) {
+        self.comps.push(Comp::Shell {
+            extra: CompExtra {
+                depth,
+                group: None,
+                help: None,
+            },
+            script: op,
+        });
+    }
+
+    pub(crate) fn push_value(
+        &mut self,
+        body: String,
+        help: Option<String>,
+        group: Option<String>,
+        depth: usize,
+        is_argument: bool,
+    ) {
+        self.comps.push(Comp::Value {
+            body,
+            is_argument,
+            extra: CompExtra { depth, group, help },
+        });
+    }
+
+    pub(crate) fn push_comp(&mut self, comp: Comp) {
+        self.comps.push(comp);
+    }
+
+    pub(crate) fn extend_comps(&mut self, comps: Vec<Comp>) {
+        self.comps.extend(comps);
+    }
+
+    pub(crate) fn drain_comps(&mut self) -> std::vec::Drain<Comp> {
+        self.comps.drain(0..)
+    }
+
+    pub(crate) fn swap_comps(&mut self, other: &mut Vec<Comp>) {
+        std::mem::swap(other, &mut self.comps);
+    }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct CompExtra {
+    /// Used by complete_gen to separate commands from each other
+    pub(crate) depth: usize,
+
+    /// Render this option in a group along with all other items with the same name
+    pub(crate) group: Option<String>,
+
+    /// help message attached to a completion item
+    pub(crate) help: Option<String>,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum Comp {
+    /// short or long flag
+    Flag {
+        extra: CompExtra,
+        name: ShortLong,
+    },
+
+    /// argument + metadata
+    Argument {
+        extra: CompExtra,
+        name: ShortLong,
+        metavar: &'static str,
+    },
+
+    ///
+    Command {
+        extra: CompExtra,
+        name: &'static str,
+        short: Option<char>,
+    },
+
+    /// comes from completed values, part of "dynamic" completion
+    Value {
+        extra: CompExtra,
+        body: String,
+        /// values from arguments (say -p=SPEC and user already typed "-p b"
+        /// should suppress all other options except for metavaraiables?
+        ///
+        is_argument: bool,
+    },
+
+    Metavariable {
+        extra: CompExtra,
+        meta: &'static str,
+        is_argument: bool,
+    },
+
+    Shell {
+        extra: CompExtra,
+        script: ShellComp,
+    },
+}
+
+impl Comp {
+    /// to avoid leaking items with higher depth into items with lower depth
+    fn depth(&self) -> usize {
+        match self {
+            Comp::Command { extra, .. }
+            | Comp::Value { extra, .. }
+            | Comp::Flag { extra, .. }
+            | Comp::Shell { extra, .. }
+            | Comp::Metavariable { extra, .. }
+            | Comp::Argument { extra, .. } => extra.depth,
+        }
+    }
+
+    /// completer needs to replace meta placeholder with actual values - uses this
+    ///
+    /// value indicates if it's an argument or a positional meta
+    pub(crate) fn is_metavar(&self) -> Option<bool> {
+        if let Comp::Metavariable { is_argument, .. } = self {
+            Some(*is_argument)
+        } else {
+            None
+        }
+    }
+
+    pub(crate) fn set_group(&mut self, group: String) {
+        let extra = match self {
+            Comp::Flag { extra, .. }
+            | Comp::Argument { extra, .. }
+            | Comp::Command { extra, .. }
+            | Comp::Value { extra, .. }
+            | Comp::Shell { extra, .. }
+            | Comp::Metavariable { extra, .. } => extra,
+        };
+        if extra.group.is_none() {
+            extra.group = Some(group);
+        }
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct ShowComp<'a> {
+    /// value to be actually inserted by the autocomplete system
+    pub(crate) subst: String,
+
+    /// pretty rendering which might include metavars, etc
+    pub(crate) pretty: String,
+
+    pub(crate) extra: &'a CompExtra,
+}
+
+impl std::fmt::Display for ShowComp<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        if let (Some(help), true) = (&self.extra.help, self.subst.is_empty()) {
+            write!(f, "{}: {}", self.pretty, help)
+        } else if let Some(help) = &self.extra.help {
+            write!(f, "{:24} -- {}", self.pretty, help)
+        } else {
+            write!(f, "{}", self.pretty)
+        }
+    }
+}
+
+impl Arg {
+    fn and_os_string(&self) -> Option<(&Self, &OsStr)> {
+        match self {
+            Arg::Short(_, _, s) => {
+                if s.is_empty() {
+                    None
+                } else {
+                    Some((self, s))
+                }
+            }
+            Arg::Long(_, _, s) | Arg::ArgWord(s) | Arg::Word(s) | Arg::PosWord(s) => {
+                Some((self, s))
+            }
+        }
+    }
+}
+
+fn pair_to_os_string<'a>(pair: (&'a Arg, &'a OsStr)) -> Option<(&'a Arg, &'a str)> {
+    Some((pair.0, pair.1.to_str()?))
+}
+
+#[derive(Debug, Copy, Clone)]
+enum Prefix<'a> {
+    NA,
+    Short(char),
+    Long(&'a str),
+}
+
+impl State {
+    /// Generate completion from collected heads
+    ///
+    /// before calling this method we run parser in "complete" mode and collect live heads inside
+    /// `self.comp`, this part goes over collected heads and generates possible completions from
+    /// that
+    pub(crate) fn check_complete(&self) -> Option<String> {
+        let comp = self.comp_ref()?;
+
+        let mut items = self
+            .items
+            .iter()
+            .rev()
+            .filter_map(Arg::and_os_string)
+            .filter_map(pair_to_os_string);
+
+        // try get a current item to complete - must be non-virtual right most one
+        // value must be present here, and can fail only for non-utf8 values
+        // can't do much completing with non-utf8 values since bpaf needs to print them to stdout
+        let (_, lit) = items.next()?;
+
+        // For cases like "-k=val", "-kval", "--key=val", "--key val"
+        // last value is going  to be either Arg::Word or Arg::ArgWord
+        // so to perform full completion we look at the preceeding item
+        // and use it's value if it was a composite short/long argument
+        let preceeding = items.next();
+        let (pos_only, full_lit) = match preceeding {
+            Some((Arg::Short(_, true, _os) | Arg::Long(_, true, _os), full_lit)) => {
+                (false, full_lit)
+            }
+            Some((Arg::PosWord(_), _)) => (true, lit),
+            _ => (false, lit),
+        };
+
+        let prefix = match preceeding {
+            Some((Arg::Short(s, true, _os), _lit)) => Prefix::Short(*s),
+            Some((Arg::Long(l, true, _os), _lit)) => Prefix::Long(l.as_str()),
+            _ => Prefix::NA,
+        };
+
+        let (items, shell) = comp.complete(lit, pos_only, prefix);
+
+        Some(match comp.output_rev {
+            0 => render_test(&items, &shell, full_lit),
+            1 => render_simple(&items), // <- AKA elvish
+            7 => render_zsh(&items, &shell, full_lit),
+            8 => render_bash(&items, &shell, full_lit),
+            9 => render_fish(&items, &shell, full_lit, self.path[0].as_str()),
+            unk => {
+                #[cfg(debug_assertions)]
+                {
+                    eprintln!("Unsupported output revision {}, you need to genenerate your shell completion files for the app", unk);
+                    std::process::exit(1);
+                }
+                #[cfg(not(debug_assertions))]
+                {
+                    std::process::exit(0);
+                }
+            }
+        }.unwrap())
+    }
+}
+
+/// Try to expand short string names into long names if possible
+fn preferred_name(name: ShortLong) -> String {
+    match name {
+        ShortLong::Short(s) => format!("-{}", s),
+        ShortLong::Long(l) | ShortLong::Both(_, l) => format!("--{}", l),
+    }
+}
+
+// check if argument can possibly match the argument passed in and returns a preferrable replacement
+fn arg_matches(arg: &str, name: ShortLong) -> Option<String> {
+    // "" and "-" match any flag
+    if arg.is_empty() || arg == "-" {
+        return Some(preferred_name(name));
+    }
+
+    let mut can_match = false;
+
+    // separately check for short and long names, fancy strip prefix things is here to avoid
+    // allocations and cloning
+    match name {
+        ShortLong::Long(_) => {}
+        ShortLong::Short(s) | ShortLong::Both(s, _) => {
+            can_match |= arg
+                .strip_prefix('-')
+                .and_then(|a| a.strip_prefix(s))
+                .map_or(false, str::is_empty);
+        }
+    }
+
+    // and long string too
+    match name {
+        ShortLong::Short(_) => {}
+        ShortLong::Long(l) | ShortLong::Both(_, l) => {
+            can_match |= arg.strip_prefix("--").map_or(false, |s| l.starts_with(s));
+        }
+    }
+
+    if can_match {
+        Some(preferred_name(name))
+    } else {
+        None
+    }
+}
+fn cmd_matches(arg: &str, name: &'static str, short: Option<char>) -> Option<&'static str> {
+    // partial long name and exact short name match anything
+    if name.starts_with(arg)
+        || short.map_or(false, |s| {
+            // avoid allocations
+            arg.strip_prefix(s).map_or(false, str::is_empty)
+        })
+    {
+        Some(name)
+    } else {
+        None
+    }
+}
+
+impl Comp {
+    /// this completion should suppress anything else that is not a value
+    fn only_value(&self) -> bool {
+        match self {
+            Comp::Flag { .. } | Comp::Argument { .. } | Comp::Command { .. } => false,
+            Comp::Metavariable { is_argument, .. } | Comp::Value { is_argument, .. } => {
+                *is_argument
+            }
+            Comp::Shell { .. } => true,
+        }
+    }
+    fn is_pos(&self) -> bool {
+        match self {
+            Comp::Flag { .. } | Comp::Argument { .. } | Comp::Command { .. } => false,
+            Comp::Value { is_argument, .. } => !is_argument,
+            Comp::Metavariable { .. } | Comp::Shell { .. } => true,
+        }
+    }
+}
+
+impl Complete {
+    fn complete(
+        &self,
+        arg: &str,
+        pos_only: bool,
+        prefix: Prefix,
+    ) -> (Vec<ShowComp>, Vec<ShellComp>) {
+        let mut items: Vec<ShowComp> = Vec::new();
+        let mut shell = Vec::new();
+        let max_depth = self.comps.iter().map(Comp::depth).max().unwrap_or(0);
+        let mut only_values = false;
+
+        for item in self
+            .comps
+            .iter()
+            .filter(|c| c.depth() == max_depth && (!pos_only || c.is_pos()))
+        {
+            match (only_values, item.only_value()) {
+                (true, true) | (false, false) => {}
+                (true, false) => continue,
+                (false, true) => {
+                    only_values = true;
+                    items.clear();
+                }
+            }
+
+            match item {
+                Comp::Command { name, short, extra } => {
+                    if let Some(long) = cmd_matches(arg, name, *short) {
+                        items.push(ShowComp {
+                            subst: long.to_string(),
+                            pretty: long.to_string(),
+                            extra,
+                        });
+                    }
+                }
+
+                Comp::Flag { name, extra } => {
+                    if let Some(long) = arg_matches(arg, *name) {
+                        items.push(ShowComp {
+                            pretty: long.clone(),
+                            subst: long,
+                            extra,
+                        });
+                    }
+                }
+
+                Comp::Argument {
+                    name,
+                    metavar,
+                    extra,
+                } => {
+                    if let Some(long) = arg_matches(arg, *name) {
+                        items.push(ShowComp {
+                            pretty: format!("{}={}", long, metavar),
+                            subst: long,
+                            extra,
+                        });
+                    }
+                }
+
+                Comp::Value {
+                    body,
+                    extra,
+                    is_argument: _,
+                } => {
+                    items.push(ShowComp {
+                        pretty: body.clone(),
+                        extra,
+                        subst: match prefix {
+                            Prefix::NA => body.clone(),
+                            Prefix::Short(s) => format!("-{}={}", s, body),
+                            Prefix::Long(l) => format!("--{}={}", l, body),
+                        },
+                    });
+                }
+
+                Comp::Metavariable {
+                    extra,
+                    meta,
+                    is_argument,
+                } => {
+                    if !is_argument && !pos_only && arg.starts_with('-') {
+                        continue;
+                    }
+                    items.push(ShowComp {
+                        subst: String::new(),
+                        pretty: (*meta).to_string(),
+                        extra,
+                    });
+                }
+
+                Comp::Shell { script, .. } => {
+                    shell.push(*script);
+                }
+            }
+        }
+
+        (items, shell)
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/complete_run.rs.html b/src/bpaf/complete_run.rs.html new file mode 100644 index 00000000..8a693140 --- /dev/null +++ b/src/bpaf/complete_run.rs.html @@ -0,0 +1,217 @@ +complete_run.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+
use crate::complete_gen::Complete;
+use std::ffi::OsStr;
+
+fn dump_bash_completer(name: &str) {
+    println!(
+        r#"_bpaf_dynamic_completion()
+{{
+    line="$1 --bpaf-complete-rev=8 ${{COMP_WORDS[@]:1}}"
+    if [[ ${{COMP_WORDS[-1]}} == "" ]]; then
+        line="${{line}} \"\""
+    fi
+    source <( eval ${{line}})
+}}
+complete -o nosort -F _bpaf_dynamic_completion {name}"#,
+        name = name,
+    );
+}
+
+fn dump_zsh_completer(name: &str) {
+    println!(
+        r#"#compdef {name}
+local line
+line="${{words[1]}} --bpaf-complete-rev=7 ${{words[@]:1}}"
+if [[ ${{words[-1]}} == "" ]]; then
+    line="${{line}} \"\""
+fi
+source <(eval ${{line}})
+"#,
+        name = name
+    );
+}
+
+fn dump_fish_completer(_name: &str) {
+    println!(
+        r#"set -l current (commandline --tokenize --current-process)
+set -l tmpline $current[1] --bpaf-complete-rev=9 $current[2..]
+if test (commandline --current-process) != (string trim (commandline --current-process))
+    set tmpline $tmpline ""
+end
+source ( $tmpline | psub )"#
+    );
+}
+
+// I would love to support elvish better but debugger is not a thing
+// and on any error in code it simply replies "no candidates" with no
+// obvious way even to print "you are here"...
+// https://github.com/elves/elvish/issues/803
+fn dump_elvish_completer(name: &str) {
+    println!(
+        "\
+set edit:completion:arg-completer[{name}] = {{ |@args| var args = $args[1..];
+     var @lines = ( {name} --bpaf-complete-rev={rev} $@args );
+     use str;
+     for line $lines {{
+         var @arg = (str:split \"\\t\" $line)
+         try {{
+             edit:complex-candidate $arg[0] &display=( printf \"%-19s %s\" $arg[0] $arg[1] )
+         }} catch {{
+             edit:complex-candidate $line
+         }}
+     }}
+}}",
+        name = name,
+        rev = 1,
+    );
+}
+
+#[derive(Debug)]
+pub(crate) struct ArgScanner<'a> {
+    pub(crate) revision: Option<usize>,
+    pub(crate) name: Option<&'a str>,
+}
+
+impl ArgScanner<'_> {
+    pub(crate) fn check_next(&mut self, arg: &OsStr) -> bool {
+        let arg = match arg.to_str() {
+            Some(arg) => arg,
+            None => return false,
+        };
+        // this only works when there's a name
+        if let Some(name) = &self.name {
+            let mut matched = true;
+            match arg {
+                "--bpaf-complete-style-zsh" => dump_zsh_completer(name),
+                "--bpaf-complete-style-bash" => dump_bash_completer(name),
+                "--bpaf-complete-style-fish" => dump_fish_completer(name),
+                "--bpaf-complete-style-elvish" => dump_elvish_completer(name),
+                _ => {
+                    matched = false;
+                }
+            }
+            if matched {
+                std::process::exit(0)
+            }
+        }
+        if let Some(ver) = arg.strip_prefix("--bpaf-complete-rev=") {
+            if let Ok(ver) = ver.parse::<usize>() {
+                self.revision = Some(ver);
+            }
+            return true;
+        }
+        false
+    }
+    pub(crate) fn done(&self) -> Option<Complete> {
+        Some(Complete::new(self.revision?))
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/complete_shell.rs.html b/src/bpaf/complete_shell.rs.html new file mode 100644 index 00000000..f522360b --- /dev/null +++ b/src/bpaf/complete_shell.rs.html @@ -0,0 +1,633 @@ +complete_shell.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+
use crate::{complete_gen::ShowComp, Error, Meta, Parser, State};
+
+struct Shell<'a>(&'a str);
+
+impl std::fmt::Display for Shell<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        use std::fmt::Write;
+        f.write_char('\'')?;
+        for c in self.0.chars() {
+            if c == '\'' {
+                f.write_str("'\\''")
+            } else {
+                f.write_char(c)
+            }?
+        }
+        f.write_char('\'')?;
+        Ok(())
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+/// Shell specific completion
+#[non_exhaustive]
+pub enum ShellComp {
+    /// A file or directory name with an optional file mask.
+    ///
+    /// For bash filemask should start with `*.` or contain only the
+    /// extension
+    File {
+        /// Optional filemask to use, no spaces, no tabs
+        mask: Option<&'static str>,
+    },
+
+    /// Similar to `File` but limited to directories only
+    /// For bash filemask should start with `*.` or contain only the
+    /// extension
+    Dir {
+        /// Optional filemask to use, no spaces, no tabs
+        mask: Option<&'static str>,
+    },
+
+    /// You can also specify a raw value to use for each supported shell
+    ///
+    /// It is possible to fill in values for shells you don't want to support
+    /// with empty strings but the code is not going to work for those shells
+    Raw {
+        /// This raw string will be used for `bash` shell
+        /// <https://www.gnu.org/software/bash/manual/html_node/Command-Line-Editing.html>
+        bash: &'static str,
+
+        /// This raw string will be used for `zsh` shell
+        /// <https://zsh.sourceforge.io/Doc/Release/Completion-System.html>
+        zsh: &'static str,
+
+        /// This raw string will be used for `fish` shell
+        /// <https://fishshell.com/docs/current/completions.html>
+        fish: &'static str,
+
+        /// This raw string will be used for `elvish` shell
+        /// <https://elv.sh/ref/edit.html#completion-api>
+        elvish: &'static str,
+    },
+
+    /// Don't produce anything at all from this parser - can be useful if you want to compose
+    /// bpaf completion with shell completion
+    Nothing,
+}
+
+/// Parser that inserts static shell completion into bpaf's dynamic shell completion
+#[cfg(feature = "autocomplete")]
+pub struct ParseCompShell<P> {
+    pub(crate) inner: P,
+    pub(crate) op: crate::complete_shell::ShellComp,
+}
+
+#[cfg(feature = "autocomplete")]
+impl<P, T> Parser<T> for ParseCompShell<P>
+where
+    P: Parser<T> + Sized,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        // same as with ParseComp the goal is to replace metavars added by inner parser
+        // with a completion that would call a bash script.
+        // unlike ParseComp we don't care if inner parser succeeds
+
+        // stash old completions
+        let mut comp_items = Vec::new();
+        args.swap_comps_with(&mut comp_items);
+
+        let res = self.inner.eval(args);
+
+        // at this point comp_items contains values added by the inner parser
+        args.swap_comps_with(&mut comp_items);
+
+        let depth = args.depth();
+        if let Some(comp) = args.comp_mut() {
+            for ci in comp_items {
+                if ci.is_metavar().is_some() {
+                    comp.push_shell(self.op, depth);
+                } else {
+                    comp.push_comp(ci);
+                }
+            }
+        }
+
+        res
+    }
+
+    fn meta(&self) -> Meta {
+        self.inner.meta()
+    }
+}
+
+pub(crate) fn render_zsh(
+    items: &[ShowComp],
+    ops: &[ShellComp],
+    full_lit: &str,
+) -> Result<String, std::fmt::Error> {
+    use std::fmt::Write;
+    let mut res = String::new();
+
+    if items.is_empty() && ops.is_empty() {
+        return Ok(format!("compadd -- {}\n", full_lit));
+    }
+
+    for op in ops {
+        match op {
+            ShellComp::File { mask: None } => writeln!(res, "_files"),
+            ShellComp::File { mask: Some(mask) } => writeln!(res, "_files -g {}", Shell(mask)),
+            ShellComp::Dir { mask: None } => writeln!(res, "_files -/"),
+            ShellComp::Dir { mask: Some(mask) } => writeln!(res, "_files -/ -g {}", Shell(mask)),
+            ShellComp::Raw { zsh, .. } => writeln!(res, "{}", Shell(zsh)),
+            ShellComp::Nothing => Ok(()),
+        }?;
+    }
+
+    if items.len() == 1 {
+        if items[0].subst.is_empty() {
+            writeln!(res, "compadd -- {}", Shell(items[0].pretty.as_str()))?;
+            writeln!(res, "compadd ''")?;
+            return Ok(res);
+        } else {
+            return Ok(format!("compadd -- {}\n", Shell(items[0].subst.as_str())));
+        }
+    }
+    writeln!(res, "local -a descr")?;
+
+    for item in items {
+        writeln!(res, "descr=({})", Shell(&item.to_string()))?;
+        //        writeln!(res, "args=(\"{}\")", item.subst)?;
+        if let Some(group) = &item.extra.group {
+            writeln!(
+                res,
+                "compadd -l -d descr -V {} -X {} -- {}",
+                Shell(group),
+                Shell(group),
+                Shell(&item.subst),
+            )?;
+        } else {
+            // it seems sorting as well as not sorting is done in a group,
+            // by default group contains just one element so and `-o nosort`
+            // does nothing, while `-V whatever` stops sorting...
+            writeln!(
+                res,
+                "compadd -l -V nosort -d descr -- {}",
+                Shell(&item.subst)
+            )?;
+        }
+    }
+    Ok(res)
+}
+
+pub(crate) fn render_bash(
+    items: &[ShowComp],
+    ops: &[ShellComp],
+    full_lit: &str,
+) -> Result<String, std::fmt::Error> {
+    // Bash is strange when it comes to completion - rather than taking
+    // a glob - _filedir takes an extension which it later to include uppercase
+    // version as well and to include "*." in front. For compatibility with
+    // zsh and other shells - this code strips "*." from the beginning....
+    fn bashmask(i: &str) -> &str {
+        i.strip_prefix("*.").unwrap_or(i)
+    }
+
+    use std::fmt::Write;
+    let mut res = String::new();
+
+    if items.is_empty() && ops.is_empty() {
+        return Ok(format!("COMPREPLY+=({})\n", Shell(full_lit)));
+    }
+
+    for op in ops {
+        match op {
+            ShellComp::File { mask: None } => write!(res, "_filedir"),
+            ShellComp::File { mask: Some(mask) } => {
+                writeln!(res, "_filedir '{}'", Shell(bashmask(mask)))
+            }
+            ShellComp::Dir { mask: None } => write!(res, "_filedir -d"),
+            ShellComp::Dir { mask: Some(mask) } => {
+                writeln!(res, "_filedir -d '{}'", Shell(bashmask(mask)))
+            }
+            ShellComp::Raw { bash, .. } => writeln!(res, "{}", Shell(bash)),
+            ShellComp::Nothing => Ok(()),
+        }?;
+    }
+
+    if items.len() == 1 {
+        if items[0].subst.is_empty() {
+            writeln!(res, "COMPREPLY+=( {} '')", Shell(&items[0].pretty))?;
+        } else {
+            writeln!(res, "COMPREPLY+=( {} )\n", Shell(&items[0].subst))?;
+        }
+
+        return Ok(res);
+    }
+    let mut prev = "";
+    for item in items.iter() {
+        if let Some(group) = &item.extra.group {
+            if prev != group {
+                prev = group;
+                writeln!(res, "COMPREPLY+=({})", Shell(group))?;
+            }
+        }
+        writeln!(res, "COMPREPLY+=({})", Shell(&item.to_string()))?;
+    }
+
+    Ok(res)
+}
+
+pub(crate) fn render_test(
+    items: &[ShowComp],
+    ops: &[ShellComp],
+    lit: &str,
+) -> Result<String, std::fmt::Error> {
+    use std::fmt::Write;
+
+    if items.is_empty() && ops.is_empty() {
+        return Ok(format!("{}\n", lit));
+    }
+
+    if items.len() == 1 && ops.is_empty() && !items[0].subst.is_empty() {
+        return Ok(items[0].subst.clone());
+    }
+
+    let mut res = String::new();
+    for op in items {
+        writeln!(
+            res,
+            "{}\t{}\t{}\t{}",
+            op.subst,
+            op.pretty,
+            op.extra.group.as_deref().unwrap_or(""),
+            op.extra.help.as_deref().unwrap_or("")
+        )?;
+    }
+    writeln!(res)?;
+    for op in ops {
+        writeln!(res, "{:?}", op)?;
+    }
+
+    Ok(res)
+}
+
+pub(crate) fn render_fish(
+    items: &[ShowComp],
+    ops: &[ShellComp],
+    full_lit: &str,
+    app: &str,
+) -> Result<String, std::fmt::Error> {
+    use std::fmt::Write;
+    let mut res = String::new();
+    if items.is_empty() && ops.is_empty() {
+        return Ok(format!("complete -c {} --arguments={}", app, full_lit));
+    }
+    let shared = if ops.is_empty() { "-f " } else { "" };
+    for item in items.iter().rev().filter(|i| !i.subst.is_empty()) {
+        write!(res, "complete -c {} {}", app, shared)?;
+        if let Some(long) = item.subst.strip_prefix("--") {
+            write!(res, "--long-option {} ", long)?;
+        } else if let Some(short) = item.subst.strip_prefix('-') {
+            write!(res, "--short-option {} ", short)?;
+        } else {
+            write!(res, "-a {} ", item.subst)?;
+        }
+        if let Some(help) = item.extra.help.as_deref() {
+            write!(res, "-d {:?}", help)?;
+        }
+        writeln!(res)?;
+    }
+
+    Ok(res)
+}
+
+pub(crate) fn render_simple(items: &[ShowComp]) -> Result<String, std::fmt::Error> {
+    use std::fmt::Write;
+    let mut res = String::new();
+    if items.len() == 1 {
+        writeln!(res, "{}", items[0].subst)?;
+    } else {
+        for item in items {
+            if let Some(descr) = item.extra.help.as_deref() {
+                writeln!(
+                    res,
+                    "{}\t{}",
+                    item.subst,
+                    descr.split('\n').next().unwrap_or("")
+                )
+            } else {
+                writeln!(res, "{}", item.subst)
+            }?;
+        }
+    }
+    Ok(res)
+}
+
\ No newline at end of file diff --git a/src/bpaf/doc.rs.html b/src/bpaf/doc.rs.html new file mode 100644 index 00000000..9adf8e3b --- /dev/null +++ b/src/bpaf/doc.rs.html @@ -0,0 +1,123 @@ +doc.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+
//! Documentation generation system
+//!
+//! # Command line parser documentation generation
+//!
+//! [`OptionParser`] implements two methods: [`render_html`](OptionParser::render_html) and
+//! [`render_manpage`](OptionParser::render_manpage) that create a documentation in a mix of
+//! html/markdown and ROFF formats respectively.
+//!
+//! To use it you should do something like this
+//! ```
+//! #[test]
+//! fn update_doc() {
+//!     # use bpaf::*;
+//!     # let options = || short('a').switch().to_options();
+//!     let options = options();
+//!     let md = options.render_markdown("app_name");
+//!     let roff = options.render_manpage("app_name", Section::General, None, None, None);
+//!     # drop(md); drop(roff);
+//!     // then save those docs into a files
+//!     // If you commit those docs into your repo and optionally fail a test if there
+//!     // are changes - CI will ensure that documentation is always up to date
+//! }
+//! ```
+//!
+//! # Documentation fragments to use inside `--help` messages
+//!
+//! `bpaf` tries to use semantic approach to documentation generation, instead of describing what
+//! color specific string slice should be you need to specify what this string slice supposed to
+//! mean.
+//!
+//! Most of the help related functions take `Into<Doc>` parameters, normally you would pass one of
+//! following things:
+//!
+//! 1. Ready made `Doc` - usually with combinatoric API
+//! ```ignore
+//! # use bpaf::doc::Doc;
+//! let mut doc = Doc::default();
+//! doc.emphasis("Usage: ");
+//! doc.literal("my_program");
+//! // do something with it
+//! drop(doc)
+//! ```
+//! 2. A string slice - `&str` can be converted into a fully plain text `Doc` which is enough
+//!    for most applications
+//!
+//! 3. A slice of style value pairs
+#![cfg_attr(not(doctest), doc = include_str!("docs2/help.md"))]
+//!
+//! 4. A structure from your own crate that can be converted into `Doc`
+//!
+
+#[doc(inline)]
+pub use crate::buffer::{Doc, MetaInfo, Style};
+
+#[doc(inline)]
+#[cfg(feature = "docgen")]
+pub use crate::buffer::Section;
+
+#[cfg(doc)]
+use crate::*;
+
\ No newline at end of file diff --git a/src/bpaf/error.rs.html b/src/bpaf/error.rs.html new file mode 100644 index 00000000..021eb45e --- /dev/null +++ b/src/bpaf/error.rs.html @@ -0,0 +1,1295 @@ +error.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+
use std::ops::Range;
+
+use crate::{
+    args::{Arg, State},
+    buffer::{Block, Color, Doc, Style, Token},
+    item::{Item, ShortLong},
+    meta_help::Metavar,
+    meta_youmean::{Suggestion, Variant},
+    Meta,
+};
+
+/// Unsuccessful command line parsing outcome, internal representation
+#[derive(Debug)]
+pub struct Error(pub(crate) Message);
+
+impl Error {
+    pub(crate) fn combine_with(self, other: Self) -> Self {
+        Error(self.0.combine_with(other.0))
+    }
+}
+
+#[derive(Debug)]
+pub(crate) enum Message {
+    // those can be caught ---------------------------------------------------------------
+    /// Tried to consume an env variable with no fallback, variable was not set
+    NoEnv(&'static str),
+
+    /// User specified an error message on some
+    ParseSome(&'static str),
+
+    /// User asked for parser to fail explicitly
+    ParseFail(&'static str),
+
+    /// pure_with failed to parse a value
+    PureFailed(String),
+
+    /// Expected one of those values
+    ///
+    /// Used internally to generate better error messages
+    Missing(Vec<MissingItem>),
+
+    // those cannot be caught-------------------------------------------------------------
+    /// Parsing failed and this is the final output
+    ParseFailure(ParseFailure),
+    /// Tried to consume a strict positional argument, value was present but was not strictly
+    /// positional
+    StrictPos(usize, Metavar),
+
+    /// Parser provided by user failed to parse a value
+    ParseFailed(Option<usize>, String),
+
+    /// Parser provided by user failed to validate a value
+    GuardFailed(Option<usize>, &'static str),
+
+    /// Argument requres a value but something else was passed,
+    /// required: --foo <BAR>
+    /// given: --foo --bar
+    ///        --foo -- bar
+    ///        --foo
+    NoArgument(usize, Metavar),
+
+    /// Parser is expected to consume all the things from the command line
+    /// this item will contain an index of the unconsumed value
+    Unconsumed(/* TODO - unused? */ usize),
+
+    /// argument is ambigoups - parser can accept it as both a set of flags and a short flag with no =
+    Ambiguity(usize, String),
+
+    /// Suggested fixes for typos or missing input
+    Suggestion(usize, Suggestion),
+
+    /// Two arguments are mutually exclusive
+    /// --release --dev
+    Conflict(/* winner */ usize, usize),
+
+    /// Expected one or more items in the scope, got someting else if any
+    Expected(Vec<Item>, Option<usize>),
+
+    /// Parameter is accepted but only once
+    OnlyOnce(/* winner */ usize, usize),
+}
+
+impl Message {
+    pub(crate) fn can_catch(&self) -> bool {
+        match self {
+            Message::NoEnv(_)
+            | Message::ParseSome(_)
+            | Message::ParseFail(_)
+            | Message::Missing(_)
+            | Message::PureFailed(_) => true,
+            Message::StrictPos(_, _)
+            | Message::ParseFailed(_, _)
+            | Message::GuardFailed(_, _)
+            | Message::Unconsumed(_)
+            | Message::Ambiguity(_, _)
+            | Message::Suggestion(_, _)
+            | Message::Conflict(_, _)
+            | Message::ParseFailure(_)
+            | Message::Expected(_, _)
+            | Message::OnlyOnce(_, _)
+            | Message::NoArgument(_, _) => false,
+        }
+    }
+}
+
+/// Missing item in a context
+#[derive(Debug, Clone)]
+pub struct MissingItem {
+    /// Item that is missing
+    pub(crate) item: Item,
+    /// Position it is missing from - exact for positionals, earliest possible for flags
+    pub(crate) position: usize,
+    /// Range where search was performed, important for combinators that narrow the search scope
+    /// such as adjacent
+    pub(crate) scope: Range<usize>,
+}
+
+impl Message {
+    #[must_use]
+    pub(crate) fn combine_with(self, other: Self) -> Self {
+        #[allow(clippy::match_same_arms)]
+        match (self, other) {
+            // help output takes priority
+            (a @ Message::ParseFailure(_), _) => a,
+            (_, b @ Message::ParseFailure(_)) => b,
+
+            // combine missing elements
+            (Message::Missing(mut a), Message::Missing(mut b)) => {
+                a.append(&mut b);
+                Message::Missing(a)
+            }
+
+            // otherwise earliest wins
+            (a, b) => {
+                if a.can_catch() {
+                    b
+                } else {
+                    a
+                }
+            }
+        }
+    }
+}
+
+/// Unsuccessful command line parsing outcome, use it for unit tests
+///
+/// When [`OptionParser::run_inner`](crate::OptionParser::run_inner) produces `Err(ParseFailure)`
+/// it means that the parser couldn't produce the value it supposed to produce and the program
+/// should terminate.
+///
+/// If you are handling variants manually - `Stdout` contains formatted output and you can use any
+/// logging framework to produce the output, `Completion` should be printed to stdout unchanged -
+/// shell completion mechanism relies on that. In both cases application should exit with error
+/// code of 0. `Stderr` variant indicates a genuinly parsing error which should be printed to
+/// stderr or a logging framework of your choice as an error and the app should exit with error
+/// code of 1. [`ParseFailure::exit_code`] is a helper method that performs printing and produces
+/// the exit code to use.
+///
+/// For purposes of for unit testing for user parsers, you can consume it with
+/// [`ParseFailure::unwrap_stdout`] and [`ParseFailure::unwrap_stdout`] - both of which produce a
+/// an unformatted `String` that parser might produce if failure type is correct or panics
+/// otherwise.
+#[derive(Clone, Debug)]
+pub enum ParseFailure {
+    /// Print this to stdout and exit with success code
+    Stdout(Doc, bool),
+    /// This also goes to stdout with exit code of 0,
+    /// this cannot be Doc because completion needs more control about rendering
+    Completion(String),
+    /// Print this to stderr and exit with failure code
+    Stderr(Doc),
+}
+
+impl ParseFailure {
+    /// Returns the contained `stderr` values - for unit tests
+    ///
+    /// # Panics
+    ///
+    /// Panics if failure contains `stdout`
+    #[allow(clippy::must_use_candidate)]
+    #[track_caller]
+    pub fn unwrap_stderr(self) -> String {
+        match self {
+            Self::Stderr(err) => err.monochrome(true),
+            Self::Completion(..) | Self::Stdout(..) => panic!("not an stderr: {:?}", self),
+        }
+    }
+
+    /// Returns the contained `stdout` values - for unit tests
+    ///
+    /// # Panics
+    ///
+    /// Panics if failure contains `stderr`
+    #[allow(clippy::must_use_candidate)]
+    #[track_caller]
+    pub fn unwrap_stdout(self) -> String {
+        match self {
+            Self::Stdout(err, full) => err.monochrome(full),
+            Self::Completion(s) => s,
+            Self::Stderr(..) => panic!("not an stdout: {:?}", self),
+        }
+    }
+
+    /// Returns the exit code for the failure
+    #[allow(clippy::must_use_candidate)]
+    pub fn exit_code(self) -> i32 {
+        match self {
+            Self::Stdout(..) | Self::Completion(..) => 0,
+            Self::Stderr(..) => 1,
+        }
+    }
+
+    /// Prints a message to `stdout` or `stderr` appropriate to the failure.
+    pub fn print_mesage(&self, max_width: usize) {
+        let color = Color::default();
+        match self {
+            ParseFailure::Stdout(msg, full) => {
+                println!("{}", msg.render_console(*full, color, max_width));
+            }
+            ParseFailure::Completion(s) => {
+                print!("{}", s);
+            }
+            ParseFailure::Stderr(msg) => {
+                #[allow(unused_mut)]
+                let mut error;
+                #[cfg(not(feature = "color"))]
+                {
+                    error = "Error: ";
+                }
+
+                #[cfg(feature = "color")]
+                {
+                    error = String::new();
+                    color.push_str(Style::Invalid, &mut error, "Error: ");
+                }
+
+                eprintln!("{}{}", error, msg.render_console(true, color, max_width));
+            }
+        }
+    }
+}
+
+fn check_conflicts(args: &State) -> Option<Message> {
+    let (loser, winner) = args.conflict()?;
+    Some(Message::Conflict(winner, loser))
+}
+
+fn textual_part(args: &State, ix: Option<usize>) -> Option<std::borrow::Cow<str>> {
+    match args.items.get(ix?)? {
+        Arg::Short(_, _, _) | Arg::Long(_, _, _) => None,
+        Arg::ArgWord(s) | Arg::Word(s) | Arg::PosWord(s) => Some(s.to_string_lossy()),
+    }
+}
+
+fn only_once(args: &State, cur: usize) -> Option<usize> {
+    if cur == 0 {
+        return None;
+    }
+    let mut iter = args.items[..cur].iter().rev();
+    let offset = match args.items.get(cur)? {
+        Arg::Short(s, _, _) => iter.position(|a| a.match_short(*s)),
+        Arg::Long(l, _, _) => iter.position(|a| a.match_long(l)),
+        Arg::ArgWord(_) | Arg::Word(_) | Arg::PosWord(_) => None,
+    };
+    Some(cur - offset? - 1)
+}
+
+impl Message {
+    #[allow(clippy::too_many_lines)] // it's a huge match with lots of simple cases
+    pub(crate) fn render(mut self, args: &State, meta: &Meta) -> ParseFailure {
+        // try to come up with a better error message for a few cases
+        match self {
+            Message::Unconsumed(ix) => {
+                if let Some(conflict) = check_conflicts(args) {
+                    self = conflict;
+                } else if let Some((ix, suggestion)) = crate::meta_youmean::suggest(args, meta) {
+                    self = Message::Suggestion(ix, suggestion);
+                } else if let Some(prev_ix) = only_once(args, ix) {
+                    self = Message::OnlyOnce(prev_ix, ix);
+                }
+            }
+            Message::Missing(xs) => {
+                self = summarize_missing(&xs, meta, args);
+            }
+            _ => {}
+        }
+
+        let mut doc = Doc::default();
+        match self {
+            // already rendered
+            Message::ParseFailure(f) => return f,
+
+            // this case is handled above
+            Message::Missing(_) => {
+                // this one is unreachable
+            }
+
+            // Error: --foo is not expected in this context
+            Message::Unconsumed(ix) => {
+                let item = &args.items[ix];
+                doc.token(Token::BlockStart(Block::TermRef));
+                doc.write(item, Style::Invalid);
+                doc.token(Token::BlockEnd(Block::TermRef));
+                doc.text(" is not expected in this context");
+            }
+
+            // Error: environment variable FOO is not set
+            Message::NoEnv(name) => {
+                doc.text("environment variable ");
+                doc.token(Token::BlockStart(Block::TermRef));
+                doc.invalid(name);
+                doc.token(Token::BlockEnd(Block::TermRef));
+                doc.text(" is not set");
+            }
+
+            // Error: FOO expected to be  in the right side of --
+            Message::StrictPos(_ix, metavar) => {
+                doc.text("expected ");
+                doc.token(Token::BlockStart(Block::TermRef));
+                doc.metavar(metavar);
+                doc.token(Token::BlockEnd(Block::TermRef));
+                doc.text(" to be on the right side of ");
+                doc.token(Token::BlockStart(Block::TermRef));
+                doc.literal("--");
+                doc.token(Token::BlockEnd(Block::TermRef));
+            }
+
+            // Error: <message from some or fail>
+            Message::ParseSome(s) | Message::ParseFail(s) => {
+                doc.text(s);
+            }
+
+            // Error: couldn't parse FIELD: <FromStr message>
+            Message::ParseFailed(mix, s) => {
+                doc.text("couldn't parse");
+                if let Some(field) = textual_part(args, mix) {
+                    doc.text(" ");
+                    doc.token(Token::BlockStart(Block::TermRef));
+                    doc.invalid(&field);
+                    doc.token(Token::BlockEnd(Block::TermRef));
+                }
+                doc.text(": ");
+                doc.text(&s);
+            }
+
+            // Error: ( FIELD:  | check failed: ) <message from guard>
+            Message::GuardFailed(mix, s) => {
+                if let Some(field) = textual_part(args, mix) {
+                    doc.token(Token::BlockStart(Block::TermRef));
+                    doc.invalid(&field);
+                    doc.token(Token::BlockEnd(Block::TermRef));
+                    doc.text(": ");
+                } else {
+                    doc.text("check failed: ");
+                }
+                doc.text(s);
+            }
+
+            // Error: --foo requires an argument FOO, got a flag --bar, try --foo=-bar to use it as an argument
+            // Error: --foo requires an argument FOO
+            Message::NoArgument(x, mv) => match args.get(x + 1) {
+                Some(Arg::Short(_, _, os) | Arg::Long(_, _, os)) => {
+                    let arg = &args.items[x];
+                    let os = &os.to_string_lossy();
+
+                    doc.token(Token::BlockStart(Block::TermRef));
+                    doc.write(arg, Style::Literal);
+                    doc.token(Token::BlockEnd(Block::TermRef));
+                    doc.text(" requires an argument ");
+                    doc.token(Token::BlockStart(Block::TermRef));
+                    doc.metavar(mv);
+                    doc.token(Token::BlockEnd(Block::TermRef));
+                    doc.text(", got a flag ");
+                    doc.token(Token::BlockStart(Block::TermRef));
+                    doc.write(os, Style::Invalid);
+                    doc.token(Token::BlockEnd(Block::TermRef));
+                    doc.text(", try ");
+                    doc.token(Token::BlockStart(Block::TermRef));
+                    doc.write(arg, Style::Literal);
+                    doc.literal("=");
+                    doc.write(os, Style::Literal);
+                    doc.token(Token::BlockEnd(Block::TermRef));
+                    doc.text(" to use it as an argument");
+                }
+                // "Some" part of this branch is actually unreachable
+                Some(Arg::ArgWord(_) | Arg::Word(_) | Arg::PosWord(_)) | None => {
+                    let arg = &args.items[x];
+                    doc.token(Token::BlockStart(Block::TermRef));
+                    doc.write(arg, Style::Literal);
+                    doc.token(Token::BlockEnd(Block::TermRef));
+                    doc.text(" requires an argument ");
+                    doc.token(Token::BlockStart(Block::TermRef));
+                    doc.metavar(mv);
+                    doc.token(Token::BlockEnd(Block::TermRef));
+                }
+            },
+            // Error: <message from pure_with>
+            Message::PureFailed(s) => {
+                doc.text(&s);
+            }
+            // Error: app supports -f as both an option and an option-argument, try to split -foo
+            // into invididual options (-f -o ..) or use -f=oo syntax to disambiguate
+            Message::Ambiguity(ix, name) => {
+                let mut chars = name.chars();
+                let first = chars.next().unwrap();
+                let rest = chars.as_str();
+                let second = chars.next().unwrap();
+                let s = args.items[ix].os_str().to_str().unwrap();
+
+                if let Some(name) = args.path.first() {
+                    doc.literal(name);
+                    doc.text(" supports ");
+                } else {
+                    doc.text("app supports ");
+                }
+
+                doc.token(Token::BlockStart(Block::TermRef));
+                doc.literal("-");
+                doc.write_char(first, Style::Literal);
+                doc.token(Token::BlockEnd(Block::TermRef));
+                doc.text(" as both an option and an option-argument, try to split ");
+                doc.token(Token::BlockStart(Block::TermRef));
+                doc.write(s, Style::Literal);
+                doc.token(Token::BlockEnd(Block::TermRef));
+                doc.text(" into individual options (");
+                doc.literal("-");
+                doc.write_char(first, Style::Literal);
+                doc.literal(" -");
+                doc.write_char(second, Style::Literal);
+                doc.literal(" ..");
+                doc.text(") or use ");
+                doc.token(Token::BlockStart(Block::TermRef));
+                doc.literal("-");
+                doc.write_char(first, Style::Literal);
+                doc.literal("=");
+                doc.literal(rest);
+                doc.token(Token::BlockEnd(Block::TermRef));
+                doc.text(" syntax to disambiguate");
+            }
+            // Error: No such (flag|argument|command), did you mean  ...
+            Message::Suggestion(ix, suggestion) => {
+                let actual = &args.items[ix].to_string();
+                match suggestion {
+                    Suggestion::Variant(v) => {
+                        let ty = match &args.items[ix] {
+                            _ if actual.starts_with('-') => "flag",
+                            Arg::Short(_, _, _) | Arg::Long(_, _, _) => "flag",
+                            Arg::ArgWord(_) => "argument value",
+                            Arg::Word(_) | Arg::PosWord(_) => "command or positional",
+                        };
+
+                        doc.text("no such ");
+                        doc.text(ty);
+                        doc.text(": ");
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.invalid(actual);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text(", did you mean ");
+                        doc.token(Token::BlockStart(Block::TermRef));
+
+                        match v {
+                            Variant::CommandLong(name) => doc.literal(name),
+                            Variant::Flag(ShortLong::Long(l) | ShortLong::Both(_, l)) => {
+                                doc.literal("--");
+                                doc.literal(l);
+                            }
+                            Variant::Flag(ShortLong::Short(s)) => {
+                                doc.literal("-");
+                                doc.write_char(s, Style::Literal);
+                            }
+                        };
+
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text("?");
+                    }
+                    Suggestion::MissingDash(name) => {
+                        doc.text("no such flag: ");
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.literal("-");
+                        doc.literal(name);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text(" (with one dash), did you mean ");
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.literal("--");
+                        doc.literal(name);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text("?");
+                    }
+                    Suggestion::ExtraDash(name) => {
+                        doc.text("no such flag: ");
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.literal("--");
+                        doc.write_char(name, Style::Literal);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text(" (with two dashes), did you mean ");
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.literal("-");
+                        doc.write_char(name, Style::Literal);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text("?");
+                    }
+                    Suggestion::Nested(x, v) => {
+                        let ty = match v {
+                            Variant::CommandLong(_) => "subcommand",
+                            Variant::Flag(_) => "flag",
+                        };
+                        doc.text(ty);
+                        doc.text(" ");
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.literal(actual);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text(
+                            " is not valid in this context, did you mean to pass it to command ",
+                        );
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.literal(&x);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text("?");
+                    }
+                }
+            }
+            // Error: Expected (no arguments|--foo), got ..., pass --help
+            Message::Expected(exp, actual) => {
+                doc.text("expected ");
+                match exp.len() {
+                    0 => {
+                        doc.text("no arguments");
+                    }
+                    1 => {
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.write_item(&exp[0]);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                    }
+                    2 => {
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.write_item(&exp[0]);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text(" or ");
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.write_item(&exp[1]);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                    }
+                    _ => {
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.write_item(&exp[0]);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text(", ");
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.write_item(&exp[1]);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text(", or more");
+                    }
+                }
+                match actual {
+                    Some(actual) => {
+                        doc.text(", got ");
+                        doc.token(Token::BlockStart(Block::TermRef));
+                        doc.write(&args.items[actual], Style::Invalid);
+                        doc.token(Token::BlockEnd(Block::TermRef));
+                        doc.text(". Pass ");
+                    }
+                    None => {
+                        doc.text(", pass ");
+                    }
+                }
+                doc.token(Token::BlockStart(Block::TermRef));
+                doc.literal("--help");
+                doc.token(Token::BlockEnd(Block::TermRef));
+                doc.text(" for usage information");
+            }
+
+            // Error: --intel cannot be used at the same time as --att
+            Message::Conflict(winner, loser) => {
+                doc.token(Token::BlockStart(Block::TermRef));
+                doc.write(&args.items[loser], Style::Literal);
+                doc.token(Token::BlockEnd(Block::TermRef));
+                doc.text(" cannot be used at the same time as ");
+                doc.token(Token::BlockStart(Block::TermRef));
+                doc.write(&args.items[winner], Style::Literal);
+                doc.token(Token::BlockEnd(Block::TermRef));
+            }
+
+            // Error: argument FOO cannot be used multiple times in this context
+            Message::OnlyOnce(_winner, loser) => {
+                doc.text("argument ");
+                doc.token(Token::BlockStart(Block::TermRef));
+                doc.write(&args.items[loser], Style::Literal);
+                doc.token(Token::BlockEnd(Block::TermRef));
+                doc.text(" cannot be used multiple times in this context");
+            }
+        };
+
+        ParseFailure::Stderr(doc)
+    }
+}
+
+/// go over all the missing items, pick the left most scope
+pub(crate) fn summarize_missing(items: &[MissingItem], inner: &Meta, args: &State) -> Message {
+    // missing items can belong to different scopes, pick the best scope to work with
+    let best_item = match items
+        .iter()
+        .max_by_key(|item| (item.position, item.scope.start))
+    {
+        Some(x) => x,
+        None => return Message::ParseSome("parser requires an extra flag, argument or parameter, but its name is hidden by the author"),
+    };
+
+    let mut best_scope = best_item.scope.clone();
+
+    let mut saw_command = false;
+    let expected = items
+        .iter()
+        .filter_map(|i| {
+            let cmd = matches!(i.item, Item::Command { .. });
+            if i.scope == best_scope && !(saw_command && cmd) {
+                saw_command |= cmd;
+                Some(i.item.clone())
+            } else {
+                None
+            }
+        })
+        .collect::<Vec<_>>();
+
+    best_scope.start = best_scope.start.max(best_item.position);
+    let mut args = args.clone();
+    args.set_scope(best_scope);
+    if let Some((ix, _arg)) = args.items_iter().next() {
+        if let Some((ix, sugg)) = crate::meta_youmean::suggest(&args, inner) {
+            Message::Suggestion(ix, sugg)
+        } else {
+            Message::Expected(expected, Some(ix))
+        }
+    } else {
+        Message::Expected(expected, None)
+    }
+}
+
+/*
+#[inline(never)]
+/// the idea is to post some context for the error
+fn snip(buffer: &mut Buffer, args: &State, items: &[usize]) {
+    for ix in args.scope() {
+        buffer.write(ix, Style::Text);
+    }
+}
+*/
+
\ No newline at end of file diff --git a/src/bpaf/from_os_str.rs.html b/src/bpaf/from_os_str.rs.html new file mode 100644 index 00000000..a7621614 --- /dev/null +++ b/src/bpaf/from_os_str.rs.html @@ -0,0 +1,53 @@ +from_os_str.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+
use std::{
+    any::{Any, TypeId},
+    ffi::OsString,
+    path::PathBuf,
+    str::FromStr,
+};
+
+pub(crate) fn parse_os_str<T>(os: OsString) -> Result<T, String>
+where
+    T: FromStr + 'static,
+    <T as std::str::FromStr>::Err: std::fmt::Display,
+{
+    if TypeId::of::<T>() == TypeId::of::<OsString>() {
+        let anybox: Box<dyn Any> = Box::new(os);
+        Ok(*(anybox.downcast::<T>().unwrap()))
+    } else if TypeId::of::<T>() == TypeId::of::<PathBuf>() {
+        let anybox: Box<dyn Any> = Box::new(PathBuf::from(os));
+        Ok(*(anybox.downcast::<T>().unwrap()))
+    } else {
+        match os.to_str() {
+            Some(s) => T::from_str(s).map_err(|e| e.to_string()),
+            None => Err(format!("{} is not a valid utf8", os.to_string_lossy())),
+        }
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/info.rs.html b/src/bpaf/info.rs.html new file mode 100644 index 00000000..b9998494 --- /dev/null +++ b/src/bpaf/info.rs.html @@ -0,0 +1,1425 @@ +info.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+
//! Help message generation and rendering
+
+use crate::{
+    args::{Args, State},
+    error::Message,
+    meta_help::render_help,
+    parsers::NamedArg,
+    short, Doc, Error, Meta, ParseFailure, Parser,
+};
+
+/// Information about the parser
+///
+/// No longer public, users are only interacting with it via [`OptionParser`]
+#[derive(Debug, Clone)]
+#[doc(hidden)]
+pub struct Info {
+    /// version field, see [`version`][Info::version]
+    pub version: Option<Doc>,
+    /// Custom description field, see [`descr`][Info::descr]
+    pub descr: Option<Doc>,
+    /// Custom header field, see [`header`][Info::header]
+    pub header: Option<Doc>,
+    /// Custom footer field, see [`footer`][Info::footer]
+    pub footer: Option<Doc>,
+    /// Custom usage field, see [`usage`][Info::usage]
+    pub usage: Option<Doc>,
+    pub help_arg: NamedArg,
+    pub version_arg: NamedArg,
+    pub help_if_no_args: bool,
+    pub max_width: usize,
+}
+
+impl Default for Info {
+    fn default() -> Self {
+        Self {
+            version: None,
+            descr: None,
+            header: None,
+            footer: None,
+            usage: None,
+            help_arg: short('h').long("help").help("Prints help information"),
+            version_arg: short('V')
+                .long("version")
+                .help("Prints version information"),
+            help_if_no_args: false,
+            max_width: 100,
+        }
+    }
+}
+
+/// Ready to run [`Parser`] with additional information attached
+///
+/// Created with [`to_options`](Parser::to_options)
+///
+/// In addition to the inner parser `OptionParser` contains documentation about a program or a
+/// subcommand as a whole, version, custom usage, if specified, and handles custom parsers for
+/// `--version` and `--help` flags.
+pub struct OptionParser<T> {
+    pub(crate) inner: Box<dyn Parser<T>>,
+    pub(crate) info: Info,
+}
+
+impl<T> OptionParser<T> {
+    /// Execute the [`OptionParser`], extract a parsed value or print some diagnostic and exit
+    ///
+    /// # Usage
+    /// ```no_run
+    /// # use bpaf::*;
+    /// /// Parses number of repetitions of `-v` on a command line
+    /// fn verbosity() -> OptionParser<usize> {
+    ///     let parser = short('v')
+    ///         .req_flag(())
+    ///         .many()
+    ///         .map(|xs|xs.len());
+    ///
+    ///     parser
+    ///         .to_options()
+    ///         .descr("Takes verbosity flag and does nothing else")
+    /// }
+    ///
+    /// fn main() {
+    ///     let verbosity: usize = verbosity().run();
+    /// }
+    /// ```
+    #[must_use]
+    pub fn run(self) -> T
+    where
+        Self: Sized,
+    {
+        match self.run_inner(Args::current_args()) {
+            Ok(t) => t,
+            Err(err) => {
+                err.print_mesage(self.info.max_width);
+                std::process::exit(err.exit_code())
+            }
+        }
+    }
+
+    /// Execute the [`OptionParser`], extract a parsed value or return a [`ParseFailure`]
+    ///
+    /// In most cases using [`run`](OptionParser::run) is sufficient, you can use `try_run` if you
+    /// want to control the exit code or you need to perform a custom cleanup.
+    ///
+    /// # Usage
+    /// ```no_run
+    /// # use bpaf::*;
+    /// /// Parses number of repetitions of `-v` on a command line
+    /// fn verbosity() -> OptionParser<usize> {
+    ///     let parser = short('v')
+    ///         .req_flag(())
+    ///         .many()
+    ///         .map(|xs|xs.len());
+    ///
+    ///     parser
+    ///         .to_options()
+    ///         .descr("Takes verbosity flag and does nothing else")
+    /// }
+    ///
+    /// fn main() {
+    ///     let verbosity: Option<usize> = match verbosity().try_run() {
+    ///         Ok(v) => Some(v),
+    ///         Err(ParseFailure::Stdout(buf, full)) => {
+    ///             print!("{}", buf.monochrome(full));
+    ///             None
+    ///         }
+    ///         Err(ParseFailure::Completion(msg)) => {
+    ///             print!("{}", msg);
+    ///             None
+    ///         }
+    ///         Err(ParseFailure::Stderr(buf)) => {
+    ///             eprintln!("{}", buf.monochrome(true));
+    ///             None
+    ///         }
+    ///     };
+    ///
+    ///     // Run cleanup tasks
+    /// }
+    /// ```
+    ///
+    /// # Errors
+    ///
+    /// [`ParseFailure`] represents parsing errors, autocomplete results and generated `--help`
+    /// output.
+    #[deprecated = "You should switch to equivalent parser.run_inner(Args::current_args())"]
+    pub fn try_run(self) -> Result<T, ParseFailure>
+    where
+        Self: Sized,
+    {
+        self.run_inner(Args::current_args())
+    }
+
+    /// Execute the [`OptionParser`] and produce a values for unit tests or manual processing
+    ///
+    /// ```rust
+    /// # use bpaf::*;
+    /// # /*
+    /// #[test]
+    /// fn positional_argument() {
+    /// # */
+    ///     let parser =
+    ///         positional::<String>("FILE")
+    ///             .help("File to process")
+    ///             .to_options();
+    ///
+    ///     let help = parser
+    ///         .run_inner(&["--help"])
+    ///         .unwrap_err()
+    ///         .unwrap_stdout();
+    ///     let expected_help = "\
+    /// Usage: FILE
+    ///
+    /// Available positional items:
+    ///     FILE        File to process
+    ///
+    /// Available options:
+    ///     -h, --help  Prints help information
+    /// ";
+    ///     assert_eq!(expected_help, help);
+    /// # /*
+    /// }
+    /// # */
+    /// ```
+    ///
+    /// See also [`Args`] and it's `From` impls to produce input and
+    /// [`ParseFailure::unwrap_stderr`] / [`ParseFailure::unwrap_stdout`] for processing results.
+    ///
+    /// # Errors
+    ///
+    /// If parser can't produce desired result `run_inner` returns [`ParseFailure`]
+    /// which represents runtime behavior: one branch to print something to stdout and exit with
+    /// success and the other branch to print something to stderr and exit with failure.
+    ///
+    /// `bpaf` generates contents of this `ParseFailure` using expected textual output from
+    /// [`parse`](Parser::parse), stdout/stderr isn't actually captured.
+    ///
+    /// Exact string reperentations may change between versions including minor releases.
+    pub fn run_inner<'a>(&self, args: impl Into<Args<'a>>) -> Result<T, ParseFailure>
+    where
+        Self: Sized,
+    {
+        // prepare available short flags and arguments for disambiguation
+        let mut short_flags = Vec::new();
+        let mut short_args = Vec::new();
+        self.inner
+            .meta()
+            .collect_shorts(&mut short_flags, &mut short_args);
+        short_flags.extend(&self.info.help_arg.short);
+        short_flags.extend(&self.info.version_arg.short);
+        let args = args.into();
+        let mut err = None;
+        let mut state = State::construct(args, &short_flags, &short_args, &mut err);
+
+        // this only handles disambiguation failure in construct
+        if let Some(msg) = err {
+            return Err(msg.render(&state, &self.inner.meta()));
+        }
+
+        self.run_subparser(&mut state)
+    }
+
+    /// Run subparser, implementation detail
+    pub(crate) fn run_subparser(&self, args: &mut State) -> Result<T, ParseFailure> {
+        // process should work like this:
+        // - inner parser is evaluated, it returns Error
+        // - if error is finalized (ParseFailure) - it is simply propagated outwards,
+        //   otherwise we are making a few attempts at improving it after dealing with
+        //   autocomplete/help
+        //
+        // - generate autocomplete, if enabled
+        // - produce --help, --version
+        // - Try to improve error message and finalize it otherwise
+        //
+        // outer parser gets value in ParseFailure format
+
+        if self.info.help_if_no_args && args.is_empty() {
+            let buffer = render_help(
+                &args.path,
+                &self.info,
+                &self.inner.meta(),
+                &self.info.meta(),
+                true,
+            );
+            return Err(ParseFailure::Stdout(buffer, false));
+        };
+
+        let res = self.inner.eval(args);
+        if let Err(Error(Message::ParseFailure(failure))) = res {
+            return Err(failure);
+        }
+        #[cfg(feature = "autocomplete")]
+        if let Some(comp) = args.check_complete() {
+            return Err(ParseFailure::Completion(comp));
+        }
+
+        let err = match res {
+            Ok(ok) => {
+                if let Some((ix, _)) = args.items_iter().next() {
+                    Message::Unconsumed(ix)
+                } else {
+                    return Ok(ok);
+                }
+            }
+            Err(Error(err)) => err,
+        };
+
+        // handle --help and --version messages
+        if let Ok(extra) = self.info.eval(args) {
+            let mut detailed = false;
+            let buffer = match extra {
+                ExtraParams::Help(d) => {
+                    detailed = d;
+                    render_help(
+                        &args.path,
+                        &self.info,
+                        &self.inner.meta(),
+                        &self.info.meta(),
+                        true,
+                    )
+                }
+                ExtraParams::Version(v) => {
+                    use crate::buffer::{Block, Token};
+                    let mut buffer = Doc::default();
+                    buffer.token(Token::BlockStart(Block::Block));
+                    buffer.text("Version: ");
+                    buffer.doc(&v);
+                    buffer.token(Token::BlockEnd(Block::Block));
+                    buffer
+                }
+            };
+            return Err(ParseFailure::Stdout(buffer, detailed));
+        }
+        Err(err.render(args, &self.inner.meta()))
+    }
+
+    /// Get first line of description if Available
+    ///
+    /// Used internally to avoid duplicating description for [`command`].
+    #[must_use]
+    pub(crate) fn short_descr(&self) -> Option<Doc> {
+        self.info.descr.as_ref().and_then(Doc::first_line)
+    }
+
+    /// Set the version field.
+    ///
+    /// By default `bpaf` won't include any version info and won't accept `--version` switch.
+    ///
+    /// # Combinatoric usage
+    ///
+    /// ```rust
+    /// use bpaf::*;
+    /// fn options() -> OptionParser<bool>  {
+    ///    short('s')
+    ///        .switch()
+    ///        .to_options()
+    ///        .version(env!("CARGO_PKG_VERSION"))
+    /// }
+    /// ```
+    ///
+    /// # Derive usage
+    ///
+    /// `version` annotation is available after `options` and `command` annotations, takes
+    /// an optional argument - version value to use, otherwise `bpaf_derive` would use value from cargo.
+    ///
+    /// ```rust
+    /// # use bpaf::*;
+    /// #[derive(Debug, Clone, Bpaf)]
+    /// #[bpaf(options, version)]
+    /// struct Options {
+    ///     #[bpaf(short)]
+    ///     switch: bool
+    /// }
+    /// ```
+    ///
+    /// # Example
+    /// ```console
+    /// $ app --version
+    /// Version: 0.5.0
+    /// ```
+    #[must_use]
+    pub fn version<B: Into<Doc>>(mut self, version: B) -> Self {
+        self.info.version = Some(version.into());
+        self
+    }
+    /// Set the description field
+    ///
+    /// Description field should be 1-2 lines long briefly explaining program purpose. If
+    /// description field is present `bpaf` would print it right before the usage line.
+    ///
+    /// # Combinatoric usage
+    /// ```rust
+    /// # use bpaf::*;
+    /// fn options() -> OptionParser<bool>  {
+    ///    short('s')
+    ///        .switch()
+    ///        .to_options()
+    ///        .descr("This is a description")
+    ///        .header("This is a header")
+    ///        .footer("This is a footer")
+    /// }
+    /// ```
+    ///
+    /// # Derive usage
+    ///
+    /// `bpaf_derive` uses doc comments on the `struct` / `enum` to derive description, it skips single empty
+    /// lines and uses double empty lines break it into blocks. `bpaf_derive` would use first block as the
+    /// description, second block - header, third block - footer.
+    ///
+    /// ```rust
+    /// # use bpaf::*;
+    /// #[derive(Debug, Clone, Bpaf)]
+    /// #[bpaf(options, version)]
+    /// /// This is a description
+    /// ///
+    /// ///
+    /// /// This is a header
+    /// ///
+    /// ///
+    /// /// This is a footer
+    /// ///
+    /// ///
+    /// /// This is just a comment
+    /// struct Options {
+    ///     #[bpaf(short)]
+    ///     switch: bool
+    /// }
+    /// ```
+    ///
+    /// # Example
+    ///
+    /// ```console
+    /// This is a description
+    ///
+    /// Usage: [-s]
+    ///
+    /// This is a header
+    ///
+    /// Available options:
+    ///     -s
+    ///     -h, --help     Prints help information
+    ///     -V, --version  Prints version information
+    ///
+    /// This is a footer
+    /// ```
+    #[must_use]
+    pub fn descr<B: Into<Doc>>(mut self, descr: B) -> Self {
+        self.info.descr = Some(descr.into());
+        self
+    }
+
+    /// Set the header field
+    ///
+    /// `bpaf` displays the header between the usage line and a list of the available options in `--help` output
+    ///
+    /// # Combinatoric usage
+    /// ```rust
+    /// # use bpaf::*;
+    /// fn options() -> OptionParser<bool>  {
+    ///    short('s')
+    ///        .switch()
+    ///        .to_options()
+    ///        .descr("This is a description")
+    ///        .header("This is a header")
+    ///        .footer("This is a footer")
+    /// }
+    /// ```
+    ///
+    /// # Derive usage
+    ///
+    /// `bpaf_derive` uses doc comments on the `struct` / `enum` to derive description, it skips single empty
+    /// lines and uses double empty lines break it into blocks. `bpaf_derive` would use first block as the
+    /// description, second block - header, third block - footer.
+    ///
+    /// ```rust
+    /// # use bpaf::*;
+    /// #[derive(Debug, Clone, Bpaf)]
+    /// #[bpaf(options, version)]
+    /// /// This is a description
+    /// ///
+    /// ///
+    /// /// This is a header
+    /// ///
+    /// ///
+    /// /// This is a footer
+    /// ///
+    /// ///
+    /// /// This is just a comment
+    /// struct Options {
+    ///     #[bpaf(short)]
+    ///     switch: bool
+    /// }
+    /// ```
+    ///
+    /// # Example
+    ///
+    /// ```console
+    /// This is a description
+    ///
+    /// Usage: [-s]
+    ///
+    /// This is a header
+    ///
+    /// Available options:
+    ///     -s
+    ///     -h, --help     Prints help information
+    ///     -V, --version  Prints version information
+    ///
+    /// This is a footer
+    /// ```
+    #[must_use]
+    pub fn header<B: Into<Doc>>(mut self, header: B) -> Self {
+        self.info.header = Some(header.into());
+        self
+    }
+
+    /// Set the footer field
+    ///
+    /// `bpaf` displays the footer after list of the available options in `--help` output
+    ///
+    /// # Combinatoric usage
+    /// ```rust
+    /// # use bpaf::*;
+    /// fn options() -> OptionParser<bool>  {
+    ///    short('s')
+    ///        .switch()
+    ///        .to_options()
+    ///        .descr("This is a description")
+    ///        .header("This is a header")
+    ///        .footer("This is a footer")
+    /// }
+    /// ```
+    ///
+    /// # Derive usage
+    ///
+    /// `bpaf_derive` uses doc comments on the `struct` / `enum` to derive description, it skips single empty
+    /// lines and uses double empty lines break it into blocks. `bpaf_derive` would use first block as the
+    /// description, second block - header, third block - footer.
+    ///
+    /// ```rust
+    /// # use bpaf::*;
+    /// #[derive(Debug, Clone, Bpaf)]
+    /// #[bpaf(options, version)]
+    /// /// This is a description
+    /// ///
+    /// ///
+    /// /// This is a header
+    /// ///
+    /// ///
+    /// /// This is a footer
+    /// ///
+    /// ///
+    /// /// This is just a comment
+    /// struct Options {
+    ///     #[bpaf(short)]
+    ///     switch: bool
+    /// }
+    /// ```
+    ///
+    /// # Example
+    ///
+    /// ```console
+    /// This is a description
+    ///
+    /// Usage: [-s]
+    ///
+    /// This is a header
+    ///
+    /// Available options:
+    ///     -s
+    ///     -h, --help     Prints help information
+    ///     -V, --version  Prints version information
+    ///
+    /// This is a footer
+    /// ```
+    #[must_use]
+    pub fn footer<M: Into<Doc>>(mut self, footer: M) -> Self {
+        self.info.footer = Some(footer.into());
+        self
+    }
+
+    /// Set custom usage field
+    ///
+    /// Custom usage field to use instead of one derived by `bpaf`.
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/usage.md"))]
+    #[must_use]
+    pub fn usage<B>(mut self, usage: B) -> Self
+    where
+        B: Into<Doc>,
+    {
+        self.info.usage = Some(usage.into());
+        self
+    }
+
+    /// Generate new usage line using automatically derived usage
+    ///
+    /// You can customize the surroundings of the usage line while still
+    /// having part that frequently changes generated by bpaf
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/with_usage.md"))]
+    ///
+    /// At the moment this method is not directly supported by derive API,
+    /// but since it gives you an object of [`OptionParser<T>`](OptionParser)
+    /// type you can alter it using Combinatoric API:
+    /// ```text
+    /// #[derive(Debug, Clone, Bpaf)] {
+    /// pub struct Options {
+    ///     ...
+    /// }
+    ///
+    /// fn my_decor(usage: Doc) -> Doc {
+    ///     ...
+    /// }
+    ///
+    /// fn main() {
+    ///     let options = options().with_usage(my_decor).run();
+    ///     ...
+    /// }
+    /// ```
+    #[must_use]
+    pub fn with_usage<F>(mut self, f: F) -> Self
+    where
+        F: Fn(Doc) -> Doc,
+    {
+        let mut buf = Doc::default();
+        buf.write_meta(&self.inner.meta(), true);
+        self.info.usage = Some(f(buf));
+        self
+    }
+
+    /// Check the invariants `bpaf` relies on for normal operations
+    ///
+    /// Takes a parameter whether to check for cosmetic invariants or not
+    /// (max help width exceeding 120 symbols, etc), currently not in use
+    ///
+    /// Best used as part of your test suite:
+    /// ```no_run
+    /// # use bpaf::*;
+    /// #[test]
+    /// fn check_options() {
+    /// # let options = || short('p').switch().to_options();
+    ///     options().check_invariants(false)
+    /// }
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// `check_invariants` indicates problems with panic
+    pub fn check_invariants(&self, _cosmetic: bool) {
+        self.inner.meta().positional_invariant_check(true);
+    }
+
+    /// Customize parser for `--help`
+    ///
+    /// By default `bpaf` displays help when program is called with either `--help` or `-h`, you
+    /// can customize those names and description in the help message
+    ///
+    /// Note, `--help` is something user expects to work
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/custom_help_version.md"))]
+    #[must_use]
+    pub fn help_parser(mut self, parser: NamedArg) -> Self {
+        self.info.help_arg = parser;
+        self
+    }
+
+    /// Customize parser for `--version`
+    ///
+    /// By default `bpaf` displays version information when program is called with either `--version`
+    /// or `-V` (and version is available), you can customize those names and description in the help message
+    ///
+    /// Note, `--version` is something user expects to work
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/custom_help_version.md"))]
+    #[must_use]
+    pub fn version_parser(mut self, parser: NamedArg) -> Self {
+        self.info.version_arg = parser;
+        self
+    }
+
+    /// Print help if app was called with no parameters
+    ///
+    /// By default `bpaf` tries to parse command line options and displays the best possible
+    /// error it can come up with. If application requires a subcommand or some argument
+    /// and user specified none - it might be a better experience for user to print
+    /// the help message.
+    ///
+    /// ```rust
+    /// # use bpaf::*;
+    /// # fn options() -> OptionParser<bool> { short('a').switch().to_options() }
+    /// // create option parser in a usual way, derive or combinatoric API
+    /// let opts = options().fallback_to_usage().run();
+    /// ```
+    #[must_use]
+    pub fn fallback_to_usage(mut self) -> Self {
+        self.info.help_if_no_args = true;
+        self
+    }
+
+    /// Set the width of the help message printed to the terminal upon failure
+    ///
+    /// By default, the help message is printed with a width of 100 characters.
+    /// This method allows to change where the help message is wrapped.
+    ///
+    /// Setting the max width too low may negatively affect the readability of the help message.
+    /// Also, the alignment padding of broken lines is always applied.
+    #[must_use]
+    pub fn max_width(mut self, width: usize) -> Self {
+        self.info.max_width = width;
+        self
+    }
+}
+
+impl Info {
+    #[inline(never)]
+    fn mk_help_parser(&self) -> impl Parser<()> {
+        self.help_arg.clone().req_flag(())
+    }
+    #[inline(never)]
+    fn mk_version_parser(&self) -> impl Parser<()> {
+        self.version_arg.clone().req_flag(())
+    }
+}
+
+impl Parser<ExtraParams> for Info {
+    fn eval(&self, args: &mut State) -> Result<ExtraParams, Error> {
+        let help = self.mk_help_parser();
+        if help.eval(args).is_ok() {
+            return Ok(ExtraParams::Help(help.eval(args).is_ok()));
+        }
+
+        if let Some(version) = &self.version {
+            if self.mk_version_parser().eval(args).is_ok() {
+                return Ok(ExtraParams::Version(version.clone()));
+            }
+        }
+
+        // error message is not actually used anywhere
+        Err(Error(Message::ParseFail("not a version or help")))
+    }
+
+    fn meta(&self) -> Meta {
+        let help = self.mk_help_parser().meta();
+        match &self.version {
+            Some(_) => Meta::And(vec![help, self.mk_version_parser().meta()]),
+            None => help,
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum ExtraParams {
+    Help(bool),
+    Version(Doc),
+}
+
\ No newline at end of file diff --git a/src/bpaf/item.rs.html b/src/bpaf/item.rs.html new file mode 100644 index 00000000..9f574b0c --- /dev/null +++ b/src/bpaf/item.rs.html @@ -0,0 +1,287 @@ +item.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+
use crate::{info::Info, meta_help::Metavar, parsers::NamedArg, Doc, Meta};
+
+#[doc(hidden)]
+#[derive(Clone, Debug)]
+pub enum Item {
+    Any {
+        metavar: Doc,
+        /// used by any, moves it from positionals into arguments
+        anywhere: bool,
+        help: Option<Doc>,
+    },
+    /// Positional item, consumed from the the front of the arguments
+    /// <FILE>
+    Positional { metavar: Metavar, help: Option<Doc> },
+    Command {
+        name: &'static str,
+        short: Option<char>,
+        help: Option<Doc>,
+        meta: Box<Meta>,
+        info: Box<Info>,
+    },
+    /// short or long name, consumed anywhere
+    /// -f
+    /// --file
+    Flag {
+        name: ShortLong,
+        /// used for disambiguation
+        shorts: Vec<char>,
+        env: Option<&'static str>,
+        help: Option<Doc>,
+    },
+    /// Short or long name followed by a value, consumed anywhere
+    /// -f <VAL>
+    /// --file <VAL>
+    Argument {
+        name: ShortLong,
+        /// used for disambiguation
+        shorts: Vec<char>,
+        metavar: Metavar,
+        env: Option<&'static str>,
+        help: Option<Doc>,
+    },
+}
+
+impl Item {
+    pub(crate) fn is_pos(&self) -> bool {
+        match self {
+            Item::Any { anywhere, .. } => !anywhere,
+            Item::Positional { .. } | Item::Command { .. } => true,
+            Item::Flag { .. } | Item::Argument { .. } => false,
+        }
+    }
+    /// Normalize name inside [`ShortLong`] into either short or long
+    pub(crate) fn normalize(&mut self, short: bool) {
+        match self {
+            Item::Positional { .. } | Item::Command { .. } | Item::Any { .. } => {}
+            Item::Flag { name, .. } | Item::Argument { name, .. } => name.normalize(short),
+        }
+    }
+}
+
+#[doc(hidden)]
+#[derive(Copy, Clone, Debug)]
+pub enum ShortLong {
+    Short(char),
+    Long(&'static str),
+    Both(char, &'static str),
+}
+
+impl ShortLong {
+    pub(crate) fn as_long(&self) -> Option<&'static str> {
+        match self {
+            ShortLong::Long(l) | ShortLong::Both(_, l) => Some(l),
+            ShortLong::Short(_) => None,
+        }
+    }
+    pub(crate) fn as_short(&self) -> Option<char> {
+        match self {
+            ShortLong::Short(s) | ShortLong::Both(s, _) => Some(*s),
+            ShortLong::Long(_) => None,
+        }
+    }
+}
+
+impl PartialEq<&str> for ShortLong {
+    fn eq(&self, other: &&str) -> bool {
+        fn short_eq(c: char, s: &str) -> bool {
+            let mut tmp = [0u8; 4];
+            s.strip_prefix('-') == Some(c.encode_utf8(&mut tmp))
+        }
+        fn long_eq(l: &str, s: &str) -> bool {
+            Some(l) == s.strip_prefix("--")
+        }
+        match self {
+            ShortLong::Short(s) => short_eq(*s, other),
+            ShortLong::Long(l) => long_eq(l, other),
+            ShortLong::Both(s, l) => short_eq(*s, other) || long_eq(l, other),
+        }
+    }
+}
+
+impl ShortLong {
+    /// Changes [`ShortLong`](ShortLong::ShortLong) variant into either short or long depending,
+    /// leaves both Short and Long untouched
+    pub(crate) fn normalize(&mut self, short: bool) {
+        match self {
+            ShortLong::Short(_) | ShortLong::Long(_) => {}
+            ShortLong::Both(s, l) => {
+                if short {
+                    *self = Self::Short(*s);
+                } else {
+                    *self = Self::Long(l);
+                }
+            }
+        }
+    }
+}
+
+impl TryFrom<&NamedArg> for ShortLong {
+    type Error = ();
+
+    fn try_from(named: &NamedArg) -> Result<Self, Self::Error> {
+        match (named.short.is_empty(), named.long.is_empty()) {
+            (true, true) => Err(()),
+            (true, false) => Ok(Self::Long(named.long[0])),
+            (false, true) => Ok(Self::Short(named.short[0])),
+            (false, false) => Ok(Self::Both(named.short[0], named.long[0])),
+        }
+    }
+}
+
+impl Item {
+    #[must_use]
+    pub(crate) fn required(self, required: bool) -> Meta {
+        let boxed = Meta::from(self);
+        if required {
+            boxed
+        } else {
+            Meta::Optional(Box::new(boxed))
+        }
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/lib.rs.html b/src/bpaf/lib.rs.html new file mode 100644 index 00000000..5f71a2f7 --- /dev/null +++ b/src/bpaf/lib.rs.html @@ -0,0 +1,3051 @@ +lib.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+
#![warn(missing_docs)]
+#![allow(clippy::needless_doctest_main)]
+#![allow(clippy::redundant_else)] // not useful
+#![allow(rustdoc::redundant_explicit_links)] // two random markdown parsers I tried only supports explicit links
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+
+//! Lightweight and flexible command line argument parser with derive and combinatoric style API
+
+//! # Quick links
+//! - [Introduction](_documentation::_0_intro) - features, design goals, restrictions
+//! - [Tutorials](_documentation::_1_tutorials) - practical learning oriented information and
+//!   examples to get you started
+//!   + [Types of arguments](_documentation::_1_tutorials::_0_types_of_arguments) -
+//!     common types of line options and conventions (optional)
+//!   + [Combinatoric API](_documentation::_1_tutorials::_1_combinatoric_api)  -
+//!     Parse arguments without using proc macros
+//!   + [Derive API](_documentation::_1_tutorials::_2_derive_api) -
+//!     Create a parser by defining a structure
+//! - [How-to and guides](_documentation::_2_howto) - assumes familiarity with the basics and
+//!   explains how to concrete tasks
+//! - [Explanations](_documentation::_4_explanation) - theoretical information about abstractions
+//!   used by the library, oriented for understanding
+//! - [FAQ](https://github.com/pacak/bpaf/discussions) - questions from library users
+
+//! # A quick start
+//!
+//! Add `bpaf`, optionally with derive enabled
+//!
+//! ```text
+//! $ cargo add bpaf -F derive,dull_color
+//! ```
+//!
+//! Use either derive or combinatoric API and try running it
+//!
+#![cfg_attr(not(doctest), doc = include_str!("docs2/intro.md"))]
+
+//!
+//! ## Consuming items - making `Parser`
+//!
+//! `bpaf` allows you to describe the parsers using a mix of two APIs: combinatoric and derive.
+//! Both APIs can achieve the same results, you can use one that better suits your needs. You can
+//! find documentation with more examples following those links.
+//!
+//! - For an argument with a name you define [`NamedArg`] using a combination of [`short`],
+//!   [`long`] and [`env`](crate::env()). At the same time you can attach
+//!   [`help`](NamedArg::help).
+//! - [`NamedArg::switch`] - simple switch that returns `true` if it's present on a command
+//!   line and `false` otherwise.
+//! - [`NamedArg::flag`] - a variant of `switch` that lets you return one of two custom
+//!   values, for example `Color::On` and `Color::Off`.
+//! - [`NamedArg::req_flag`] - a variant of `switch` that only only succeeds when it's name
+//!   is present on a command line
+//! - [`NamedArg::argument`] - named argument containing a value, you can further
+//!   customize it with [`adjacent`](crate::parsers::ParseArgument::adjacent)
+//! - [`positional`] - positional argument, you can further customize it with
+//!   [`strict`](ParsePositional::strict)
+//! - [`OptionParser::command`] - subcommand parser.
+//! - [`any`] and its specialized version [`literal`] are escape hatches that can parse anything
+//!   not fitting into usual classification.
+//! - [`pure`] and [`pure_with`] - a way to generate a value that can be composed without parsing
+//!   it from the command line.
+//!
+//! ## Transforming and changing parsers
+//!
+//! By default primitive parsers gives you back a single `bool`, a single `PathBuf` or a single
+//! value produced by [`FromStr`] trait, etc. You can further transform it by chaining methods from
+//! [`Parser`] trait, some of those methods are applied automagically if you are using derive API.
+//!
+//! `bpaf` distinguishes two types of parse failures - "value is absent" and
+//! "value is present but invalid", most parsers listed in this section only handle the first
+//! type of failure by default, but you can use their respective `catch` method to handle the later
+//! one.
+//!
+//! - [`fallback`](Parser::fallback) and [`fallback_with`](Parser::fallback_with) - return a
+//!   different value if parser fails to find what it is looking for. Generated help for former
+//!   can be updated to include default value using
+//!   [`display_fallback`](ParseFallback::display_fallback) and
+//!   [`debug_fallback`](ParseFallback::debug_fallback) .
+//! - [`optional`](Parser::optional) - return `None` if value is missing instead of failing, see
+//!   also [`catch`](ParseOptional::catch) .
+//! - [`many`](Parser::many), [`some`](Parser::some) and [`collect`](Parser::collect) - collect
+//!   multiple values into a collection, usually a vector, see their respective
+//!   [`catch`](ParseMany::catch), [`catch`](ParseSome::catch) and [`catch`](ParseCollect::catch).
+//! - [`map`](Parser::map), [`parse`](Parser::parse) and [`guard`](Parser::guard) - transform
+//!   and/or validate value produced by a parser
+//! - [`to_options`](Parser::to_options) - finalize the parser and prepare to run it
+//!
+//! ## Combining multiple parsers together
+//!
+//! Once you have parsers for all the primitive fields figured out you can start combining them
+//! together to produce a parser for a final result - data type you designed in the step one.
+//! For derive API you apply annotations to data types with `#[derive(Bpaf)`] and `#[bpaf(..)]`,
+//! with combinatoric API you use [`construct!`](crate::construct!) macro.
+//!
+//! All fields in a struct needs to be successfully parsed in order for the parser to succeed
+//! and only one variant from enum will consume its values at a time.
+//!
+//! You can use [`adjacent`](ParseCon::adjacent) annotation to parse multiple flags as an adjacent
+//! group allowing for more unusual scenarios such as multiple value arguments or chained commands.
+//!
+//! ## Improving user experience
+//!
+//! `bpaf` would use doc comments on fields and structures in derive mode and and values passed
+//! in various `help` methods to generate `--help` documentation, you can further improve it
+//! using those methods:
+//!
+//! - [`hide_usage`](Parser::hide_usage) and [`hide`](Parser::hide) - hide the parser from
+//!   generated *Usage* line or whole generated help
+//! - [`group_help`](Parser::group_help) and [`with_group_help`](Parser::with_group_help) -
+//!   add a common description shared by several parsers
+//! - [`custom_usage`](Parser::custom_usage) - customize usage for a primitive or composite parser
+//! - [`usage`](OptionParser::usage) and [`with_usage`](OptionParser::with_usage) lets you to
+//!   customize whole usage line as a whole either by completely overriding it or by building around it.
+//!
+//! By default with completion enabled `bpaf` would complete names for flags, arguments and
+//! commands. You can also generate completion for argument values, possible positionals, etc.
+//! This requires enabling **autocomplete** cargo feature.
+//!
+//! - [`complete`](Parser::complete) and [`complete_shell`](Parser::complete_shell)
+//!
+//! And finally you can generate documentation for command line in markdown, html and manpage
+//! formats using [`render_markdown`](OptionParser::render_markdown),
+//! [`render_html`](OptionParser::render_html) and [`render_manpage`](OptionParser::render_manpage),
+//! for more detailed info see [`doc`] module
+//!
+//! ## Testing your parsers and running them
+//! - You can [`OptionParser::run`] the parser on the arguments passed on the command line
+//! - [`check_invariants`](OptionParser::check_invariants) checks for a few invariants in the
+//!   parser `bpaf` relies on
+//! - [`run_inner`](OptionParser::run_inner) runs the parser with custom [`Args`] you can create
+//!   either explicitly or implicitly using one of the [`From`] implementations, `Args` can be
+//!   customized with [`set_comp`](Args::set_comp) and [`set_name`](Args::set_name).
+//! - [`ParseFailure`] contains the parse outcome, you can consume it either by hands or using one
+//!   of [`exit_code`](ParseFailure::exit_code), [`unwrap_stdout`](ParseFailure::unwrap_stdout) and
+//!   [`unwrap_stderr`](ParseFailure::unwrap_stderr)
+//!
+//! ## Cargo features
+//!
+//!  - `derive`: adds a dependency on `bpaf_derive` crate and reexport `Bpaf` derive macro. You
+//!     need to enable it to use derive API. Disabled by default.
+//!
+//!  - `batteries`: helpers implemented with public `bpaf` API. Disabled by default.
+//!
+//!  - `autocomplete`: enables support for shell autocompletion. Disabled by default.
+//!
+//!
+//! - `bright-color`, `dull-color`: use more colors when printing `--help` and such. Enabling
+//!   either color feature adds some extra dependencies and might raise MRSV. If you are planning
+//!   to use this feature in a published app - it’s best to expose them as feature flags:
+//!
+//!    ```toml
+//!    [features]
+//!    bright-color = ["bpaf/bright-color"]
+//!    dull-color = ["bpaf/dull-color"]
+//!    ```
+//!    Disabled by default.
+//!
+//!  - `docgen`: generate documentation from help declaration, see [`OptionParser::render_markdown`] and [`doc`](crate::doc). Disabled by default.
+
+
+
+#[cfg(feature = "extradocs")]
+#[rustfmt::skip]
+#[allow(unused_imports)]
+pub mod _documentation;
+
+mod arg;
+mod args;
+#[cfg(feature = "batteries")]
+pub mod batteries;
+mod buffer;
+#[cfg(feature = "autocomplete")]
+mod complete_gen;
+#[cfg(feature = "autocomplete")]
+mod complete_run;
+#[cfg(feature = "autocomplete")]
+mod complete_shell;
+pub mod doc;
+mod error;
+mod from_os_str;
+mod info;
+mod item;
+mod meta;
+mod meta_help;
+mod meta_youmean;
+pub mod params;
+mod structs;
+#[cfg(test)]
+mod tests;
+
+pub mod parsers {
+    //! This module exposes parsers that accept further configuration with builder pattern
+    //!
+    //! In most cases you won't be using those names directly, they're only listed here to provide
+    //! access to documentation
+    #[cfg(feature = "autocomplete")]
+    #[doc(inline)]
+    pub use crate::complete_shell::ParseCompShell;
+    #[doc(inline)]
+    pub use crate::params::{
+        NamedArg, ParseAny, ParseArgument, ParseCommand, ParseFlag, ParsePositional,
+    };
+    #[doc(inline)]
+    pub use crate::structs::{
+        ParseCollect, ParseCon, ParseCount, ParseFallback, ParseFallbackWith, ParseLast, ParseMany,
+        ParseOptional, ParseSome,
+    };
+}
+
+// -------------------------------------------------------------------
+
+#[doc(inline)]
+pub use crate::{args::Args, buffer::Doc, error::ParseFailure, info::OptionParser};
+
+#[doc(hidden)]
+// used by construct macro, not part of public API
+pub use crate::{args::State, error::Error, meta::Meta, structs::ParseCon};
+
+use std::{marker::PhantomData, str::FromStr};
+
+use crate::{
+    buffer::{MetaInfo, Style},
+    item::Item,
+    params::build_positional,
+    parsers::{NamedArg, ParseAny, ParseCommand, ParsePositional},
+    structs::{
+        ParseCollect, ParseCount, ParseFail, ParseFallback, ParseFallbackWith, ParseGroupHelp,
+        ParseGuard, ParseHide, ParseLast, ParseMany, ParseMap, ParseOptional, ParseOrElse,
+        ParsePure, ParsePureWith, ParseSome, ParseUsage, ParseWith, ParseWithGroupHelp,
+    },
+};
+
+#[cfg(feature = "autocomplete")]
+pub use crate::complete_shell::ShellComp;
+#[cfg(feature = "autocomplete")]
+use structs::ParseComp;
+
+#[doc(inline)]
+#[cfg(feature = "bpaf_derive")]
+pub use bpaf_derive::Bpaf;
+
+/// Compose several parsers to produce a single result
+///
+/// # Usage reference
+/// ```rust
+/// # use bpaf::*;
+/// # { struct Res(bool, bool, bool);
+/// # let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
+/// // structs with unnamed fields:
+/// construct!(Res(a, b, c));
+/// # }
+///
+/// # { struct Res { a: bool, b: bool, c: bool }
+/// # let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
+/// // structs with named fields:
+/// construct!(Res {a, b, c});
+/// # }
+///
+/// # { enum Ty { Res(bool, bool, bool) }
+/// # let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
+/// // enums with unnamed fields:
+/// construct!(Ty::Res(a, b, c));
+/// # }
+///
+/// # { enum Ty { Res { a: bool, b: bool, c: bool } }
+/// # let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
+/// // enums with named fields:
+/// construct!(Ty::Res {a, b, c});
+/// # }
+///
+/// # { let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
+/// // tuples:
+/// construct!(a, b, c);
+/// # }
+///
+/// # { let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
+/// // parallel composition, tries all parsers, picks one that consumes the left most value,
+/// // or if they consume the same (or not at all) - the left most in a list
+/// construct!([a, b, c]);
+/// # }
+///
+/// // defining primitive parsers inside construct macro :)
+/// construct!(a(short('a').switch()), b(long("arg").argument::<usize>("ARG")));
+///
+/// # { let a = short('a').switch();
+/// // defining a boxed parser
+/// construct!(a);
+/// # }
+/// ```
+///
+/// # Combinatoric usage
+/// `construct!` can compose parsers sequentially or in parallel.
+///
+/// Sequential composition runs each parser and if all of them succeed you get a parser object of a
+/// new type back. Placeholder names for values inside `construct!` macro must correspond to both
+/// struct/enum names and parser names present in scope. In examples below `a` corresponds to a
+/// function and `b` corresponds to a variable name. Note parens in `a()`, you must to use them to
+/// indicate function parsers.
+///
+/// Inside the parens you can put a whole expression to use instead of
+/// having to define them in advance: `a(positional::<String>("POS"))`. Probably a good idea to use this
+/// approach only for simple parsers.
+///
+/// ```rust
+/// # use bpaf::*;
+/// struct Res (u32, u32);
+/// enum Ul { T { a: u32, b: u32 } }
+///
+/// // You can share parameters across multiple construct invocations
+/// // if defined as functions
+/// fn a() -> impl Parser<u32> {
+///     short('a').argument::<u32>("N")
+/// }
+///
+/// // You can construct structs or enums with unnamed fields
+/// fn res() -> impl Parser<Res> {
+///     let b = short('b').argument::<u32>("n");
+///     construct!(Res ( a(), b ))
+/// }
+///
+/// // You can construct structs or enums with named fields
+/// fn ult() -> impl Parser<Ul> {
+///     let b = short('b').argument::<u32>("n");
+///     construct!(Ul::T { a(), b })
+/// }
+///
+/// // You can also construct simple tuples
+/// fn tuple() -> impl Parser<(u32, u32)> {
+///     let b = short('b').argument::<u32>("n");
+///     construct!(a(), b)
+/// }
+///
+/// // You can create boxed version of parsers so the type matches as long
+/// // as return type is the same - can be useful for all sort of dynamic parsers
+/// fn boxed() -> Box<dyn Parser<u32>> {
+///     let a = short('a').argument::<u32>("n");
+///     construct!(a)
+/// }
+///
+/// // In addition to having primitives defined before using them - you can also define
+/// // them directly inside construct macro. Probably only a good idea if you have only simple
+/// // components
+/// struct Options {
+///     arg: u32,
+///     switch: bool,
+/// }
+///
+/// fn coyoda() -> impl Parser<Options> {
+///     construct!(Options {
+///         arg(short('a').argument::<u32>("ARG")),
+///         switch(short('s').switch())
+///     })
+/// }
+/// ```
+///
+/// Parallel composition picks one of several available parsers (result types must match) and returns a
+/// parser object of the same type. Similar to sequential composition you can use parsers from variables
+/// or functions:
+///
+/// ```rust
+/// # use bpaf::*;
+/// fn b() -> impl Parser<u32> {
+///     short('b').argument::<u32>("NUM")
+/// }
+///
+/// fn a_or_b() -> impl Parser<u32> {
+///     let a = short('a').argument::<u32>("NUM");
+///     // equivalent way of writing this would be `a.or_else(b())`
+///     construct!([a, b()])
+/// }
+/// ```
+///
+/// # Derive usage
+///
+/// `bpaf` would combine fields of struct or enum constructors sequentially and enum
+/// variants in parallel.
+/// ```rust
+/// # use bpaf::*;
+/// // to satisfy this parser user needs to pass both -a and -b
+/// #[derive(Debug, Clone, Bpaf)]
+/// struct Res {
+///     a: u32,
+///     b: u32,
+/// }
+///
+/// // to satisfy this parser user needs to pass one (and only one) of -a, -b, -c or -d
+/// #[derive(Debug, Clone, Bpaf)]
+/// enum Enumeraton {
+///     A { a: u32 },
+///     B { b: u32 },
+///     C { c: u32 },
+///     D { d: u32 },
+/// }
+///
+/// // here user needs to pass either both -a AND -b or both -c AND -d
+/// #[derive(Debug, Clone, Bpaf)]
+/// enum Ult {
+///     AB { a: u32, b: u32 },
+///     CD { c: u32, d: u32 }
+/// }
+/// ```
+
+#[macro_export]
+macro_rules! construct {
+    // construct!(Enum::Cons { a, b, c })
+    ($(::)? $ns:ident $(:: $con:ident)* { $($tokens:tt)* }) => {{ $crate::construct!(@prepare [named [$ns $(:: $con)*]] [] $($tokens)*) }};
+
+    // construct!(Enum::Cons ( a, b, c ))
+    ($(::)? $ns:ident $(:: $con:ident)* ( $($tokens:tt)* )) => {{ $crate::construct!(@prepare [pos [$ns $(:: $con)*]] [] $($tokens)*) }};
+
+    // construct!( a, b, c )
+    ($first:ident $($tokens:tt)*) => {{ $crate::construct!(@prepare [pos] [] $first $($tokens)*) }};
+
+    // construct![a, b, c]
+    ([$first:ident $($tokens:tt)*]) => {{ $crate::construct!(@prepare [alt] [] $first $($tokens)*) }};
+
+    (@prepare $ty:tt [$($fields:tt)*] $field:ident () $(, $($rest:tt)*)? ) => {{
+        let $field = $field();
+        $crate::construct!(@prepare $ty [$($fields)* $field] $($($rest)*)?)
+    }};
+    (@prepare $ty:tt [$($fields:tt)*] $field:ident ($expr:expr) $(, $($rest:tt)*)?) => {{
+        let $field = $expr;
+        $crate::construct!(@prepare $ty [$($fields)* $field] $($($rest)*)?)
+    }};
+    (@prepare $ty:tt [$($fields:tt)*] $field:ident $(, $($rest:tt)*)? ) => {{
+        $crate::construct!(@prepare $ty [$($fields)* $field] $($($rest)* )?)
+    }};
+
+    (@prepare [alt] [$first:ident $($fields:ident)*]) => {
+        #[allow(deprecated)]
+        { use $crate::Parser; $first $(.or_else($fields))* }
+    };
+
+    (@prepare $ty:tt [$($fields:tt)*]) => {
+        $crate::construct!(@fin $ty [ $($fields)* ])
+    };
+
+    (@make [named [$($con:tt)+]] [$($fields:ident)*]) => { $($con)+ { $($fields),* } };
+    (@make [pos   [$($con:tt)+]] [$($fields:ident)*]) => { $($con)+ ( $($fields),* ) };
+    (@make [pos] [$($fields:ident)*]) => { ( $($fields),* ) };
+
+
+    (@fin [named [$($con:tt)+]] []) => { $crate::pure($($con)+ { })};
+    (@fin [pos   [$($con:tt)+]] []) => { $crate::pure($($con)+ ( ))};
+
+    (@fin [pos] [$field:ident]) => {{
+        use $crate::Parser;
+        $field.boxed()
+    }};
+
+    (@fin $ty:tt [$front:ident $($fields:ident)*]) => {{
+        use $crate::Parser;
+        let meta = $crate::Meta::And(vec![ $front.meta(), $($fields.meta()),* ]);
+        let inner = move |failfast: bool, args: &mut $crate::State| {
+            let mut $front = $front.eval(args);
+            if failfast {
+                $front = Ok($front?);
+            }
+            $(let $fields = $fields.eval(args);)*
+            let $front = $front?;
+            $(let $fields = $fields?;)*
+
+            args.current = None;
+            ::std::result::Result::Ok::<_, $crate::Error>
+                ($crate::construct!(@make $ty [$front $($fields)*]))
+        };
+        $crate::ParseCon { inner, meta, failfast: false }
+    }};
+}
+
+/// Simple or composed argument parser
+///
+/// # Overview
+///
+/// It's best to think of an object implementing [`Parser`] trait as a container with a value
+/// inside that is composable with other `Parser` containers using [`construct!`] and the only
+/// way to extract this value is by transforming it to [`OptionParser`] with
+/// [`to_options`](Parser::to_options) and running it with [`run`](OptionParser::run). At which
+/// point you either get your value out or `bpaf` would generate a message describing a problem
+/// (missing argument, validation failure, user requested help, etc) and the program would
+/// exit.
+///
+/// Values inside can be of any type for as long as they implement `Debug`, `Clone` and
+/// there are no lifetimes other than static.
+///
+/// When consuming the values you can jump straight to a value that implements
+/// [`FromStr`] trait and then transform it into something that your program would use. Alternatively,
+/// you can consume either `String` or `OsString` and parse that by hand. It's better to perform
+/// as much parsing and validation inside the `Parser` as possible so the program itself gets
+/// strictly typed and correct value while the user gets immediate feedback on what's wrong with the
+/// arguments they pass.
+///
+/// Order of operations matters, each subsequent parser gets the output of the earlier one. Both
+/// parsers `a` and `b` would consume multiple numeric values, each less than 10, but `a`
+/// validates a single value and then consumes multiple of them already validated, while `b` first
+/// consumes and then performs validation. The former approach is usually more readable.
+/// ```rust
+/// # use bpaf::*;
+/// # fn simple() {
+/// let a = short('a').argument::<usize>("N")
+///     .guard(|&a| a < 10, "`a` must be below 10")
+///     .many();
+/// let b = short('b').argument::<usize>("N")
+///     .many()
+///     .guard(|bs| bs.iter().all(|&b| b < 10), "`b` must be below 10");
+/// # }
+/// ```
+///
+/// The same logic applies to derive API - the current type depends on the order of annotations:
+/// ```rust
+/// # use bpaf::*;
+/// # fn less_than_10(a: &usize) -> bool { true }
+/// # fn all_less_than_10(a: &Vec<usize>) -> bool { true }
+/// #[derive(Bpaf, Debug, Clone)]
+/// struct Simple {
+///     #[bpaf(argument("N"), guard(less_than_10, "`a` must be below 10"), many)]
+///     a: Vec<usize>,
+///     #[bpaf(argument("N"), many, guard(all_less_than_10, "`b` must be below 10"))]
+///     b: Vec<usize>,
+/// }
+/// ```
+///
+/// For example suppose your program needs the user to specify dimensions of a rectangle, with sides
+/// being 1..20 units long and the total area must not exceed 200 units square. A parser that
+/// consumes it might look like this:
+///
+/// ```rust
+/// # use bpaf::*;
+/// #[derive(Debug, Copy, Clone)]
+/// struct Rectangle {
+///     width: u32,
+///     height: u32,
+/// }
+///
+/// fn rectangle() -> impl Parser<Rectangle> {
+///     let invalid_size = "Sides of a rectangle must be 1..20 units long";
+///     let invalid_area = "Area of a rectangle must not exceed 200 units square";
+///     let width = long("width")
+///         .help("Width of the rectangle")
+///         .argument::<u32>("PX")
+///         .guard(|&x| 1 <= x && x <= 10, invalid_size);
+///     let height = long("height")
+///         .help("Height of the rectangle")
+///         .argument::<u32>("PX")
+///         .guard(|&x| 1 <= x && x <= 10, invalid_size);
+///     construct!(Rectangle { width, height })
+///         .guard(|&r| r.width * r.height <= 400, invalid_area)
+/// }
+/// ```
+///
+///
+/// # Derive specific considerations
+///
+/// Every method defined on this trait belongs to the `postprocessing` section of the field
+/// annotation. `bpaf` would try to figure out what chain to use for as long as there are no
+/// options changing the type: you can use [`fallback`](Parser::fallback_with),
+/// [`fallback_with`](Parser::fallback_with), [`guard`](Parser::guard), [`hide`](Parser::hide`) and
+/// [`group_help`](Parser::group_help) but not the rest of them.
+///
+/// ```rust
+/// # use bpaf::*;
+/// #[derive(Debug, Clone, Bpaf)]
+/// struct Options {
+///     // no annotation at all - `bpaf` inserts implicit `argument` and gets the right type
+///     number_1: u32,
+///
+///     // fallback isn't changing the type so `bpaf` still handles it
+///     #[bpaf(fallback(42))]
+///     number_2: u32,
+///
+///     // `bpaf` inserts implicit `argument`, `optional` and the right type
+///     number_3: Option<u32>,
+///
+///     // fails to compile: you need to specify `argument`
+///     // #[bpaf(optional)]
+///     // number_4: Option<u32>,
+///
+///     #[bpaf(argument("N"), optional)]
+///     number_5: Option<u32>,
+///
+///     // explicit consumer and a full postprocessing chain
+///     #[bpaf(argument::<u32>("N"), optional)]
+///     number_6: Option<u32>,
+/// }
+/// ```
+pub trait Parser<T> {
+    /// Evaluate inner function
+    ///
+    /// Mostly internal implementation details, you can try using it to test your parsers
+    // it's possible to move this function from the trait to the structs but having it
+    // in the trait ensures the composition always works
+    #[doc(hidden)]
+    fn eval(&self, args: &mut State) -> Result<T, Error>;
+
+    /// Included information about the parser
+    ///
+    /// Mostly internal implementation details, you can try using it to test your parsers
+    // it's possible to move this function from the trait to the structs but having it
+    // in the trait ensures the composition always works
+    #[doc(hidden)]
+    fn meta(&self) -> Meta;
+
+    // change shape
+    // {{{ many
+    /// Consume zero or more items from a command line and collect them into a [`Vec`]
+    ///
+    /// `many` preserves any parsing failures and propagates them outwards, with an extra
+    /// [`catch`](ParseMany::catch) statement you can instead stop at the first value
+    /// that failed to parse and ignore it and all the subsequent ones.
+    ///
+    /// `many` will collect at most one result that does not consume anything from the argument
+    /// list allowing using it in combination with any parsers with a fallback. After the first
+    /// one, it will keep collecting the results as long as they consume something.
+    ///
+    /// For derive usage `bpaf` would insert implicit `many` when the resulting type is a
+    /// vector.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/many.md"))]
+    ///
+    /// # See also
+    /// [`some`](Parser::some) also collects results to a vector but requires at least one
+    /// element to succeed, [`collect`](Parser::collect) collects results into a [`FromIterator`]
+    /// structure
+    fn many(self) -> ParseMany<Self>
+    where
+        Self: Sized,
+    {
+        ParseMany {
+            inner: self,
+            catch: false,
+        }
+    }
+    // }}}
+
+    // {{{ collect
+    /// Transform parser into a collection parser
+    ///
+    /// A generic variant of [`many`](Parser::many), instead of collecting into a vector
+    /// it collects into any collection that implements [`FromIterator`] trait
+    ///
+    /// `collect` preserves any parsing failures and propagates them outwards, with extra
+    /// [`catch`](ParseCollect::catch) statement you can instead stop at the first value
+    /// that failed to parse and ignore it and all the subsequent ones.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/collect.md"))]
+    ///
+    /// `collect` will collect at most one result that does not consume anything from the argument
+    /// list allowing using it in combination of any parsers with a fallback. After the first one
+    /// it will keep collecting the results as long as they consume something.
+    fn collect<C>(self) -> ParseCollect<Self, C, T>
+    where
+        C: FromIterator<T>,
+        Self: Sized,
+    {
+        ParseCollect {
+            inner: self,
+            catch: false,
+            ctx: PhantomData,
+        }
+    }
+    // }}}
+
+    // {{{ some
+    /// Consume one or more items from a command line and collect them into a [`Vec`]
+    ///
+    /// Takes a string used as an error message if there are no specified parameters
+    ///
+    /// `some` preserves any parsing failures and propagates them outwards, with an extra
+    /// [`catch`](ParseSome::catch) statement you can instead stop at the first value
+    /// that failed to parse and ignore it and all the subsequent ones.
+    ///
+    /// `some` will collect at most one result that does not consume anything from the argument
+    /// list allowing using it in combination with any parsers with a fallback. After the first
+    /// one, it will keep collecting the results as long as they consume something.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/some.md"))]
+    ///
+    /// # See also
+    /// [`many`](Parser::many) also collects results to a vector but succeeds with
+    /// no matching values. [`collect`](Parser::collect) collects results into a [`FromIterator`]
+    /// structure
+
+    #[must_use]
+    fn some(self, message: &'static str) -> ParseSome<Self>
+    where
+        Self: Sized + Parser<T>,
+    {
+        ParseSome {
+            inner: self,
+            message,
+            catch: false,
+        }
+    }
+    // }}}
+
+    // {{{ optional
+    /// Turn a required argument into an optional one
+    ///
+    /// `optional` converts any missing items into `None` and passes the remaining parsing
+    /// failures untouched. With an extra [`catch`](ParseOptional::catch) statement, you can handle
+    /// those failures too.
+    ///
+    /// # Derive usage
+    ///
+    /// By default, `bpaf` would automatically use optional for fields of type `Option<T>`,
+    /// for as long as it's not prevented from doing so by present postprocessing options.
+    /// But it's also possible to specify it explicitly.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/optional.md"))]
+    ///
+    #[must_use]
+    fn optional(self) -> ParseOptional<Self>
+    where
+        Self: Sized + Parser<T>,
+    {
+        ParseOptional {
+            inner: self,
+            catch: false,
+        }
+    }
+    // }}}
+
+    #[must_use]
+    /// Count how many times the inner parser succeeds, and return that number.
+    ///
+    /// When you are dealing with a parser that can succeed without consuming
+    /// anything from a command line - `bpaf` will count first such success as well.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/count.md"))]
+    fn count(self) -> ParseCount<Self, T>
+    where
+        Self: Sized + Parser<T>,
+    {
+        ParseCount {
+            inner: self,
+            ctx: PhantomData,
+        }
+    }
+
+    #[must_use]
+    /// Apply the inner parser as many times as it succeeds, return the last value
+    ///
+    /// You can use this to allow users to pick contradicting options
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/last.md"))]
+    fn last(self) -> ParseLast<Self>
+    where
+        Self: Sized + Parser<T>,
+    {
+        ParseLast { inner: self }
+    }
+
+    // parse
+    // {{{ parse
+    /// Apply a failing transformation to a contained value
+    ///
+    /// Transformation preserves the present/absent state of the value: to parse an optional value you
+    /// can either first try to `parse` it and then mark it as [`optional`](Parser::optional) or first
+    /// deal with the optionality and then parse a value wrapped in [`Option`]. In most cases
+    /// the former approach is more concise.
+    ///
+    /// Similarly, it is possible to parse multiple items with [`many`](Parser::many) or
+    /// [`some`](Parser::some) by either parsing a single item first and then turning it into a [`Vec`]
+    /// or collecting them into a [`Vec`] first and then parsing the whole vector. The former approach
+    /// is more concise.
+    ///
+    /// This is a most general of transforming parsers and you can express
+    /// [`map`](Parser::map) and [`guard`](Parser::guard) in terms of it.
+    ///
+    /// Examples are a bit artificial, to parse a value from a string you can specify
+    /// the type directly in the `argument`'s turbofish and then apply `map`.
+    ///
+    /// # Derive usage:
+    /// `parse` takes a single parameter: function name to call. Function type should match
+    /// parameter `F` used by `parse` in combinatoric API.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/parse.md"))]
+    ///
+    fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
+    where
+        Self: Sized + Parser<T>,
+        F: Fn(T) -> Result<R, E>,
+        E: ToString,
+    {
+        ParseWith {
+            inner: self,
+            inner_res: PhantomData,
+            parse_fn: f,
+            res: PhantomData,
+            err: PhantomData,
+        }
+    }
+    // }}}
+
+    // {{{ map
+    /// Apply a pure transformation to a contained value
+    ///
+    /// A common case of the [`parse`](Parser::parse) method, exists mostly for convenience.
+    ///
+    /// # Derive usage:
+    /// The `map` takes a single parameter: function name to call. This function should transform
+    /// the value produced by the parser into a new value of the same or different type.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/map.md"))]
+    ///
+    fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
+    where
+        Self: Sized + Parser<T>,
+        F: Fn(T) -> R + 'static,
+    {
+        ParseMap {
+            inner: self,
+            inner_res: PhantomData,
+            map_fn: map,
+            res: PhantomData,
+        }
+    }
+    // }}}
+
+    // {{{ guard
+    /// Validate or fail with a message
+    ///
+    /// If the value doesn't satisfy the constraint - the parser fails with the specified error message.
+    ///
+    /// # Derive usage
+    /// Derive variant of the `guard` takes a function name instead of a closure, mostly to keep things
+    /// clean. The second argument can be either a string literal or a constant name for a static [`str`].
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/guard.md"))]
+    ///
+    #[must_use]
+    fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
+    where
+        Self: Sized + Parser<T>,
+        F: Fn(&T) -> bool,
+    {
+        ParseGuard {
+            inner: self,
+            check,
+            message,
+        }
+    }
+    // }}}
+
+    // combine
+    // {{{ fallback
+    /// Use this value as default if the value isn't present on a command line
+    ///
+    /// Parser would still fail if the value is present but failure comes from some transformation
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/dis_fallback.md"))]
+    ///
+    /// # See also
+    /// [`fallback_with`](Parser::fallback_with) would allow to try to fallback to a value that
+    /// comes from a failing computation such as reading a file. By default fallback value will
+    /// not be shown in the `--help` output, you can change that by using
+    /// [`display_fallback`](ParseFallback::display_fallback) and
+    /// [`debug_fallback`](ParseFallback::debug_fallback).
+    #[must_use]
+    fn fallback(self, value: T) -> ParseFallback<Self, T>
+    where
+        Self: Sized + Parser<T>,
+    {
+        ParseFallback {
+            inner: self,
+            value,
+            value_str: String::new(),
+        }
+    }
+    // }}}
+
+    // {{{ fallback_with
+    /// Use value produced by this function as default if the value isn't present
+    ///
+    /// Would still fail if the value is present but failure comes from some earlier transformation
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/dis_fallback_with.md"))]
+    ///
+    /// # See also
+    /// [`fallback`](Parser::fallback) implements similar logic expect that failures aren't expected.
+    /// By default fallback value will not be shown in the `--help` output, you can change that by using
+    /// [`display_fallback`](ParseFallbackWith::display_fallback) and
+    /// [`debug_fallback`](ParseFallbackWith::debug_fallback).
+    #[must_use]
+    fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
+    where
+        Self: Sized + Parser<T>,
+        F: Fn() -> Result<T, E>,
+        E: ToString,
+    {
+        ParseFallbackWith {
+            inner: self,
+            inner_res: PhantomData,
+            fallback,
+            value_str: String::new(),
+            err: PhantomData,
+        }
+    }
+    // }}}
+
+    // {{{ or_else
+    /// If first parser fails - try the second one
+    ///
+    /// For parser to succeed eiter of the components needs to succeed. If both succeed - `bpaf`
+    /// would use output from one that consumed the left most value. The second flag on the command
+    /// line remains unconsumed by `or_else`.
+    ///
+    /// # Combinatoric usage:
+    /// There's two ways to write this combinator with identical results:
+    /// ```rust
+    /// # use bpaf::*;
+    /// fn a() -> impl Parser<u32> {
+    ///     short('a').argument::<u32>("NUM")
+    /// }
+    ///
+    /// fn b() -> impl Parser<u32> {
+    ///     short('b').argument::<u32>("NUM")
+    /// }
+    ///
+    /// fn a_or_b_comb() -> impl Parser<u32> {
+    ///     construct!([a(), b()])
+    /// }
+    ///
+    /// fn a_or_b_comb2() -> impl Parser<u32> {
+    ///     a().or_else(b())
+    /// }
+    /// ```
+    ///
+    /// # Example
+    /// ```console
+    /// $ app -a 12 -b 3
+    /// // 12
+    /// $ app -b 3 -a 12
+    /// // 3
+    /// $ app -b 13
+    /// // 13
+    /// $ app
+    /// // fails asking for either -a NUM or -b NUM
+    /// ```
+    ///
+    /// # Derive usage:
+    ///
+    /// `bpaf` translates enum into alternative combinations, different shapes of variants
+    /// produce different results.
+    ///
+    ///
+    /// ```bpaf
+    /// # use bpaf::*;
+    /// #[derive(Debug, Clone, Bpaf)]
+    /// enum Flag {
+    ///     A { a: u32 }
+    ///     B { b: u32 }
+    /// }
+    /// ```
+    ///
+    /// ```console
+    /// $ app -a 12 -b 3
+    /// // Flag::A { a: 12 }
+    /// $ app -b 3 -a 12
+    /// // Flag::B { b: 3 }
+    /// $ app -b 3
+    /// // Flag::B { b: 3 }
+    /// $ app
+    /// // fails asking for either -a NUM or -b NUM
+    /// ```
+    ///
+    /// # Performance
+    ///
+    /// `bpaf` tries to evaluate both branches regardless of the successes to produce a
+    /// better error message for combinations of mutually exclusive parsers:
+    /// Suppose program accepts one of two mutually exclusive switches `-a` and `-b`
+    /// and both are present error message should point at the second flag
+    #[doc(hidden)]
+    #[deprecated(
+        since = "0.5.0",
+        note = "instead of a.or_else(b) you should use construct!([a, b])"
+    )]
+    fn or_else<P>(self, alt: P) -> ParseOrElse<T>
+    where
+        Self: Sized + Parser<T> + 'static,
+        P: Sized + Parser<T> + 'static,
+    {
+        ParseOrElse {
+            this: Box::new(self),
+            that: Box::new(alt),
+        }
+    }
+    // }}}
+
+    // misc
+    // {{{ hide
+    /// Ignore this parser during any sort of help generation
+    ///
+    /// Best used for optional parsers or parsers with a defined fallback, usually for implementing
+    /// backward compatibility or hidden aliases
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/hide.md"))]
+    ///
+    fn hide(self) -> ParseHide<Self>
+    where
+        Self: Sized + Parser<T>,
+    {
+        ParseHide { inner: self }
+    }
+    // }}}
+
+    /// Ignore this parser when generating a usage line
+    ///
+    /// Parsers hidden from usage will still show up in the available arguments list. Best used on
+    /// optional things that augment the main application functionality but not define it.
+    /// Alternatively, you can use [`custom_usage`](Parser::custom_usage) to replace a single
+    /// option or a group of them with some other text.
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/hide_usage.md"))]
+    #[must_use]
+    fn hide_usage(self) -> ParseUsage<Self>
+    where
+        Self: Sized + Parser<T>,
+    {
+        ParseUsage {
+            inner: self,
+            usage: Doc::default(),
+        }
+    }
+
+    /// Customize how this parser looks like in the usage line
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/custom_usage.md"))]
+    #[must_use]
+    fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
+    where
+        M: Into<Doc>,
+        Self: Sized + Parser<T>,
+    {
+        ParseUsage {
+            inner: self,
+            usage: usage.into(),
+        }
+    }
+
+    // {{{ group_help
+    /// Attach a help message to a complex parser
+    ///
+    /// `bpaf` inserts the group help message before the block with all the fields
+    /// from the inner parser and an empty line after the block.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/group_help.md"))]
+    fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
+    where
+        Self: Sized + Parser<T>,
+    {
+        ParseGroupHelp {
+            inner: self,
+            message: message.into(),
+        }
+    }
+    // }}}
+
+    /// Make a help message for a complex parser from its [`MetaInfo`]
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/with_group_help.md"))]
+    fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
+    where
+        Self: Sized + Parser<T>,
+        F: Fn(MetaInfo) -> Doc,
+    {
+        ParseWithGroupHelp { inner: self, f }
+    }
+
+    // {{{ comp
+    /// Dynamic shell completion
+    ///
+    /// Allows to generate autocompletion information for the shell. Completer places generated input
+    /// in place of metavar placeholders, so running `completer` on something that doesn't have a
+    /// [`positional`] or an [`argument`](NamedArg::argument) doesn't make much sense.
+    ///
+    /// Takes a function as a parameter that tries to complete partial input to a full one with an
+    /// optional description. `bpaf` would substitute a current positional item or an argument with an empty
+    /// string if a value isn't available yet so it's best to run `complete` where parsing can't fail:
+    /// right after [`argument`](NamedArg::argument) or [`positional`], but this isn't enforced.
+    ///
+    /// # Example
+    /// ```console
+    /// $ app --name L<TAB>
+    /// $ app --name Lupusregina _
+    /// ```
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/complete.md"))]
+    ///
+    /// ## A simple example
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/simple_dynamic.md"))]
+    ///
+    /// ## More detailed example
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/derive_show_asm.md"))]
+    ///
+    #[cfg(feature = "autocomplete")]
+    fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
+    where
+        M: Into<String>,
+        F: Fn(&T) -> Vec<(M, Option<M>)>,
+        Self: Sized + Parser<T>,
+    {
+        ParseComp {
+            inner: self,
+            op,
+            group: None,
+        }
+    }
+    // }}}
+
+    // {{{
+    /// Static shell completion
+    ///
+    /// Allows to ask existing shell completion to provide some information such as a file or
+    /// directory names or pass through existing shell completion scripts, see
+    /// [`ShellComp`](complete_shell::ShellComp) for accessible functionality
+    ///
+    /// Places function calls in place of metavar placeholder, so running `complete_shell` on
+    /// something that doesn't have a [`positional`] or [`argument`](NamedArg::argument) doesn't
+    /// make much sense.
+    ///
+    /// # Example
+    /// ```console
+    /// $ app --output C<TAB>
+    /// $ app --output Cargo.toml _
+    /// ```
+    ///
+    /// # Combinatoric usage
+    /// ```rust
+    /// # use bpaf::*;
+    /// fn output() -> impl Parser<String> {
+    ///     long("output")
+    ///         .help("Cargo.toml file to use as output")
+    ///         .argument("OUTPUT")
+    ///         .complete_shell(ShellComp::File { mask: Some("*.toml") })
+    /// }
+    /// ```
+    ///
+    /// # Derive usage
+    /// ```rust
+    /// # use bpaf::*;
+    /// #[derive(Debug, Clone, Bpaf)]
+    /// struct Options {
+    ///     /// Cargo.toml file to use as output
+    ///     #[bpaf(argument("OUTPUT"), complete_shell(ShellComp::File { mask: Some("*.toml") }))]
+    ///     output: String,
+    /// }
+    /// ```
+    #[cfg(feature = "autocomplete")]
+    fn complete_shell(
+        self,
+        op: complete_shell::ShellComp,
+    ) -> crate::complete_shell::ParseCompShell<Self>
+    where
+        Self: Sized + Parser<T>,
+    {
+        crate::complete_shell::ParseCompShell { inner: self, op }
+    }
+    // }}}
+
+    // consume
+    // {{{ to_options
+    /// Transform `Parser` into [`OptionParser`] to get ready to [`run`](OptionParser::run) it
+    ///
+    ///
+    /// # Derive usage
+    /// Add a top-level `options` annotation to generate [`OptionParser`] instead of default
+    /// [`Parser`].
+    ///
+    /// In addition to `options` annotation, you can also specify either `version` or
+    /// `version(value)` annotation. The former uses version from `cargo`, later uses the
+    /// specified value which should be an expression of type `&'static str`, see
+    /// [`version`](OptionParser::version).
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/to_options.md"))]
+    ///
+    /// # See also
+    /// There's some methods implemented on [`OptionParser`] directly to customize the appearance
+    fn to_options(self) -> OptionParser<T>
+    where
+        Self: Sized + Parser<T> + 'static,
+    {
+        OptionParser {
+            info: info::Info::default(),
+            inner: Box::new(self),
+        }
+    }
+    // }}}
+
+    /// Finalize and run the parser
+    ///
+    /// Generally, you'd want to use [`Parser::to_options`] to finalize the parser and [`OptionParser::run`],
+    /// but this also works for simple cases:
+    ///
+    /// ```no_run
+    /// # use bpaf::*;
+    /// fn main() {
+    ///     let name = short('n').long("name").argument::<String>("USER").run();
+    ///     // do things with name
+    /// }
+    /// ```
+    fn run(self) -> T
+    where
+        Self: Sized + Parser<T> + 'static,
+    {
+        self.to_options().run()
+    }
+
+    /// Create a boxed representation for a parser
+    ///
+    ///
+
+    /// The boxed parser doesn't expose internal representation in its type and allows to return
+    /// of different parsers in different conditional branches
+    ///
+    /// You can create it with a single argument `construct` macro or by using `boxed` annotation
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/boxed.md"))]
+    fn boxed(self) -> Box<dyn Parser<T>>
+    where
+        Self: Sized + Parser<T> + 'static,
+    {
+        Box::new(self)
+    }
+}
+
+/// Parser that produces a fixed value
+///
+/// This parser produces `T` without consuming anything from the command line, which can be useful
+/// with [`construct!`]. As with any parsers, `T` should be `Clone` and `Debug`.
+///
+/// Both `pure` and [`pure_with`] are designed to put values into structures, to generate fallback
+/// you should be using [`fallback`](Parser::fallback) and [`fallback_with`](Parser::fallback_with).
+///
+/// See also [`pure_with`] for a pure computation that can fail.
+///
+#[cfg_attr(not(doctest), doc = include_str!("docs2/pure.md"))]
+#[must_use]
+pub fn pure<T>(val: T) -> ParsePure<T> {
+    ParsePure(val)
+}
+
+/// Wrap a calculated value into a `Parser`
+///
+/// This parser represents a possibly failing equivalent to [`pure`].
+/// It produces `T` by invoking the provided callback without consuming anything from the command
+/// line, which can be useful with [`construct!`]. As with any parsers, `T` should be `Clone`
+/// and `Debug`.
+///
+/// Both [`pure`] and `pure_with` are designed to put values into structures, to generate fallback
+/// you should be using [`fallback`](Parser::fallback) and [`fallback_with`](Parser::fallback_with).
+///
+/// See also [`pure`] for a pure computation that can't fail.
+///
+#[cfg_attr(not(doctest), doc = include_str!("docs2/pure_with.md"))]
+pub fn pure_with<T, F, E>(val: F) -> ParsePureWith<T, F, E>
+where
+    F: Fn() -> Result<T, E>,
+    E: ToString,
+{
+    ParsePureWith(val)
+}
+
+/// Fail with a fixed error message
+///
+/// This parser produces `T` of any type but instead of producing it when asked - it fails
+/// with a custom error message. Can be useful for creating custom logic
+///
+/// # Combinatoric usage
+/// ```rust
+/// # use bpaf::*;
+/// fn must_agree() -> impl Parser<()> {
+///     let a = long("accept").req_flag(());
+///     let no_a = fail("You must accept the license agreement with --agree before proceeding");
+///     construct!([a, no_a])
+/// }
+/// ```
+///
+/// # Example
+/// ```console
+/// $ app
+/// // exits with "You must accept the license agreement with --agree before proceeding"
+/// $ app --agree
+/// // succeeds
+/// ```
+#[must_use]
+pub fn fail<T>(msg: &'static str) -> ParseFail<T> {
+    ParseFail {
+        field1: msg,
+        field2: PhantomData,
+    }
+}
+
+/// Parse a [`flag`](NamedArg::flag)/[`switch`](NamedArg::switch)/[`argument`](NamedArg::argument) that has a short name
+///
+/// You can chain multiple [`short`](NamedArg::short), [`long`](NamedArg::long) and
+/// [`env`](NamedArg::env()) for multiple names. You can specify multiple names of the same type,
+///  `bpaf` would use items past the first one as hidden aliases.
+#[cfg_attr(not(doctest), doc = include_str!("docs2/short_long_env.md"))]
+#[must_use]
+pub fn short(short: char) -> NamedArg {
+    NamedArg {
+        short: vec![short],
+        env: Vec::new(),
+        long: Vec::new(),
+        help: None,
+    }
+}
+
+/// Parse a [`flag`](NamedArg::flag)/[`switch`](NamedArg::switch)/[`argument`](NamedArg::argument) that has a long name
+///
+/// You can chain multiple [`short`](NamedArg::short), [`long`](NamedArg::long) and
+/// [`env`](NamedArg::env()) for multiple names. You can specify multiple names of the same type,
+///  `bpaf` would use items past the first one as hidden aliases.
+///
+#[cfg_attr(not(doctest), doc = include_str!("docs2/short_long_env.md"))]
+#[must_use]
+pub fn long(long: &'static str) -> NamedArg {
+    NamedArg {
+        short: Vec::new(),
+        long: vec![long],
+        env: Vec::new(),
+        help: None,
+    }
+}
+
+/// Parse an environment variable
+///
+/// You can chain multiple [`short`](NamedArg::short), [`long`](NamedArg::long) and
+/// [`env`](NamedArg::env()) for multiple names. You can specify multiple names of the same type,
+///  `bpaf` would use items past the first one as hidden aliases.
+///
+/// For [`flag`](NamedArg::flag) and [`switch`](NamedArg::switch) environment variable being present
+/// gives the same result as the flag being present, allowing to implement things like `NO_COLOR`
+/// variables:
+///
+/// ```console
+/// $ NO_COLOR=1 app --do-something
+/// ```
+///
+/// If you don't specify a short or a long name - whole argument is going to be absent from the
+/// help message. Use it combined with a named or positional argument to have a hidden fallback
+/// that wouldn't leak sensitive info.
+///
+#[cfg_attr(not(doctest), doc = include_str!("docs2/short_long_env.md"))]
+#[must_use]
+pub fn env(variable: &'static str) -> NamedArg {
+    NamedArg {
+        short: Vec::new(),
+        long: Vec::new(),
+        help: None,
+        env: vec![variable],
+    }
+}
+
+/// Parse a positional argument
+///
+/// For named flags and arguments ordering generally doesn't matter: most programs would
+/// understand `-O2 -v` the same way as `-v -O2`, but for positional items order matters: in *nix
+/// `cat hello world` and `cat world hello` would display contents of the same two files but in
+/// a different order.
+///
+/// When using combinatoric API you can specify the type with turbofish, for parsing types
+/// that don't implement [`FromStr`] you can use consume a `String`/`OsString` first and parse
+/// it by hand.
+/// ```no_run
+/// # use bpaf::*;
+/// fn parse_pos() -> impl Parser<usize> {
+///     positional::<usize>("POS")
+/// }
+/// ```
+///
+/// # Important restriction
+/// To parse positional arguments from a command line you should place parsers for all your
+/// named values before parsers for positional items and commands. In derive API fields parsed as
+/// positional items or commands should be at the end of your `struct`/`enum`. The same rule applies
+/// to parsers with positional fields or commands inside: such parsers should go to the end as well.
+///
+/// Use [`check_invariants`](OptionParser::check_invariants) in your test to ensure correctness.
+///
+/// For example for non-positional `non_pos` and positional `pos` parsers
+/// ```rust
+/// # use bpaf::*;
+/// # let non_pos = || short('n').switch();
+/// # let pos = ||positional::<String>("POS");
+/// let valid = construct!(non_pos(), pos());
+/// let invalid = construct!(pos(), non_pos());
+/// ```
+///
+/// **`bpaf` panics during help generation unless this restriction holds**
+///
+/// Without using `--` `bpaf` would only accept items that don't start with `-` as positional, you
+/// can use [`any`] to work around this restriction.
+///
+/// By default `bpaf` accepts positional items with or without `--` where values permit, you can
+/// further restrict the parser to accept positional items only on the right side of `--` using
+/// [`strict`](ParsePositional::strict).
+#[cfg_attr(not(doctest), doc = include_str!("docs2/positional.md"))]
+#[must_use]
+pub fn positional<T>(metavar: &'static str) -> ParsePositional<T> {
+    build_positional(metavar)
+}
+
+#[doc(hidden)]
+#[deprecated = "You should switch from command(name, sub) to sub.command(name)"]
+pub fn command<T>(name: &'static str, subparser: OptionParser<T>) -> ParseCommand<T>
+where
+    T: 'static,
+{
+    ParseCommand {
+        longs: vec![name],
+        shorts: Vec::new(),
+        help: subparser.short_descr().map(Into::into),
+        subparser,
+        adjacent: false,
+    }
+}
+
+/// Parse a single arbitrary item from a command line
+///
+/// **`any` is designed to consume items that don't fit into the usual [`flag`](NamedArg::flag)
+/// /[`switch`](NamedArg::switch)/[`argument`](NamedArg::argument)/[`positional`]/
+/// [`command`](OptionParser::command) classification, in most cases you don't need to use it**
+///
+/// By default, `any` behaves similarly to [`positional`] so you should be using it near the
+/// rightmost end of the consumer struct and it will only try to parse the first unconsumed item
+/// on the command line. It is possible to lift this restriction by calling
+/// [`anywhere`](ParseAny::anywhere) on the parser.
+///
+/// `check` argument is a function from any type `I` that implements `FromStr` to `T`.
+/// Usually this should be `String` or `OsString`, but feel free to experiment. When
+/// running `any` tries to parse an item on a command line into that `I` and applies the `check`
+/// function. If the `check` succeeds - parser `any` succeeds and produces `T`, otherwise it behaves
+/// as if it hasn't seen it. If `any` works in `anywhere` mode - it will try to parse all other
+/// unconsumed items, otherwise, `any` fails.
+///
+/// # Use `any` to capture the remaining arguments
+/// Normally you would use [`positional`] with [`strict`](ParsePositional::strict) annotation for
+/// that, but using any allows you to blur the boundary between arguments for child process and self
+/// process a bit more.
+#[cfg_attr(not(doctest), doc = include_str!("docs2/any_simple.md"))]
+///
+/// # Use `any` to parse a non standard flag
+///
+#[cfg_attr(not(doctest), doc = include_str!("docs2/any_switch.md"))]
+///
+/// # Use `any` to parse a non standard argument
+/// Normally `any` would try to display itself as a usual metavariable in the usage line and
+/// generated help, you can customize that with [`metavar`](ParseAny::metavar) method:
+///
+#[cfg_attr(not(doctest), doc = include_str!("docs2/any_literal.md"))]
+///
+/// # See also
+/// [`literal`] - a specialized version of `any` that tries to parse a fixed literal
+#[must_use]
+pub fn any<I, T, F>(metavar: &str, check: F) -> ParseAny<T>
+where
+    I: FromStr + 'static,
+    F: Fn(I) -> Option<T> + 'static,
+    <I as std::str::FromStr>::Err: std::fmt::Display,
+{
+    ParseAny {
+        metavar: [(metavar, Style::Metavar)][..].into(),
+        help: None,
+        check: Box::new(move |os: std::ffi::OsString| {
+            match crate::from_os_str::parse_os_str::<I>(os) {
+                Ok(v) => check(v),
+                Err(_) => None,
+            }
+        }),
+
+        anywhere: false,
+    }
+}
+
+/// A specialized version of [`any`] that consumes an arbitrary string
+///
+/// By default `literal` behaves similarly to [`positional`] so you should be using it near the
+/// rightmost end of the consumer struct and it will only try to parse the first unconsumed
+/// item on the command line. It is possible to lift this restriction by calling
+/// [`anywhere`](ParseAny::anywhere) on the parser.
+///
+#[cfg_attr(not(doctest), doc = include_str!("docs2/any_literal.md"))]
+///
+/// # See also
+/// [`any`] - a generic version of `literal` that uses function to decide if value is to be parsed
+/// or not.
+#[must_use]
+pub fn literal(val: &'static str) -> ParseAny<()> {
+    any("", move |s: String| if s == val { Some(()) } else { None })
+        .metavar(&[(val, crate::buffer::Style::Literal)][..])
+}
+
+/// Strip a command name if present at the front when used as a `cargo` command
+///
+// this is exactly the same as batteries::cargo_helper, but used by derive macro...
+#[must_use]
+#[doc(hidden)]
+pub fn cargo_helper<P, T>(cmd: &'static str, parser: P) -> impl Parser<T>
+where
+    T: 'static,
+    P: Parser<T>,
+{
+    let skip = literal(cmd).optional().hide();
+    construct!(skip, parser).map(|x| x.1)
+}
+
+/// Choose between several parsers specified at runtime
+///
+/// You can use this function to create multiple parsers that produce the same type of value at a runtime
+/// and let bpaf to pick one that best fits best. This function is designed to work in Combinatoric
+/// API, but you can use it in Derive API with `extern`.
+///
+#[cfg_attr(not(doctest), doc = include_str!("docs2/choice.md"))]
+pub fn choice<T: 'static>(parsers: impl IntoIterator<Item = Box<dyn Parser<T>>>) -> impl Parser<T> {
+    let mut parsers = parsers.into_iter();
+    let mut this = match parsers.next() {
+        None => return fail("Invalid choice usage").boxed(),
+        Some(p) => p,
+    };
+    for that in parsers {
+        this = Box::new(ParseOrElse { this, that })
+    }
+    this
+}
+
\ No newline at end of file diff --git a/src/bpaf/meta.rs.html b/src/bpaf/meta.rs.html new file mode 100644 index 00000000..5451c61b --- /dev/null +++ b/src/bpaf/meta.rs.html @@ -0,0 +1,705 @@ +meta.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+
use crate::{buffer::Doc, item::Item};
+
+#[doc(hidden)]
+#[derive(Clone, Debug)]
+pub enum Meta {
+    /// All arguments listed in a vector must be present
+    And(Vec<Meta>),
+    /// One of arguments listed in a vector must be present
+    Or(Vec<Meta>),
+    /// Arguments are optional and encased in [] when rendered
+    Optional(Box<Meta>),
+    /// Arguments are requred and encased in () when rendered
+    Required(Box<Meta>),
+    /// Argumens are required to be adjacent to each other
+    Adjacent(Box<Meta>),
+    /// Primitive argument as described
+    Item(Box<Item>),
+    /// Accepts multiple arguments
+    Many(Box<Meta>),
+    /// Arguments form a subsection with buffer being it's header
+    ///
+    /// whole set of arguments go into the same section as the first one
+    Subsection(Box<Meta>, Box<Doc>),
+    /// Buffer is rendered after
+    Suffix(Box<Meta>, Box<Doc>),
+    /// This item is not rendered in the help message
+    Skip,
+    /// TODO make it Option<Box<Doc>>
+    CustomUsage(Box<Meta>, Box<Doc>),
+    /// this meta must be prefixed with -- in unsage group
+    Strict(Box<Meta>),
+}
+
+// to get std::mem::take to work
+impl Default for Meta {
+    fn default() -> Self {
+        Meta::Skip
+    }
+}
+
+// Meta::Strict should bubble up to one of 3 places:
+// - top level
+// - one of "and" elements
+// - one of "or" elements
+#[derive(Debug, Clone, Copy)]
+enum StrictNorm {
+    /// starting at the top and looking for Strict inside
+    Pull,
+    Push,
+    /// Already accounted for one, can strip the rest
+    Strip,
+}
+
+impl StrictNorm {
+    fn push(&mut self) {
+        match *self {
+            StrictNorm::Pull => *self = StrictNorm::Push,
+            StrictNorm::Push | StrictNorm::Strip => {}
+        }
+    }
+}
+
+impl Meta {
+    /// Used by normalization function to collapse duplicated commands.
+    /// It seems to be fine to strip section information but not anything else
+    fn is_command(&self) -> bool {
+        match self {
+            Meta::Item(i) => matches!(i.as_ref(), Item::Command { .. }),
+            Meta::Subsection(m, _) => m.is_command(),
+            _ => false,
+        }
+    }
+
+    /// do a nested invariant check
+    pub(crate) fn positional_invariant_check(&self, verbose: bool) {
+        fn go(meta: &Meta, is_pos: &mut bool, v: bool) {
+            match meta {
+                Meta::And(xs) => {
+                    for x in xs {
+                        go(x, is_pos, v);
+                    }
+                }
+                Meta::Or(xs) => {
+                    let mut out = *is_pos;
+                    for x in xs {
+                        let mut this_pos = *is_pos;
+                        go(x, &mut this_pos, v);
+                        out |= this_pos;
+                    }
+                    *is_pos = out;
+                }
+                Meta::Item(i) => {
+                    match (*is_pos, i.is_pos()) {
+                        (true, true) | (false, false) => {}
+                        (true, false) => {
+                            panic!("bpaf usage BUG: all positional and command items must be placed in the right \
+                        most position of the structure or tuple they are in but {:?} breaks this rule. \
+                        See bpaf documentation for `positional` for details.", i);
+                        }
+                        (false, true) => {
+                            *is_pos = true;
+                        }
+                    }
+                    if let Item::Command { meta, .. } = &**i {
+                        let mut command_pos = false;
+                        if v {
+                            println!("Checking\n{:#?}", meta);
+                        }
+                        go(meta, &mut command_pos, v);
+                    }
+                }
+                Meta::Adjacent(m) => {
+                    if let Some(i) = Meta::first_item(m) {
+                        if i.is_pos() {
+                            go(m, is_pos, v);
+                        } else {
+                            let mut inner = false;
+                            go(m, &mut inner, v);
+                        }
+                    }
+                }
+                Meta::Optional(m)
+                | Meta::Required(m)
+                | Meta::Many(m)
+                | Meta::CustomUsage(m, _)
+                | Meta::Subsection(m, _)
+                | Meta::Strict(m)
+                | Meta::Suffix(m, _) => go(m, is_pos, v),
+                Meta::Skip => {}
+            }
+        }
+        let mut is_pos = false;
+        if verbose {
+            println!("Checking\n{:#?}", self);
+        }
+        go(self, &mut is_pos, verbose);
+    }
+
+    pub(crate) fn normalized(&self, for_usage: bool) -> Meta {
+        let mut m = self.clone();
+        let mut norm = StrictNorm::Pull;
+        m.normalize(for_usage, &mut norm);
+        // stip outer () around meta unless inner
+        if let Meta::Required(i) = m {
+            m = *i;
+        }
+        if matches!(m, Meta::Or(_)) {
+            m = Meta::Required(Box::new(m));
+        }
+        if matches!(norm, StrictNorm::Push) {
+            m = Meta::Strict(Box::new(m));
+        }
+        m
+    }
+
+    /// Used by adjacent parsers since it inherits behavior of the front item
+    pub(crate) fn first_item(meta: &Meta) -> Option<&Item> {
+        match meta {
+            Meta::And(xs) => xs.first().and_then(Self::first_item),
+            Meta::Item(item) => Some(item),
+            Meta::Skip | Meta::Or(_) => None,
+            Meta::Optional(x)
+            | Meta::Strict(x)
+            | Meta::Required(x)
+            | Meta::Adjacent(x)
+            | Meta::Many(x)
+            | Meta::Subsection(x, _)
+            | Meta::Suffix(x, _)
+            | Meta::CustomUsage(x, _) => Self::first_item(x),
+        }
+    }
+
+    /// Normalize meta info for display as usage. Required propagates outwards
+    fn normalize(&mut self, for_usage: bool, norm: &mut StrictNorm) {
+        fn normalize_vec(
+            xs: &mut Vec<Meta>,
+            for_usage: bool,
+            norm: &mut StrictNorm,
+            or: bool,
+        ) -> Option<Meta> {
+            let mut final_norm = *norm;
+            for m in xs.iter_mut() {
+                let mut this_norm = *norm;
+                m.normalize(for_usage, &mut this_norm);
+                let target: &mut StrictNorm = if or { &mut final_norm } else { norm };
+
+                match (*target, this_norm) {
+                    (_, StrictNorm::Pull) | (StrictNorm::Strip, _) => {}
+                    (StrictNorm::Pull, StrictNorm::Push) => {
+                        *m = Meta::Strict(Box::new(std::mem::take(m)));
+                        *target = StrictNorm::Strip;
+                    }
+                    _ => {
+                        *target = this_norm;
+                    }
+                }
+            }
+            xs.retain(|m| !matches!(m, Meta::Skip));
+
+            *norm = final_norm;
+
+            match xs.len() {
+                0 => Some(Meta::Skip),
+                1 => Some(xs.remove(0)),
+                _ => None,
+            }
+        }
+
+        match self {
+            Meta::And(xs) => {
+                if let Some(replacement) = normalize_vec(xs, for_usage, norm, false) {
+                    *self = replacement;
+                }
+            }
+            // or should have either () or [] around it
+            Meta::Or(xs) => {
+                if let Some(replacement) = normalize_vec(xs, for_usage, norm, true) {
+                    *self = replacement;
+                } else {
+                    let mut saw_cmd = false;
+                    // drop all the commands apart from the first one
+                    xs.retain(|m| {
+                        let is_cmd = m.is_command();
+                        let keep = !(is_cmd && saw_cmd);
+                        saw_cmd |= is_cmd;
+                        keep
+                    });
+                    match xs.len() {
+                        0 => *self = Meta::Skip,
+                        1 => *self = xs.remove(0),
+                        _ => *self = Meta::Required(Box::new(std::mem::take(self))),
+                    }
+                }
+            }
+            Meta::Optional(m) => {
+                m.normalize(for_usage, norm);
+                if matches!(**m, Meta::Skip) {
+                    // Optional(Skip) => Skip
+                    *self = Meta::Skip;
+                } else if let Meta::Required(mm) | Meta::Optional(mm) = m.as_mut() {
+                    // Optional(Required(m)) => Optional(m)
+                    // Optional(Optional(m)) => Optional(m)
+                    *m = std::mem::take(mm);
+                } else if let Meta::Many(many) = m.as_mut() {
+                    // Optional(Many(Required(m))) => Many(Optional(m))
+                    if let Meta::Required(x) = many.as_mut() {
+                        *self = Meta::Many(Box::new(Meta::Optional(std::mem::take(x))));
+                    }
+                }
+            }
+            Meta::Required(m) => {
+                m.normalize(for_usage, norm);
+                if matches!(**m, Meta::Skip) {
+                    // Required(Skip) => Skip
+                    *self = Meta::Skip;
+                } else if matches!(**m, Meta::And(_) | Meta::Or(_)) {
+                    // keep () around composite parsers
+                } else {
+                    // and strip them elsewhere
+                    *self = std::mem::take(m);
+                }
+            }
+            Meta::Many(m) => {
+                m.normalize(for_usage, norm);
+                if matches!(**m, Meta::Skip) {
+                    *self = Meta::Skip;
+                }
+            }
+            Meta::Adjacent(m) | Meta::Subsection(m, _) | Meta::Suffix(m, _) => {
+                m.normalize(for_usage, norm);
+                *self = std::mem::take(m);
+            }
+            Meta::Item(i) => i.normalize(for_usage),
+            Meta::Skip => {
+                // nothing to do with items and skip just bubbles upwards
+            }
+            Meta::CustomUsage(m, u) => {
+                m.normalize(for_usage, norm);
+                // strip CustomUsage if we are not in usage so writer can simply render it
+                if for_usage {
+                    if u.is_empty() {
+                        *self = Meta::Skip;
+                    }
+                } else {
+                    *self = std::mem::take(m);
+                }
+            }
+            Meta::Strict(m) => {
+                m.normalize(for_usage, norm);
+                norm.push();
+                *self = std::mem::take(m);
+            }
+        }
+    }
+}
+
+impl From<Item> for Meta {
+    fn from(value: Item) -> Self {
+        Meta::Item(Box::new(value))
+    }
+}
+
+impl Meta {
+    fn alts(self, to: &mut Vec<Meta>) {
+        match self {
+            Meta::Or(mut xs) => to.append(&mut xs),
+            Meta::Skip => {}
+            meta => to.push(meta),
+        }
+    }
+
+    pub(crate) fn or(self, other: Meta) -> Self {
+        let mut res = Vec::new();
+        self.alts(&mut res);
+        other.alts(&mut res);
+        match res.len() {
+            0 => Meta::Skip,
+            1 => res.remove(0),
+            _ => Meta::Or(res),
+        }
+    }
+
+    /// collect different kinds of short names for disambiguation
+    pub(crate) fn collect_shorts(&self, flags: &mut Vec<char>, args: &mut Vec<char>) {
+        match self {
+            Meta::And(xs) | Meta::Or(xs) => {
+                for x in xs {
+                    x.collect_shorts(flags, args);
+                }
+            }
+            Meta::Item(m) => match &**m {
+                Item::Any { .. } | Item::Positional { .. } => {}
+                Item::Command { meta, .. } => {
+                    meta.collect_shorts(flags, args);
+                }
+                Item::Flag { shorts, .. } => flags.extend(shorts),
+                Item::Argument { shorts, .. } => args.extend(shorts),
+            },
+            Meta::CustomUsage(m, _)
+            | Meta::Required(m)
+            | Meta::Optional(m)
+            | Meta::Adjacent(m)
+            | Meta::Subsection(m, _)
+            | Meta::Suffix(m, _)
+            | Meta::Many(m) => {
+                m.collect_shorts(flags, args);
+            }
+            Meta::Skip | Meta::Strict(_) => {}
+        }
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/meta_help.rs.html b/src/bpaf/meta_help.rs.html new file mode 100644 index 00000000..9b579188 --- /dev/null +++ b/src/bpaf/meta_help.rs.html @@ -0,0 +1,1339 @@ +meta_help.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+
use std::collections::BTreeSet;
+
+use crate::{
+    buffer::{Block, Doc, Style, Token},
+    info::Info,
+    item::{Item, ShortLong},
+    Meta,
+};
+
+#[doc(hidden)]
+#[derive(Debug, Clone, Copy)]
+pub struct Metavar(pub(crate) &'static str);
+
+#[derive(Debug, Clone, Copy)]
+pub(crate) enum HelpItem<'a> {
+    DecorSuffix {
+        help: &'a Doc,
+        ty: HiTy,
+    },
+    GroupStart {
+        help: &'a Doc,
+        ty: HiTy,
+    },
+    GroupEnd {
+        ty: HiTy,
+    },
+    Any {
+        metavar: &'a Doc,
+        anywhere: bool,
+        help: Option<&'a Doc>,
+    },
+    Positional {
+        metavar: Metavar,
+        help: Option<&'a Doc>,
+    },
+    Command {
+        name: &'static str,
+        short: Option<char>,
+        help: Option<&'a Doc>,
+        meta: &'a Meta,
+        #[cfg(feature = "docgen")]
+        info: &'a Info,
+    },
+    Flag {
+        name: ShortLong,
+        env: Option<&'static str>,
+        help: Option<&'a Doc>,
+    },
+    Argument {
+        name: ShortLong,
+        metavar: Metavar,
+        env: Option<&'static str>,
+        help: Option<&'a Doc>,
+    },
+    AnywhereStart {
+        inner: &'a Meta,
+        ty: HiTy,
+    },
+    AnywhereStop {
+        ty: HiTy,
+    },
+}
+impl HelpItem<'_> {
+    fn has_help(&self) -> bool {
+        match self {
+            HelpItem::Positional { help, .. }
+            | HelpItem::Command { help, .. }
+            | HelpItem::Flag { help, .. }
+            | HelpItem::Any { help, .. }
+            | HelpItem::Argument { help, .. } => help.is_some(),
+            HelpItem::GroupStart { .. } | HelpItem::DecorSuffix { .. } => true,
+            HelpItem::GroupEnd { .. }
+            | HelpItem::AnywhereStart { .. }
+            | HelpItem::AnywhereStop { .. } => false,
+        }
+    }
+
+    fn ty(&self) -> HiTy {
+        match self {
+            HelpItem::GroupStart { ty, .. }
+            | HelpItem::DecorSuffix { ty, .. }
+            | HelpItem::GroupEnd { ty }
+            | HelpItem::AnywhereStart { ty, .. }
+            | HelpItem::AnywhereStop { ty } => *ty,
+            HelpItem::Any {
+                anywhere: false, ..
+            }
+            | HelpItem::Positional { .. } => HiTy::Positional,
+            HelpItem::Command { .. } => HiTy::Command,
+            HelpItem::Any { anywhere: true, .. }
+            | HelpItem::Flag { .. }
+            | HelpItem::Argument { .. } => HiTy::Flag,
+        }
+    }
+}
+
+#[derive(Default, Debug)]
+/// A collection of all the help items separated into flags, positionals and commands
+///
+/// Items are stored as references and can be trivially copied
+pub(crate) struct HelpItems<'a> {
+    pub(crate) items: Vec<HelpItem<'a>>,
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+pub(crate) enum HiTy {
+    Flag,
+    Command,
+    Positional,
+}
+
+enum ItemBlock {
+    No,
+    Decor(HiTy),
+    Anywhere(HiTy),
+}
+
+pub(crate) struct HelpItemsIter<'a, 'b> {
+    items: &'b [HelpItem<'a>],
+    target: HiTy,
+    cur: usize,
+    block: ItemBlock,
+}
+
+impl<'a, 'b> Iterator for HelpItemsIter<'a, 'b> {
+    type Item = &'b HelpItem<'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        loop {
+            let item = self.items.get(self.cur)?;
+            self.cur += 1;
+
+            let keep = match item {
+                HelpItem::AnywhereStart { ty, .. } => {
+                    self.block = ItemBlock::Anywhere(*ty);
+                    *ty == self.target
+                }
+                HelpItem::GroupStart { ty, .. } => {
+                    self.block = ItemBlock::Decor(*ty);
+                    *ty == self.target
+                }
+                HelpItem::GroupEnd { ty, .. } | HelpItem::AnywhereStop { ty, .. } => {
+                    self.block = ItemBlock::No;
+                    *ty == self.target
+                }
+                HelpItem::DecorSuffix { .. }
+                | HelpItem::Any { .. }
+                | HelpItem::Command { .. }
+                | HelpItem::Positional { .. }
+                | HelpItem::Flag { .. }
+                | HelpItem::Argument { .. } => {
+                    let ty = item.ty();
+                    match self.block {
+                        ItemBlock::No => ty == self.target,
+                        ItemBlock::Decor(t) => t == self.target,
+                        ItemBlock::Anywhere(t) => t == self.target && item.has_help(),
+                    }
+                }
+            };
+            if keep {
+                return Some(item);
+            }
+        }
+    }
+}
+
+impl<'a> HelpItems<'a> {
+    #[inline(never)]
+    fn items_of_ty(&self, target: HiTy) -> impl Iterator<Item = &HelpItem> {
+        HelpItemsIter {
+            items: &self.items,
+            target,
+            cur: 0,
+            block: ItemBlock::No,
+        }
+    }
+}
+
+impl Meta {
+    fn peek_front_ty(&self) -> Option<HiTy> {
+        match self {
+            Meta::And(xs) | Meta::Or(xs) => xs.iter().find_map(Meta::peek_front_ty),
+            Meta::Optional(x)
+            | Meta::Required(x)
+            | Meta::Adjacent(x)
+            | Meta::Many(x)
+            | Meta::Subsection(x, _)
+            | Meta::Suffix(x, _)
+            | Meta::Strict(x)
+            | Meta::CustomUsage(x, _) => x.peek_front_ty(),
+            Meta::Item(i) => Some(HiTy::from(i.as_ref())),
+            Meta::Skip => None,
+        }
+    }
+}
+
+impl<'a> HelpItems<'a> {
+    /// Recursively classify contents of the Meta
+    pub(crate) fn append_meta(&mut self, meta: &'a Meta) {
+        fn go<'a>(hi: &mut HelpItems<'a>, meta: &'a Meta, no_ss: bool) {
+            match meta {
+                Meta::And(xs) | Meta::Or(xs) => {
+                    for x in xs {
+                        go(hi, x, no_ss);
+                    }
+                }
+                Meta::Adjacent(m) => {
+                    if let Some(ty) = m.peek_front_ty() {
+                        hi.items.push(HelpItem::AnywhereStart {
+                            inner: m.as_ref(),
+                            ty,
+                        });
+                        go(hi, m, no_ss);
+                        hi.items.push(HelpItem::AnywhereStop { ty });
+                    }
+                }
+                Meta::CustomUsage(x, _)
+                | Meta::Required(x)
+                | Meta::Optional(x)
+                | Meta::Many(x)
+                | Meta::Strict(x) => go(hi, x, no_ss),
+                Meta::Item(item) => {
+                    if matches!(item.as_ref(), Item::Positional { help: None, .. }) {
+                        return;
+                    }
+                    hi.items.push(HelpItem::from(item.as_ref()));
+                }
+                Meta::Subsection(m, help) => {
+                    if let Some(ty) = m.peek_front_ty() {
+                        if no_ss {
+                            go(hi, m, true);
+                        } else {
+                            hi.items.push(HelpItem::GroupStart { help, ty });
+                            go(hi, m, true);
+                            hi.items.push(HelpItem::GroupEnd { ty });
+                        }
+                    }
+                }
+                Meta::Suffix(m, help) => {
+                    if let Some(ty) = m.peek_front_ty() {
+                        go(hi, m, no_ss);
+                        hi.items.push(HelpItem::DecorSuffix { help, ty });
+                    }
+                }
+                Meta::Skip => (),
+            }
+        }
+        go(self, meta, false);
+    }
+
+    fn find_group(&self) -> Option<std::ops::RangeInclusive<usize>> {
+        let start = self
+            .items
+            .iter()
+            .position(|i| matches!(i, HelpItem::GroupStart { .. }))?;
+        let end = self
+            .items
+            .iter()
+            .position(|i| matches!(i, HelpItem::GroupEnd { .. }))?;
+        Some(start..=end)
+    }
+}
+
+impl From<&Item> for HiTy {
+    fn from(value: &Item) -> Self {
+        match value {
+            Item::Positional { .. }
+            | Item::Any {
+                anywhere: false, ..
+            } => Self::Positional,
+            Item::Command { .. } => Self::Command,
+            Item::Any { anywhere: true, .. } | Item::Flag { .. } | Item::Argument { .. } => {
+                Self::Flag
+            }
+        }
+    }
+}
+
+impl<'a> From<&'a Item> for HelpItem<'a> {
+    // {{{
+    fn from(item: &'a Item) -> Self {
+        match item {
+            Item::Positional { metavar, help } => Self::Positional {
+                metavar: *metavar,
+                help: help.as_ref(),
+            },
+            Item::Command {
+                name,
+                short,
+                help,
+                meta,
+                #[cfg(feature = "docgen")]
+                info,
+                #[cfg(not(feature = "docgen"))]
+                    info: _,
+            } => Self::Command {
+                name,
+                short: *short,
+                help: help.as_ref(),
+                meta,
+                #[cfg(feature = "docgen")]
+                info,
+            },
+            Item::Flag {
+                name,
+                env,
+                help,
+                shorts: _,
+            } => Self::Flag {
+                name: *name,
+                env: *env,
+                help: help.as_ref(),
+            },
+            Item::Argument {
+                name,
+                metavar,
+                env,
+                help,
+                shorts: _,
+            } => Self::Argument {
+                name: *name,
+                metavar: *metavar,
+                env: *env,
+                help: help.as_ref(),
+            },
+            Item::Any {
+                metavar,
+                anywhere,
+                help,
+            } => Self::Any {
+                metavar,
+                anywhere: *anywhere,
+                help: help.as_ref(),
+            },
+        }
+    }
+} // }}}
+
+impl Doc {
+    #[inline(never)]
+    pub(crate) fn metavar(&mut self, metavar: Metavar) {
+        if metavar
+            .0
+            .chars()
+            .all(|c| c.is_uppercase() || c.is_ascii_digit() || c == '-' || c == '_')
+        {
+            self.write_str(metavar.0, Style::Metavar);
+        } else {
+            self.write_char('<', Style::Metavar);
+            self.write_str(metavar.0, Style::Metavar);
+            self.write_char('>', Style::Metavar);
+        }
+    }
+}
+
+#[allow(clippy::too_many_lines)] // lines are _very_ boring
+fn write_help_item(buf: &mut Doc, item: &HelpItem, include_env: bool) {
+    match item {
+        HelpItem::GroupStart { help, .. } => {
+            buf.token(Token::BlockStart(Block::Block));
+            buf.token(Token::BlockStart(Block::Section2));
+            buf.em_doc(help);
+            buf.token(Token::BlockEnd(Block::Section2));
+            buf.token(Token::BlockStart(Block::DefinitionList));
+        }
+        HelpItem::GroupEnd { .. } => {
+            buf.token(Token::BlockEnd(Block::DefinitionList));
+            buf.token(Token::BlockEnd(Block::Block));
+        }
+        HelpItem::DecorSuffix { help, .. } => {
+            buf.token(Token::BlockStart(Block::ItemTerm));
+            buf.token(Token::BlockEnd(Block::ItemTerm));
+            buf.token(Token::BlockStart(Block::ItemBody));
+            buf.doc(help);
+            buf.token(Token::BlockEnd(Block::ItemBody));
+        }
+        HelpItem::Any {
+            metavar,
+            help,
+            anywhere: _,
+        } => {
+            buf.token(Token::BlockStart(Block::ItemTerm));
+            buf.doc(metavar);
+            buf.token(Token::BlockEnd(Block::ItemTerm));
+            if let Some(help) = help {
+                buf.token(Token::BlockStart(Block::ItemBody));
+                buf.doc(help);
+                buf.token(Token::BlockEnd(Block::ItemBody));
+            }
+        }
+        HelpItem::Positional { metavar, help } => {
+            buf.token(Token::BlockStart(Block::ItemTerm));
+            buf.metavar(*metavar);
+            buf.token(Token::BlockEnd(Block::ItemTerm));
+            if let Some(help) = help {
+                buf.token(Token::BlockStart(Block::ItemBody));
+                buf.doc(help);
+                buf.token(Token::BlockEnd(Block::ItemBody));
+            }
+        }
+        HelpItem::Command {
+            name,
+            short,
+            help,
+            meta: _,
+            #[cfg(feature = "docgen")]
+                info: _,
+        } => {
+            buf.token(Token::BlockStart(Block::ItemTerm));
+            buf.write_str(name, Style::Literal);
+            if let Some(short) = short {
+                buf.write_str(", ", Style::Text);
+                buf.write_char(*short, Style::Literal);
+            }
+            buf.token(Token::BlockEnd(Block::ItemTerm));
+            if let Some(help) = help {
+                buf.token(Token::BlockStart(Block::ItemBody));
+                buf.doc(help);
+                buf.token(Token::BlockEnd(Block::ItemBody));
+            }
+        }
+        HelpItem::Flag { name, env, help } => {
+            buf.token(Token::BlockStart(Block::ItemTerm));
+            write_shortlong(buf, *name);
+            buf.token(Token::BlockEnd(Block::ItemTerm));
+            if let Some(help) = help {
+                buf.token(Token::BlockStart(Block::ItemBody));
+                buf.doc(help);
+                buf.token(Token::BlockEnd(Block::ItemBody));
+            }
+            if let Some(env) = env {
+                let val = if std::env::var_os(env).is_some() {
+                    ": set"
+                } else {
+                    ": not set"
+                };
+                if help.is_some() {
+                    buf.token(Token::BlockStart(Block::ItemTerm));
+                    buf.token(Token::BlockEnd(Block::ItemTerm));
+                }
+                buf.token(Token::BlockStart(Block::ItemBody));
+                if include_env {
+                    buf.write_str(&format!("[env:{}{}]", env, val), Style::Text);
+                } else {
+                    buf.text("Uses environment variable ");
+                    buf.literal(env);
+                }
+                buf.token(Token::BlockEnd(Block::ItemBody));
+            }
+        }
+        HelpItem::Argument {
+            name,
+            metavar,
+            env,
+            help,
+        } => {
+            buf.token(Token::BlockStart(Block::ItemTerm));
+            write_shortlong(buf, *name);
+            buf.write_str("=", Style::Text);
+            buf.metavar(*metavar);
+            buf.token(Token::BlockEnd(Block::ItemTerm));
+
+            if let Some(help) = help {
+                buf.token(Token::BlockStart(Block::ItemBody));
+                buf.doc(help);
+                buf.token(Token::BlockEnd(Block::ItemBody));
+            }
+
+            if let Some(env) = env {
+                let val = match std::env::var_os(env) {
+                    Some(s) => std::borrow::Cow::from(format!(" = {:?}", s.to_string_lossy())),
+                    None => std::borrow::Cow::Borrowed(": N/A"),
+                };
+
+                if help.is_some() {
+                    buf.token(Token::BlockStart(Block::ItemTerm));
+                    buf.token(Token::BlockEnd(Block::ItemTerm));
+                }
+                buf.token(Token::BlockStart(Block::ItemBody));
+
+                if include_env {
+                    buf.write_str(&format!("[env:{}{}]", env, val), Style::Text);
+                } else {
+                    buf.text("Uses environment variable ");
+                    buf.literal(env);
+                }
+
+                buf.token(Token::BlockEnd(Block::ItemBody));
+            }
+        }
+        HelpItem::AnywhereStart { inner, .. } => {
+            buf.token(Token::BlockStart(Block::Section3));
+            buf.write_meta(inner, true);
+            buf.token(Token::BlockEnd(Block::Section3));
+        }
+        HelpItem::AnywhereStop { .. } => {
+            buf.token(Token::BlockStart(Block::Block));
+            buf.token(Token::BlockEnd(Block::Block));
+        }
+    }
+}
+
+fn write_shortlong(buf: &mut Doc, name: ShortLong) {
+    match name {
+        ShortLong::Short(s) => {
+            buf.write_char('-', Style::Literal);
+            buf.write_char(s, Style::Literal);
+        }
+        ShortLong::Long(l) => {
+            buf.write_str("    --", Style::Literal);
+            buf.write_str(l, Style::Literal);
+        }
+        ShortLong::Both(s, l) => {
+            buf.write_char('-', Style::Literal);
+            buf.write_char(s, Style::Literal);
+            buf.write_str(", ", Style::Text);
+            buf.write_str("--", Style::Literal);
+            buf.write_str(l, Style::Literal);
+        }
+    }
+}
+
+#[inline(never)]
+pub(crate) fn render_help(
+    path: &[String],
+    info: &Info,
+    parser_meta: &Meta,
+    help_meta: &Meta,
+    include_env: bool,
+) -> Doc {
+    parser_meta.positional_invariant_check(false);
+    let mut buf = Doc::default();
+
+    if let Some(t) = &info.descr {
+        buf.token(Token::BlockStart(Block::Block));
+        buf.doc(t);
+        buf.token(Token::BlockEnd(Block::Block));
+    }
+
+    buf.token(Token::BlockStart(Block::Block));
+    if let Some(usage) = &info.usage {
+        buf.doc(usage);
+    } else {
+        buf.write_str("Usage", Style::Emphasis);
+        buf.write_str(": ", Style::Text);
+        buf.token(Token::BlockStart(Block::Mono));
+        buf.write_path(path);
+        buf.write_meta(parser_meta, true);
+        buf.token(Token::BlockEnd(Block::Mono));
+    }
+    buf.token(Token::BlockEnd(Block::Block));
+
+    if let Some(t) = &info.header {
+        buf.token(Token::BlockStart(Block::Block));
+        buf.doc(t);
+        buf.token(Token::BlockEnd(Block::Block));
+    }
+
+    let mut items = HelpItems::default();
+    items.append_meta(parser_meta);
+    items.append_meta(help_meta);
+
+    buf.write_help_item_groups(items, include_env);
+
+    if let Some(footer) = &info.footer {
+        buf.token(Token::BlockStart(Block::Block));
+        buf.doc(footer);
+        buf.token(Token::BlockEnd(Block::Block));
+    }
+    buf
+}
+
+#[derive(Default)]
+struct Dedup {
+    items: BTreeSet<String>,
+    keep: bool,
+}
+
+impl Dedup {
+    fn check(&mut self, item: &HelpItem) -> bool {
+        match item {
+            HelpItem::DecorSuffix { .. } => std::mem::take(&mut self.keep),
+            HelpItem::GroupStart { .. }
+            | HelpItem::GroupEnd { .. }
+            | HelpItem::AnywhereStart { .. }
+            | HelpItem::AnywhereStop { .. } => {
+                self.keep = true;
+                true
+            }
+            HelpItem::Any { metavar, help, .. } => {
+                self.keep = self.items.insert(format!("{:?} {:?}", metavar, help));
+                self.keep
+            }
+            HelpItem::Positional { metavar, help } => {
+                self.keep = self.items.insert(format!("{:?} {:?}", metavar.0, help));
+                self.keep
+            }
+            HelpItem::Command { name, help, .. } => {
+                self.keep = self.items.insert(format!("{:?} {:?}", name, help));
+                self.keep
+            }
+            HelpItem::Flag { name, help, .. } => {
+                self.keep = self.items.insert(format!("{:?} {:?}", name, help));
+                self.keep
+            }
+            HelpItem::Argument {
+                name,
+                metavar,
+                help,
+                ..
+            } => {
+                self.keep = self
+                    .items
+                    .insert(format!("{:?} {} {:?}", name, metavar.0, help));
+                self.keep
+            }
+        }
+    }
+}
+
+impl Doc {
+    #[inline(never)]
+    pub(crate) fn write_help_item_groups(&mut self, mut items: HelpItems, include_env: bool) {
+        while let Some(range) = items.find_group() {
+            let mut dd = Dedup::default();
+            for item in items.items.drain(range) {
+                if dd.check(&item) {
+                    write_help_item(self, &item, include_env);
+                }
+            }
+        }
+
+        for (ty, name) in [
+            (HiTy::Positional, "Available positional items:"),
+            (HiTy::Flag, "Available options:"),
+            (HiTy::Command, "Available commands:"),
+        ] {
+            self.write_help_items(&items, ty, name, include_env);
+        }
+    }
+
+    #[inline(never)]
+    fn write_help_items(&mut self, items: &HelpItems, ty: HiTy, name: &str, include_env: bool) {
+        let mut xs = items.items_of_ty(ty).peekable();
+        if xs.peek().is_some() {
+            self.token(Token::BlockStart(Block::Block));
+            self.token(Token::BlockStart(Block::Section2));
+            self.write_str(name, Style::Emphasis);
+            self.token(Token::BlockEnd(Block::Section2));
+            self.token(Token::BlockStart(Block::DefinitionList));
+            let mut dd = Dedup::default();
+            for item in xs {
+                if dd.check(item) {
+                    write_help_item(self, item, include_env);
+                }
+            }
+            self.token(Token::BlockEnd(Block::DefinitionList));
+            self.token(Token::BlockEnd(Block::Block));
+        }
+    }
+
+    pub(crate) fn write_path(&mut self, path: &[String]) {
+        for item in path {
+            self.write_str(item, Style::Literal);
+            self.write_char(' ', Style::Text);
+        }
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/meta_youmean.rs.html b/src/bpaf/meta_youmean.rs.html new file mode 100644 index 00000000..647b8638 --- /dev/null +++ b/src/bpaf/meta_youmean.rs.html @@ -0,0 +1,371 @@ +meta_youmean.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+
use crate::{
+    item::ShortLong,
+    meta_help::{HelpItem, HelpItems},
+    Meta, State,
+};
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum Variant {
+    CommandLong(&'static str),
+    Flag(ShortLong),
+}
+
+#[derive(Debug)]
+pub(crate) enum Suggestion {
+    Variant(Variant),
+    /// expected --foo, actual -foo
+    MissingDash(&'static str),
+    /// expected -f, actual --f
+    ExtraDash(char),
+    Nested(String, Variant),
+}
+
+/// Looks for potential typos
+#[inline(never)]
+pub(crate) fn suggest(args: &State, meta: &Meta) -> Option<(usize, Suggestion)> {
+    let (ix, arg) = args.items_iter().next()?;
+
+    // suggesting typos for parts of group of short names (-vvv, typo in third v) would be strange
+    if arg.os_str().is_empty() {
+        return None;
+    }
+    // don't try to suggest fixes for typos in strictly positional items
+    if matches!(arg, crate::args::Arg::PosWord(_)) {
+        return None;
+    }
+    // it also should be a printable name
+    let actual = arg.to_string();
+
+    // all the help items one level deep
+    let mut hi = HelpItems::default();
+    hi.append_meta(meta);
+
+    // this will be used to avoid reallocations on scannign
+    let mut nested = HelpItems::default();
+
+    // while scanning keep the closest match
+    let mut best_match = None;
+    let mut best_dist = usize::MAX;
+    let mut improve = |dist, val| {
+        if best_dist > dist && dist > 0 && dist < 4 {
+            best_dist = dist;
+            best_match = Some(val);
+        }
+    };
+
+    let mut nest = None;
+
+    for item in &hi.items {
+        match item {
+            HelpItem::Command { name, meta, .. } => {
+                // command can result in 2 types of suggestions:
+                // - typo in a short or a long name
+                // - there is a nested command that matches perfectly - try using that
+                let distance = damerau_levenshtein(&actual, name);
+                improve(distance, Variant::CommandLong(name));
+
+                // scan nested items and look for exact matches only
+                nested.items.clear();
+                nested.append_meta(meta);
+                for item in &nested.items {
+                    match item {
+                        HelpItem::Command { name: nname, .. } => {
+                            if *nname == actual {
+                                nest = Some((name, Variant::CommandLong(nname)));
+                            }
+                        }
+                        HelpItem::Flag { name: nname, .. }
+                        | HelpItem::Argument { name: nname, .. } => {
+                            if *nname == &actual {
+                                nest = Some((name, Variant::Flag(*nname)));
+                            }
+                        }
+                        HelpItem::DecorSuffix { .. }
+                        | HelpItem::GroupStart { .. }
+                        | HelpItem::GroupEnd { .. }
+                        | HelpItem::Positional { .. }
+                        | HelpItem::AnywhereStart { .. }
+                        | HelpItem::AnywhereStop { .. }
+                        | HelpItem::Any { .. } => {}
+                    }
+                }
+            }
+            HelpItem::Flag { name, .. } | HelpItem::Argument { name, .. } => {
+                if let Some(long) = name.as_long() {
+                    let distance = damerau_levenshtein(&actual, &format!("--{}", long));
+                    improve(distance, Variant::Flag(*name));
+                }
+                if let Some(short) = name.as_short() {
+                    if let Some(act) = actual.strip_prefix("--") {
+                        let mut tmp = [0u8; 4];
+                        if act == short.encode_utf8(&mut tmp) {
+                            return Some((ix, Suggestion::ExtraDash(short)));
+                        }
+                    }
+                }
+            }
+            HelpItem::Positional { .. }
+            | HelpItem::DecorSuffix { .. }
+            | HelpItem::GroupStart { .. }
+            | HelpItem::GroupEnd { .. }
+            | HelpItem::AnywhereStart { .. }
+            | HelpItem::AnywhereStop { .. }
+            | HelpItem::Any { .. } => {}
+        }
+    }
+
+    if let Some((&name, variant)) = nest {
+        Some((ix, Suggestion::Nested(name.to_string(), variant)))
+    } else {
+        // skip confusing errors
+        if best_dist == usize::MAX {
+            return None;
+        }
+        let best_match = best_match?;
+
+        // handle missing single dash typos separately
+        if let Variant::Flag(n) = best_match {
+            if let Some(long) = n.as_long() {
+                if actual.strip_prefix('-') == Some(long) {
+                    return Some((ix, Suggestion::MissingDash(long)));
+                }
+            }
+        }
+        Some((ix, Suggestion::Variant(best_match)))
+    }
+}
+
+/// Damerau-Levenshtein distance function
+///
+/// returns `usize::MAX` if there's no common characters at all mostly to avoid
+/// confusing error messages - "you typed 'foo', maybe you ment 'bar'" where
+/// 'foo' and 'bar' don't have anything in common
+fn damerau_levenshtein(a: &str, b: &str) -> usize {
+    #![allow(clippy::many_single_char_names)]
+    let a_len = a.chars().count();
+    let b_len = b.chars().count();
+    let mut d = vec![0; (a_len + 1) * (b_len + 1)];
+
+    let ix = |ib, ia| a_len * ia + ib;
+
+    for i in 0..=a_len {
+        d[ix(i, 0)] = i;
+    }
+
+    for j in 0..=b_len {
+        d[ix(0, j)] = j;
+    }
+
+    let mut pa = '\0';
+    let mut pb = '\0';
+    for (i, ca) in a.chars().enumerate() {
+        let i = i + 1;
+        for (j, cb) in b.chars().enumerate() {
+            let j = j + 1;
+            let cost = usize::from(ca != cb);
+            d[ix(i, j)] = (d[ix(i - 1, j)] + 1)
+                .min(d[ix(i, j - 1)] + 1)
+                .min(d[ix(i - 1, j - 1)] + cost);
+            if i > 1 && j > 1 && ca == pb && cb == pa {
+                d[ix(i, j)] = d[ix(i, j)].min(d[ix(i - 2, j - 2)] + 1);
+            }
+            pb = cb;
+        }
+        pa = ca;
+    }
+
+    let diff = d[ix(a_len, b_len)];
+
+    if diff >= a_len.min(b_len) {
+        usize::MAX
+    } else {
+        diff
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/params.rs.html b/src/bpaf/params.rs.html new file mode 100644 index 00000000..0035b010 --- /dev/null +++ b/src/bpaf/params.rs.html @@ -0,0 +1,1841 @@ +params.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+
//! Tools to define primitive parsers
+//!
+//! # Ways to consume data
+//!
+//! ## Flag
+//!
+//! - [`flag`](NamedArg::flag) - a string that consists of two dashes (`--flag`) and a name and a single
+//! dash and a single character (`-f`) created with [`long`](NamedArg::long) and [`short`](NamedArg::short)
+//! respectively. Depending if this name is present or absent on the command line
+//! primitive flag parser produces one of two values. User can combine several short flags in a single
+//! invocation: `-a -b -c` is the same as `-abc`.
+//!
+#![cfg_attr(not(doctest), doc = include_str!("docs2/flag.md"))]
+//!
+//! ## Required flag
+//!
+//! Similar to `flag`, but instead of falling back to the second value required flag parser would
+//! fail. Mostly useful in combination with other parsers, created with [`NamedArg::req_flag`].
+//!
+#![cfg_attr(not(doctest), doc = include_str!("docs2/req_flag.md"))]
+//!
+//! ## Switch
+//!
+//! A special case of a flag that gets decoded into a `bool`, mostly serves as a convenient
+//! shortcut to `.flag(true, false)`. Created with [`NamedArg::switch`].
+//!
+#![cfg_attr(not(doctest), doc = include_str!("docs2/switch.md"))]
+//!
+//! ## Argument
+//!
+//! A short or long `flag` followed by either a space or `=` and
+//! then by a string literal.  `-f foo`, `--flag bar` or `-o=-` are all valid argument examples. Note, string
+//! literal can't start with `-` unless separated from the flag with `=`. For short flags value
+//! can follow immediately: `-fbar`.
+//!
+#![cfg_attr(not(doctest), doc = include_str!("docs2/argument.md"))]
+//!
+//! ## Positional
+//!
+//! A positional argument with no additonal name, for example in `vim main.rs` `main.rs`
+//! is a positional argument. Can't start with `-`, created with [`positional`].
+//!
+#![cfg_attr(not(doctest), doc = include_str!("docs2/positional.md"))]
+//!
+//! ## Any
+//!
+//! Also a positional argument with no additional name, but unlike [`positional`] itself, [`any`]
+//! isn't restricted to positional looking structure and would consume any items as they appear on
+//! a command line. Can be useful to collect anything unused to pass to other applications.
+//!
+#![cfg_attr(not(doctest), doc = include_str!("docs2/any_simple.md"))]
+#![cfg_attr(not(doctest), doc = include_str!("docs2/any_literal.md"))]
+//!
+//! ## Command
+//!
+//! A command defines a starting point for an independent subparser. Name must be a valid utf8
+//! string. For example `cargo build` invokes command `"build"` and after `"build"` `cargo`
+//! starts accepting values it won't accept otherwise
+//!
+#![cfg_attr(not(doctest), doc = include_str!("docs2/command.md"))]
+//!
+use std::{ffi::OsString, marker::PhantomData, str::FromStr};
+
+use crate::{
+    args::{Arg, State},
+    error::{Message, MissingItem},
+    from_os_str::parse_os_str,
+    item::ShortLong,
+    meta_help::Metavar,
+    Doc, Error, Item, Meta, OptionParser, Parser,
+};
+
+#[cfg(doc)]
+use crate::{any, command, env, long, positional, short};
+
+/// A named thing used to create [`flag`](NamedArg::flag), [`switch`](NamedArg::switch) or
+/// [`argument`](NamedArg::argument)
+///
+/// # Combinatoric usage
+///
+/// Named items (`argument`, `flag` and `switch`) can have up to 2 visible names (one short and one long)
+/// and multiple hidden short and long aliases if needed. It's also possible to consume items from
+/// environment variables using [`env`](NamedArg::env()). You usually start with [`short`] or [`long`]
+/// function, then apply [`short`](NamedArg::short) / [`long`](NamedArg::long) / [`env`](NamedArg::env()) /
+/// [`help`](NamedArg::help) repeatedly to build a desired set of names then transform it into
+/// a parser using `flag`, `switch` or `positional`.
+///
+#[cfg_attr(not(doctest), doc = include_str!("docs2/named_arg_combine.md"))]
+///
+/// # Derive usage
+///
+/// When using derive API it is possible to omit some or all the details:
+/// 1. If no naming information is present at all - `bpaf` would use field name as a long name
+///    (or a short name if field name consists of a single character)
+/// 2. If `short` or `long` annotation is present without an argument - `bpaf` would use first character
+///    or a full name as long and short name respectively. It won't try to add implicit long or
+///    short name from the previous item.
+/// 3. If `short` or `long` annotation is present with an argument - those are values `bpaf` would
+///    use instead of the original field name
+/// 4. You can specify many `short` and `long` names, any past the first one of each type will
+///    become hidden aliases
+/// 5. If `env(arg)` annotation is present - in addition to long/short names derived according to
+///    rules 1..3 `bpaf` would also parse environment variable `arg` which can be a string literal
+///    or an expression.
+#[cfg_attr(not(doctest), doc = include_str!("docs2/named_arg_derive.md"))]
+#[derive(Clone, Debug)]
+pub struct NamedArg {
+    pub(crate) short: Vec<char>,
+    pub(crate) long: Vec<&'static str>,
+    pub(crate) env: Vec<&'static str>,
+    pub(crate) help: Option<Doc>,
+}
+
+impl NamedArg {
+    pub(crate) fn flag_item(&self) -> Option<Item> {
+        Some(Item::Flag {
+            name: ShortLong::try_from(self).ok()?,
+            help: self.help.clone(),
+            env: self.env.first().copied(),
+            shorts: self.short.clone(),
+        })
+    }
+}
+
+impl NamedArg {
+    /// Add a short name to a flag/switch/argument
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/short_long_env.md"))]
+    #[must_use]
+    pub fn short(mut self, short: char) -> Self {
+        self.short.push(short);
+        self
+    }
+
+    /// Add a long name to a flag/switch/argument
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/short_long_env.md"))]
+    #[must_use]
+    pub fn long(mut self, long: &'static str) -> Self {
+        self.long.push(long);
+        self
+    }
+
+    /// Environment variable fallback
+    ///
+    /// If named value isn't present - try to fallback to this environment variable.
+    ///
+    /// You can specify it multiple times, `bpaf` would use items past the first one as hidden aliases.
+    ///
+    /// For [`flag`](NamedArg::flag) and [`switch`](NamedArg::switch) environment variable being present
+    /// gives the same result as the flag being present, allowing to implement things like `NO_COLOR`
+    /// variables:
+    ///
+    /// ```console
+    /// $ NO_COLOR=1 app --do-something
+    /// ```
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/short_long_env.md"))]
+    #[must_use]
+    pub fn env(mut self, variable: &'static str) -> Self {
+        self.env.push(variable);
+        self
+    }
+
+    /// Add a help message to a `flag`/`switch`/`argument`
+    ///
+    /// `bpaf` converts doc comments and string into help by following those rules:
+    /// 1. Everything up to the first blank line is included into a "short" help message
+    /// 2. Everything is included into a "long" help message
+    /// 3. `bpaf` preserves linebreaks followed by a line that starts with a space
+    /// 4. Linebreaks are removed otherwise
+    ///
+    /// You can pass anything that can be converted into [`Doc`], if you are not using
+    /// documentation generation functionality ([`doc`](crate::doc)) this can be `&str`.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/switch_help.md"))]
+    #[must_use]
+    pub fn help<M>(mut self, help: M) -> Self
+    where
+        M: Into<Doc>,
+    {
+        self.help = Some(help.into());
+        self
+    }
+
+    /// Simple boolean flag
+    ///
+    /// A special case of a [`flag`](NamedArg::flag) that gets decoded into a `bool`, mostly serves as a convenient
+    /// shortcut to `.flag(true, false)`.
+    ///
+    /// In Derive API bpaf would use `switch` for `bool` fields inside named structs that don't
+    /// have other consumer annotations ([`flag`](NamedArg::flag),
+    /// [`argument`](NamedArg::argument), etc).
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/switch.md"))]
+    #[must_use]
+    pub fn switch(self) -> ParseFlag<bool> {
+        build_flag_parser(true, Some(false), self)
+    }
+
+    /// Flag with custom present/absent values
+    ///
+    /// More generic version of [`switch`](NamedArg::switch) that can use arbitrary type instead of
+    /// [`bool`].
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/flag.md"))]
+    #[must_use]
+    pub fn flag<T>(self, present: T, absent: T) -> ParseFlag<T>
+    where
+        T: Clone + 'static,
+    {
+        build_flag_parser(present, Some(absent), self)
+    }
+
+    /// Required flag with custom value
+    ///
+    /// Similar to [`flag`](NamedArg::flag) takes no option arguments, but would only
+    /// succeed if user specifies its name on a command line.
+    /// Works best in combination with other parsers.
+    ///
+    /// In derive style API `bpaf` would transform field-less enum variants into a parser
+    /// that accepts one of it's variant names as `req_flag`. Additionally `bpaf` handles `()`
+    /// fields as `req_flag`.
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/req_flag.md"))]
+    #[must_use]
+    pub fn req_flag<T>(self, present: T) -> impl Parser<T>
+    where
+        T: Clone + 'static,
+    {
+        build_flag_parser(present, None, self)
+    }
+
+    /// Argument
+    ///
+    /// A short (`-a`) or long (`--name`) name followed by  either a space or `=` and
+    /// then by a string literal.  `-f foo`, `--flag bar` or `-o=-` are all valid argument examples. Note, string
+    /// literal can't start with `-` unless separated from the flag with `=`. For short flags value
+    /// can follow immediately: `-fbar`.
+    ///
+    /// When using combinatoring API you can specify the type with turbofish, for parsing types
+    /// that don't implement [`FromStr`] you can use consume a `String`/`OsString` first and parse
+    /// it by hands.
+    ///
+    /// For `metavar` value you should pick something short and descriptive about the parameter,
+    /// usually in capital letters. For example for an abstract file parameter it could be
+    /// `"FILE"`, for a username - `"USER"`, etc.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/argument.md"))]
+    ///
+    /// You can further restrict it using [`adjacent`](ParseArgument::adjacent)
+    #[must_use]
+    pub fn argument<T>(self, metavar: &'static str) -> ParseArgument<T>
+    where
+        T: FromStr + 'static,
+    {
+        build_argument(self, metavar)
+    }
+
+    /// `adjacent` requires for the argument to be present in the same word as the flag:
+    /// `-f bar` - no, `-fbar` or `-f=bar` - yes.
+    pub(crate) fn matches_arg(&self, arg: &Arg, adjacent: bool) -> bool {
+        match arg {
+            Arg::Short(s, is_adj, _) => self.short.contains(s) && (!adjacent || *is_adj),
+            Arg::Long(l, is_adj, _) => self.long.contains(&l.as_str()) && (!adjacent || *is_adj),
+            Arg::ArgWord(_) | Arg::Word(_) | Arg::PosWord(_) => false,
+        }
+    }
+}
+
+impl<T> OptionParser<T> {
+    /// Parse a subcommand
+    ///
+    /// Subcommands allow to use a totally independent parser inside a current one. Inner parser
+    /// can have its own help message, description, version and so on. You can nest them arbitrarily
+    /// too.
+    ///
+    /// # Important restriction
+    /// When parsing command arguments from command lines you should have parsers for all your
+    /// named values before parsers for commands and positional items. In derive API fields parsed as
+    /// positional should be at the end of your `struct`/`enum`. Same rule applies
+    /// to parsers with positional fields or commands inside: such parsers should go to the end as well.
+    ///
+    /// Use [`check_invariants`](OptionParser::check_invariants) in your test to ensure correctness.
+    ///
+    /// For example for non positional `non_pos` and a command `command` parsers
+    /// ```rust
+    /// # use bpaf::*;
+    /// # let non_pos = || short('n').switch();
+    /// # let command = || pure(()).to_options().command("POS");
+    /// let valid = construct!(non_pos(), command());
+    /// let invalid = construct!(command(), non_pos());
+    /// ```
+    ///
+    /// **`bpaf` panics during help generation unless if this restriction holds**
+    ///
+    /// You can attach a single visible short alias and multiple hiddden short and long aliases
+    /// using [`short`](ParseCommand::short) and [`long`](ParseCommand::long) methods.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/command.md"))]
+    ///
+    /// To represent multiple possible commands it is convenient to use enums
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/command_enum.md"))]
+    #[must_use]
+    pub fn command(self, name: &'static str) -> ParseCommand<T>
+    where
+        T: 'static,
+    {
+        ParseCommand {
+            longs: vec![name],
+            shorts: Vec::new(),
+            help: self.short_descr().map(Into::into),
+            subparser: self,
+            adjacent: false,
+        }
+    }
+}
+
+/// Builder structure for the [`command`]
+///
+/// Created with [`command`], implements parser for the inner structure, gives access to [`help`](ParseCommand::help).
+pub struct ParseCommand<T> {
+    pub(crate) longs: Vec<&'static str>,
+    pub(crate) shorts: Vec<char>,
+    // short help!
+    pub(crate) help: Option<Doc>,
+    pub(crate) subparser: OptionParser<T>,
+    pub(crate) adjacent: bool,
+}
+
+impl<P> ParseCommand<P> {
+    /// Add a brief description to a command
+    ///
+    /// `bpaf` uses this description along with the command name
+    /// in help output so it shouldn't exceed one or two lines. If `help` isn't specified
+    /// `bpaf` falls back to [`descr`](OptionParser::descr) from the inner parser.
+    ///
+    /// # Combinatoric usage
+    ///
+    /// ```rust
+    /// # use bpaf::*;
+    /// fn inner() -> OptionParser<bool> {
+    ///     short('i')
+    ///         .help("Mysterious inner switch")
+    ///         .switch()
+    ///         .to_options()
+    ///         .descr("performs an operation")
+    /// }
+    ///
+    /// fn mysterious_parser() -> impl Parser<bool> {
+    ///     inner().command("mystery")
+    ///         .help("This command performs a mystery operation")
+    /// }
+    /// ```
+    ///
+    /// # Derive usage
+    /// `bpaf_derive` uses doc comments for inner parser, no specific options are available.
+    /// See [`descr`](OptionParser::descr) for more details
+    /// ```rust
+    /// # use bpaf::*;
+    /// /// This command performs a mystery operation
+    /// #[derive(Debug, Clone, Bpaf)]
+    /// #[bpaf(command)]
+    /// struct Mystery {
+    ///     #[bpaf(short)]
+    ///     /// Mysterious inner switch
+    ///     inner: bool,
+    /// }
+    /// ```
+    ///
+    /// # Example
+    /// ```console
+    /// $ app --help
+    ///     <skip>
+    /// Available commands:
+    ///     mystery  This command performs a mystery operation
+    /// ```
+    #[must_use]
+    pub fn help<M>(mut self, help: M) -> Self
+    where
+        M: Into<Doc>,
+    {
+        self.help = Some(help.into());
+        self
+    }
+
+    /// Add a custom short alias for a command
+    ///
+    /// Behavior is similar to [`short`](NamedArg::short), only first short name is visible.
+    #[must_use]
+    pub fn short(mut self, short: char) -> Self {
+        self.shorts.push(short);
+        self
+    }
+
+    /// Add a custom hidden long alias for a command
+    ///
+    /// Behavior is similar to [`long`](NamedArg::long), but since you had to specify the first long
+    /// name when making the command - this one becomes a hidden alias.
+    #[must_use]
+    pub fn long(mut self, long: &'static str) -> Self {
+        self.longs.push(long);
+        self
+    }
+
+    /// Allow for the command to succeed even if there are non consumed items present
+    ///
+    /// Normally a subcommand parser should handle the rest of the unconsumed elements thus
+    /// allowing only "vertical" chaining of commands. `adjacent` modifier lets command parser to
+    /// succeed if there are leftovers for as long as all comsumed items form a single adjacent
+    /// block. This opens possibilities to chain commands sequentially.
+    ///
+    /// Let's consider two examples with consumed items marked in bold :
+    ///
+    /// - <code>**cmd** **-a** -b **-c** -d</code>
+    /// - <code>**cmd** **-a** **-c** -b -d</code>
+    ///
+    /// In the first example `-b` breaks the adjacency for all the consumed items so parsing will fail,
+    /// while here in the second one the name and all the consumed items are adjacent to each other so
+    /// parsing will succeed.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_command.md"))]
+    #[must_use]
+    pub fn adjacent(mut self) -> Self {
+        self.adjacent = true;
+        self
+    }
+}
+
+impl<T> Parser<T> for ParseCommand<T> {
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        // used to avoid allocations for short names
+        let mut tmp = String::new();
+        if self.longs.iter().any(|long| args.take_cmd(long))
+            || self.shorts.iter().any(|s| {
+                tmp.clear();
+                tmp.push(*s);
+                args.take_cmd(&tmp)
+            })
+        {
+            #[cfg(feature = "autocomplete")]
+            if args.touching_last_remove() {
+                // in completion mode prefer to autocomplete the command name vs going inside the
+                // parser
+                args.clear_comps();
+                args.push_command(self.longs[0], self.shorts.first().copied(), &self.help);
+                return Err(Error(Message::Missing(Vec::new())));
+            }
+
+            if let Some(cur) = args.current {
+                args.set_scope(cur..args.scope().end);
+            }
+
+            args.path.push(self.longs[0].to_string());
+            if self.adjacent {
+                let mut orig_args = args.clone();
+
+                // narrow down the scope to adjacently available elements
+                args.set_scope(args.adjacently_available_from(args.scope().start + 1));
+
+                match self
+                    .subparser
+                    .run_subparser(args)
+                    .map_err(Message::ParseFailure)
+                {
+                    Ok(ok) => {
+                        args.set_scope(orig_args.scope());
+                        Ok(ok)
+                    }
+                    Err(err) => {
+                        let orig_scope = args.scope();
+                        if let Some(narrow_scope) = args.adjacent_scope(&orig_args) {
+                            orig_args.set_scope(narrow_scope);
+                            if let Ok(res) = self.subparser.run_subparser(&mut orig_args) {
+                                orig_args.set_scope(orig_scope);
+                                std::mem::swap(&mut orig_args, args);
+                                return Ok(res);
+                            }
+                        }
+                        Err(Error(err))
+                    }
+                }
+            } else {
+                self.subparser
+                    .run_subparser(args)
+                    .map_err(|e| Error(Message::ParseFailure(e)))
+            }
+        } else {
+            #[cfg(feature = "autocomplete")]
+            args.push_command(self.longs[0], self.shorts.first().copied(), &self.help);
+
+            let missing = MissingItem {
+                item: self.item(),
+                position: args.scope().start,
+                scope: args.scope(),
+            };
+            Err(Error(Message::Missing(vec![missing])))
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::from(self.item())
+    }
+}
+
+impl<T> ParseCommand<T> {
+    fn item(&self) -> Item {
+        Item::Command {
+            name: self.longs[0],
+            short: self.shorts.first().copied(),
+            help: self.help.clone(),
+            meta: Box::new(self.subparser.inner.meta()),
+            info: Box::new(self.subparser.info.clone()),
+        }
+    }
+}
+
+fn build_flag_parser<T>(present: T, absent: Option<T>, named: NamedArg) -> ParseFlag<T>
+where
+    T: Clone + 'static,
+{
+    ParseFlag {
+        present,
+        absent,
+        named,
+    }
+}
+
+#[derive(Clone)]
+/// Parser for a named switch, created with [`NamedArg::flag`] or [`NamedArg::switch`]
+pub struct ParseFlag<T> {
+    present: T,
+    absent: Option<T>,
+    named: NamedArg,
+}
+
+impl<T: Clone + 'static> Parser<T> for ParseFlag<T> {
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        if args.take_flag(&self.named) || self.named.env.iter().find_map(std::env::var_os).is_some()
+        {
+            #[cfg(feature = "autocomplete")]
+            if args.touching_last_remove() {
+                args.push_flag(&self.named);
+            }
+            Ok(self.present.clone())
+        } else {
+            #[cfg(feature = "autocomplete")]
+            args.push_flag(&self.named);
+            match &self.absent {
+                Some(ok) => Ok(ok.clone()),
+                None => {
+                    if let Some(item) = self.named.flag_item() {
+                        let missing = MissingItem {
+                            item,
+                            position: args.scope().start,
+                            scope: args.scope(),
+                        };
+                        Err(Error(Message::Missing(vec![missing])))
+                    } else if let Some(name) = self.named.env.first() {
+                        Err(Error(Message::NoEnv(name)))
+                    } else {
+                        todo!("no key!")
+                    }
+                }
+            }
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        if let Some(item) = self.named.flag_item() {
+            item.required(self.absent.is_none())
+        } else {
+            Meta::Skip
+        }
+    }
+}
+
+impl<T> ParseFlag<T> {
+    /// Add a help message to `flag`
+    ///
+    /// See [`NamedArg::help`]
+    #[must_use]
+    pub fn help<M>(mut self, help: M) -> Self
+    where
+        M: Into<Doc>,
+    {
+        self.named.help = Some(help.into());
+        self
+    }
+}
+
+impl<T> ParseArgument<T> {
+    /// Add a help message to an `argument`
+    ///
+    /// See [`NamedArg::help`]
+    #[must_use]
+    pub fn help<M>(mut self, help: M) -> Self
+    where
+        M: Into<Doc>,
+    {
+        self.named.help = Some(help.into());
+        self
+    }
+}
+
+fn build_argument<T>(named: NamedArg, metavar: &'static str) -> ParseArgument<T> {
+    ParseArgument {
+        named,
+        metavar,
+        ty: PhantomData,
+        adjacent: false,
+    }
+}
+
+/// Parser for a named argument, created with [`argument`](NamedArg::argument).
+#[derive(Clone)]
+pub struct ParseArgument<T> {
+    ty: PhantomData<T>,
+    named: NamedArg,
+    metavar: &'static str,
+    adjacent: bool,
+}
+
+impl<T> ParseArgument<T> {
+    /// Restrict parsed arguments to have both flag and a value in the same word:
+    ///
+    /// In other words adjacent restricted `ParseArgument` would accept `--flag=value` or
+    /// `-fbar` but not `--flag value`. Note, this is different from [`adjacent`](crate::ParseCon::adjacent),
+    /// just plays a similar role.
+    ///
+    /// Should allow to parse some of the more unusual things
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_argument.md"))]
+    #[must_use]
+    pub fn adjacent(mut self) -> Self {
+        self.adjacent = true;
+        self
+    }
+
+    fn item(&self) -> Option<Item> {
+        Some(Item::Argument {
+            name: ShortLong::try_from(&self.named).ok()?,
+            metavar: Metavar(self.metavar),
+            env: self.named.env.first().copied(),
+            help: self.named.help.clone(),
+            shorts: self.named.short.clone(),
+        })
+    }
+
+    fn take_argument(&self, args: &mut State) -> Result<OsString, Error> {
+        match args.take_arg(&self.named, self.adjacent, Metavar(self.metavar)) {
+            Ok(Some(w)) => {
+                #[cfg(feature = "autocomplete")]
+                if args.touching_last_remove() {
+                    args.push_metavar(self.metavar, &self.named.help, true);
+                }
+                Ok(w)
+            }
+            Err(err) => {
+                #[cfg(feature = "autocomplete")]
+                args.push_argument(&self.named, self.metavar);
+                Err(err)
+            }
+            _ => {
+                #[cfg(feature = "autocomplete")]
+                args.push_argument(&self.named, self.metavar);
+                if let Some(val) = self.named.env.iter().find_map(std::env::var_os) {
+                    args.current = None;
+                    return Ok(val);
+                }
+
+                if let Some(item) = self.item() {
+                    let missing = MissingItem {
+                        item,
+                        position: args.scope().start,
+                        scope: args.scope(),
+                    };
+                    Err(Error(Message::Missing(vec![missing])))
+                } else if let Some(name) = self.named.env.first() {
+                    Err(Error(Message::NoEnv(name)))
+                } else {
+                    unreachable!()
+                }
+            }
+        }
+    }
+}
+
+impl<T> Parser<T> for ParseArgument<T>
+where
+    T: FromStr + 'static,
+    <T as std::str::FromStr>::Err: std::fmt::Display,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        let os = self.take_argument(args)?;
+        match parse_os_str::<T>(os) {
+            Ok(ok) => Ok(ok),
+            Err(err) => Err(Error(Message::ParseFailed(args.current, err))),
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        if let Some(item) = self.item() {
+            Meta::from(item)
+        } else {
+            Meta::Skip
+        }
+    }
+}
+
+pub(crate) fn build_positional<T>(metavar: &'static str) -> ParsePositional<T> {
+    ParsePositional {
+        metavar,
+        help: None,
+        result_type: PhantomData,
+        strict: false,
+    }
+}
+
+/// Parse a positional item, created with [`positional`]
+///
+/// You can add extra information to positional parsers with [`help`](Self::help)
+/// and [`strict`](Self::strict) on this struct.
+#[derive(Clone)]
+pub struct ParsePositional<T> {
+    metavar: &'static str,
+    help: Option<Doc>,
+    result_type: PhantomData<T>,
+    strict: bool,
+}
+
+impl<T> ParsePositional<T> {
+    /// Add a help message to a [`positional`] parser
+    ///
+    /// `bpaf` converts doc comments and string into help by following those rules:
+    /// 1. Everything up to the first blank line is included into a "short" help message
+    /// 2. Everything is included into a "long" help message
+    /// 3. `bpaf` preserves linebreaks followed by a line that starts with a space
+    /// 4. Linebreaks are removed otherwise
+    ///
+    /// You can pass anything that can be converted into [`Doc`], if you are not using
+    /// documentation generation functionality ([`doc`](crate::doc)) this can be `&str`.
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/positional.md"))]
+    #[must_use]
+    pub fn help<M>(mut self, help: M) -> Self
+    where
+        M: Into<Doc>,
+    {
+        self.help = Some(help.into());
+        self
+    }
+
+    /// Changes positional parser to be a "strict" positional
+    ///
+    /// Usually positional items can appear anywhere on a command line:
+    /// ```console
+    /// $ ls -d bpaf
+    /// $ ls bpaf -d
+    /// ```
+    /// here `ls` takes a positional item `bpaf` and a flag `-d`
+    ///
+    /// But in some cases it might be useful to have a stricter separation between
+    /// positonal items and flags, such as passing arguments to a subprocess:
+    /// ```console
+    /// $ cargo run --example basic -- --help
+    /// ```
+    ///
+    /// here `cargo` takes a `--help` as a positional item and passes it to the example
+    ///
+    /// `bpaf` allows to require user to pass `--` for positional items with `strict` annotation.
+    /// `bpaf` would display such positional elements differently in usage line as well.
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/positional_strict.md"))]
+    #[must_use]
+    pub fn strict(mut self) -> Self {
+        self.strict = true;
+        self
+    }
+
+    fn meta(&self) -> Meta {
+        let meta = Meta::from(Item::Positional {
+            metavar: Metavar(self.metavar),
+            help: self.help.clone(),
+        });
+        if self.strict {
+            Meta::Strict(Box::new(meta))
+        } else {
+            meta
+        }
+    }
+}
+
+fn parse_pos_word(
+    args: &mut State,
+    strict: bool,
+    metavar: &'static str,
+    help: &Option<Doc>,
+) -> Result<OsString, Error> {
+    let metavar = Metavar(metavar);
+    match args.take_positional_word(metavar) {
+        Ok((ix, is_strict, word)) => {
+            if strict && !is_strict {
+                #[cfg(feature = "autocomplete")]
+                args.push_pos_sep();
+
+                return Err(Error(Message::StrictPos(ix, metavar)));
+            }
+            #[cfg(feature = "autocomplete")]
+            if args.touching_last_remove() && !args.check_no_pos_ahead() {
+                args.push_metavar(metavar.0, help, false);
+                args.set_no_pos_ahead();
+            }
+            Ok(word)
+        }
+        Err(err) => {
+            #[cfg(feature = "autocomplete")]
+            if !args.check_no_pos_ahead() {
+                args.push_metavar(metavar.0, help, false);
+                args.set_no_pos_ahead();
+            }
+            Err(err)
+        }
+    }
+}
+
+impl<T> Parser<T> for ParsePositional<T>
+where
+    T: FromStr + 'static,
+    <T as std::str::FromStr>::Err: std::fmt::Display,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        let os = parse_pos_word(args, self.strict, self.metavar, &self.help)?;
+        match parse_os_str::<T>(os) {
+            Ok(ok) => Ok(ok),
+            Err(err) => Err(Error(Message::ParseFailed(args.current, err))),
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        self.meta()
+    }
+}
+
+/// Consume an arbitrary value that satisfies a condition, created with [`any`], implements
+/// [`anywhere`](ParseAny::anywhere).
+pub struct ParseAny<T> {
+    pub(crate) metavar: Doc,
+    pub(crate) help: Option<Doc>,
+    pub(crate) check: Box<dyn Fn(OsString) -> Option<T>>,
+    pub(crate) anywhere: bool,
+}
+
+impl<T> ParseAny<T> {
+    pub(crate) fn item(&self) -> Item {
+        Item::Any {
+            metavar: self.metavar.clone(),
+            help: self.help.clone(),
+            anywhere: self.anywhere,
+        }
+    }
+
+    /// Add a help message to [`any`] parser.
+    /// See examples in [`any`]
+    #[must_use]
+    pub fn help<M: Into<Doc>>(mut self, help: M) -> Self {
+        self.help = Some(help.into());
+        self
+    }
+
+    /// Replace metavar with a custom value
+    /// See examples in [`any`]
+    #[must_use]
+    pub fn metavar<M: Into<Doc>>(mut self, metavar: M) -> Self {
+        self.metavar = metavar.into();
+        self
+    }
+
+    /// Try to apply the parser to each unconsumed element instead of just the front one
+    ///
+    /// By default `any` tries to parse just the front unconsumed item behaving similar to
+    /// [`positional`] parser, `anywhere` changes it so it applies to every unconsumed item,
+    /// similar to argument parser.
+    ///
+    /// See examples in [`any`]
+    #[must_use]
+    pub fn anywhere(mut self) -> Self {
+        self.anywhere = true;
+        self
+    }
+}
+
+impl<T> Parser<T> for ParseAny<T> {
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        for (ix, x) in args.items_iter() {
+            let (os, next) = match x {
+                Arg::Short(_, next, os) | Arg::Long(_, next, os) => (os, *next),
+                Arg::ArgWord(os) | Arg::Word(os) | Arg::PosWord(os) => (os, false),
+            };
+            if let Some(i) = (self.check)(os.clone()) {
+                args.remove(ix);
+                if next {
+                    args.remove(ix + 1);
+                }
+
+                return Ok(i);
+            }
+            if !self.anywhere {
+                break;
+            }
+        }
+        let missing_item = MissingItem {
+            item: self.item(),
+            position: args.scope().start,
+            scope: args.scope(),
+        };
+        Err(Error(Message::Missing(vec![missing_item])))
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::Item(Box::new(self.item()))
+    }
+}
+
\ No newline at end of file diff --git a/src/bpaf/structs.rs.html b/src/bpaf/structs.rs.html new file mode 100644 index 00000000..ebea8ef9 --- /dev/null +++ b/src/bpaf/structs.rs.html @@ -0,0 +1,2311 @@ +structs.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+
//! Structures that implement different methods on [`Parser`] trait
+use crate::{
+    args::State,
+    buffer::MetaInfo,
+    error::{Message, MissingItem},
+    Doc, Error, Meta, Parser,
+};
+use std::marker::PhantomData;
+
+/// Parser that substitutes missing value with a function results but not parser
+/// failure, created with [`fallback_with`](Parser::fallback_with).
+pub struct ParseFallbackWith<T, P, F, E> {
+    pub(crate) inner: P,
+    pub(crate) inner_res: PhantomData<T>,
+    pub(crate) fallback: F,
+    pub(crate) value_str: String,
+    pub(crate) err: PhantomData<E>,
+}
+
+impl<T, P, F, E> Parser<T> for ParseFallbackWith<T, P, F, E>
+where
+    P: Parser<T>,
+    F: Fn() -> Result<T, E>,
+    E: ToString,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        let mut clone = args.clone();
+        match self.inner.eval(&mut clone) {
+            Ok(ok) => {
+                std::mem::swap(args, &mut clone);
+                Ok(ok)
+            }
+            Err(Error(e)) => {
+                #[cfg(feature = "autocomplete")]
+                args.swap_comps(&mut clone);
+                if e.can_catch() {
+                    match (self.fallback)() {
+                        Ok(ok) => Ok(ok),
+                        Err(e) => Err(Error(Message::PureFailed(e.to_string()))),
+                    }
+                } else {
+                    Err(Error(e))
+                }
+            }
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        let m = Meta::Optional(Box::new(self.inner.meta()));
+        if self.value_str.is_empty() {
+            m
+        } else {
+            let buf = Doc::from(self.value_str.as_str());
+            Meta::Suffix(Box::new(m), Box::new(buf))
+        }
+    }
+}
+
+/// Parser with attached message to several fields, created with [`group_help`](Parser::group_help).
+pub struct ParseGroupHelp<P> {
+    pub(crate) inner: P,
+    pub(crate) message: Doc,
+}
+
+impl<T, P> Parser<T> for ParseGroupHelp<P>
+where
+    P: Parser<T>,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        #[cfg(feature = "autocomplete")]
+        let mut comp_items = Vec::new();
+        #[cfg(feature = "autocomplete")]
+        args.swap_comps_with(&mut comp_items);
+
+        #[allow(clippy::let_and_return)]
+        let res = self.inner.eval(args);
+
+        #[cfg(feature = "autocomplete")]
+        args.swap_comps_with(&mut comp_items);
+        #[cfg(feature = "autocomplete")]
+        args.push_with_group(&self.message.to_completion(), &mut comp_items);
+
+        res
+    }
+
+    fn meta(&self) -> Meta {
+        let meta = Box::new(self.inner.meta());
+        Meta::Subsection(meta, Box::new(self.message.clone()))
+    }
+}
+
+/// Parser with attached message to several fields, created with [`group_help`](Parser::group_help).
+pub struct ParseWithGroupHelp<P, F> {
+    pub(crate) inner: P,
+    pub(crate) f: F,
+}
+
+impl<T, P, F> Parser<T> for ParseWithGroupHelp<P, F>
+where
+    P: Parser<T>,
+    F: Fn(MetaInfo) -> Doc,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        self.inner.eval(args)
+    }
+
+    fn meta(&self) -> Meta {
+        let meta = self.inner.meta();
+        let buf = (self.f)(MetaInfo(&meta));
+
+        Meta::Subsection(Box::new(meta), Box::new(buf))
+    }
+}
+
+/// Apply inner parser several times and collect results into `Vec`, created with
+/// [`some`](Parser::some), requires for at least one item to be available to succeed.
+/// Implements [`catch`](ParseMany::catch)
+pub struct ParseSome<P> {
+    pub(crate) inner: P,
+    pub(crate) message: &'static str,
+    pub(crate) catch: bool,
+}
+
+impl<P> ParseSome<P> {
+    #[must_use]
+    /// Handle parse failures
+    ///
+    /// Can be useful to decide to skip parsing of some items on a command line
+    /// When parser succeeds - `catch` version would return a value as usual
+    /// if it fails - `catch` would restore all the consumed values and return None.
+    ///
+    /// There's several structures that implement this attribute: [`ParseOptional`], [`ParseMany`]
+    /// and [`ParseSome`], behavior should be identical for all of them.
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/some_catch.md"))]
+    pub fn catch(mut self) -> Self {
+        self.catch = true;
+        self
+    }
+}
+
+impl<T, P> Parser<Vec<T>> for ParseSome<P>
+where
+    P: Parser<T>,
+{
+    fn eval(&self, args: &mut State) -> Result<Vec<T>, Error> {
+        let mut res = Vec::new();
+        let mut len = usize::MAX;
+
+        while let Some(val) = parse_option(&self.inner, &mut len, args, self.catch)? {
+            res.push(val);
+        }
+
+        if res.is_empty() {
+            Err(Error(Message::ParseSome(self.message)))
+        } else {
+            Ok(res)
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::Many(Box::new(Meta::Required(Box::new(self.inner.meta()))))
+    }
+}
+
+/// Apply inner parser several times and collect results into `FromIterator`, created with
+/// [`collect`](Parser::collect),
+/// Implements [`catch`](ParseCollect::catch)
+pub struct ParseCollect<P, C, T> {
+    pub(crate) inner: P,
+    pub(crate) catch: bool,
+    pub(crate) ctx: PhantomData<(C, T)>,
+}
+
+impl<T, C, P> ParseCollect<P, C, T> {
+    #[must_use]
+    /// Handle parse failures
+    ///
+    /// Can be useful to decide to skip parsing of some items on a command line
+    /// When parser succeeds - `catch` version would return a value as usual
+    /// if it fails - `catch` would restore all the consumed values and return None.
+    ///
+    /// There's several structures that implement this attribute: [`ParseOptional`], [`ParseMany`]
+    /// and [`ParseSome`], behavior should be identical for all of them.
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/some_catch.md"))]
+    pub fn catch(mut self) -> Self {
+        self.catch = true;
+        self
+    }
+}
+
+impl<T, C, P> Parser<C> for ParseCollect<P, C, T>
+where
+    P: Parser<T>,
+    C: FromIterator<T>,
+{
+    fn eval(&self, args: &mut State) -> Result<C, Error> {
+        let mut len = usize::MAX;
+        std::iter::from_fn(|| parse_option(&self.inner, &mut len, args, self.catch).transpose())
+            .collect::<Result<C, Error>>()
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::Many(Box::new(Meta::Required(Box::new(self.inner.meta()))))
+    }
+}
+
+/// Parser that returns results as usual but not shown in `--help` output, created with
+/// [`Parser::hide`]
+pub struct ParseHide<P> {
+    pub(crate) inner: P,
+}
+
+impl<T, P> Parser<T> for ParseHide<P>
+where
+    P: Parser<T>,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        #[cfg(feature = "autocomplete")]
+        let mut comps = Vec::new();
+
+        #[cfg(feature = "autocomplete")]
+        args.swap_comps_with(&mut comps);
+
+        #[allow(clippy::let_and_return)]
+        let res = self.inner.eval(args);
+
+        #[cfg(feature = "autocomplete")]
+        args.swap_comps_with(&mut comps);
+        if let Err(Error(Message::Missing(_))) = res {
+            Err(Error(Message::Missing(Vec::new())))
+        } else {
+            res
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::Skip
+    }
+}
+
+/// Parser that hides inner parser from usage line
+///
+/// No other changes to the inner parser
+pub struct ParseUsage<P> {
+    pub(crate) inner: P,
+    pub(crate) usage: Doc,
+}
+impl<T, P> Parser<T> for ParseUsage<P>
+where
+    P: Parser<T>,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        self.inner.eval(args)
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::CustomUsage(Box::new(self.inner.meta()), Box::new(self.usage.clone()))
+    }
+}
+
+/// Parser that tries to either of two parsers and uses one that succeeeds, created with
+/// [`Parser::or_else`].
+pub struct ParseOrElse<T> {
+    pub(crate) this: Box<dyn Parser<T>>,
+    pub(crate) that: Box<dyn Parser<T>>,
+}
+
+impl<T> Parser<T> for ParseOrElse<T> {
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        #[cfg(feature = "autocomplete")]
+        let mut comp_items = Vec::new();
+        #[cfg(feature = "autocomplete")]
+        args.swap_comps_with(&mut comp_items);
+
+        // create forks for both branches
+        // if they both fail - fallback to the original arguments
+        // if they both succed - pick the one that consumes left, remember the second one
+        // if one succeeds - pick that, forget the remaining one unless we are doing completion
+        let mut args_a = args.clone();
+        let mut args_b = args.clone();
+
+        // run both parsers, expand Result<T, Error> into Option<T> + Option<Error>
+        // so that code that does a bunch of comparing logic can be shared across
+        // all invocations of parsers rather than being inlined into each one.
+
+        let (res_a, err_a) = match self.this.eval(&mut args_a) {
+            Ok(ok) => (Some(ok), None),
+            Err(err) => (None, Some(err)),
+        };
+
+        let (res_b, err_b) = match self.that.eval(&mut args_b) {
+            Ok(ok) => (Some(ok), None),
+            Err(err) => (None, Some(err)),
+        };
+
+        if this_or_that_picks_first(
+            err_a,
+            err_b,
+            args,
+            &mut args_a,
+            &mut args_b,
+            #[cfg(feature = "autocomplete")]
+            comp_items,
+        )? {
+            Ok(res_a.unwrap())
+        } else {
+            Ok(res_b.unwrap())
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        self.this.meta().or(self.that.meta())
+    }
+}
+
+/// Given two possible errors along with to sets of arguments produce a new error or an instruction
+/// to pick between two answers. Updates arguments state to match the results
+fn this_or_that_picks_first(
+    err_a: Option<Error>,
+    err_b: Option<Error>,
+    args: &mut State,
+    args_a: &mut State,
+    args_b: &mut State,
+
+    #[cfg(feature = "autocomplete")] mut comp_stash: Vec<crate::complete_gen::Comp>,
+) -> Result<bool, Error> {
+    // if higher depth parser succeeds - it takes a priority
+    // completion from different depths should never mix either
+    match Ord::cmp(&args_a.depth(), &args_b.depth()) {
+        std::cmp::Ordering::Less => {
+            std::mem::swap(args, args_b);
+            #[cfg(feature = "autocomplete")]
+            if let Some(comp) = args.comp_mut() {
+                comp.extend_comps(comp_stash);
+            }
+            return match err_b {
+                Some(err) => Err(err),
+                None => Ok(false),
+            };
+        }
+        std::cmp::Ordering::Equal => {}
+        std::cmp::Ordering::Greater => {
+            std::mem::swap(args, args_a);
+            #[cfg(feature = "autocomplete")]
+            if let Some(comp) = args.comp_mut() {
+                comp.extend_comps(comp_stash);
+            }
+            return match err_a {
+                Some(err) => Err(err),
+                None => Ok(true),
+            };
+        }
+    }
+
+    // otherwise pick based on the left most or successful one
+    #[allow(clippy::let_and_return)] // <- it is without autocomplete only
+    let res = match (err_a, err_b) {
+        (None, None) => {
+            if args.len() == args_a.len() && args.len() == args_b.len() {
+                Ok((true, None))
+            } else {
+                Ok(args_a.pick_winner(args_b))
+            }
+        }
+        (Some(e1), Some(e2)) => Err(e1.combine_with(e2)),
+        // otherwise either a or b are success, true means a is success
+        (a_ok, _) => Ok((a_ok.is_none(), None)),
+    };
+
+    #[cfg(feature = "autocomplete")]
+    let len_a = args_a.len();
+
+    #[cfg(feature = "autocomplete")]
+    let len_b = args_b.len();
+
+    #[cfg(feature = "autocomplete")]
+    if let (Some(a), Some(b)) = (args_a.comp_mut(), args_b.comp_mut()) {
+        // if both parsers managed to consume the same amount - including 0, keep
+        // results from both, otherwise keep results from one that consumed more
+        let (keep_a, keep_b) = match res {
+            Ok((true, _)) => (true, false),
+            Ok((false, _)) => (false, true),
+            Err(_) => match len_a.cmp(&len_b) {
+                std::cmp::Ordering::Less => (true, false),
+                std::cmp::Ordering::Equal => (true, true),
+                std::cmp::Ordering::Greater => (false, true),
+            },
+        };
+        if keep_a {
+            comp_stash.extend(a.drain_comps());
+        }
+        if keep_b {
+            comp_stash.extend(b.drain_comps());
+        }
+    }
+
+    match res {
+        Ok((true, ix)) => {
+            if let Some(win) = ix {
+                args_a.save_conflicts(args_b, win);
+            }
+            std::mem::swap(args, args_a);
+        }
+        Ok((false, ix)) => {
+            if let Some(win) = ix {
+                args_b.save_conflicts(args_a, win);
+            }
+            std::mem::swap(args, args_b);
+        }
+        // no winner, keep the completions but don't touch args otherwise
+        Err(_) => {}
+    }
+
+    #[cfg(feature = "autocomplete")]
+    if let Some(comp) = args.comp_mut() {
+        comp.extend_comps(comp_stash);
+    }
+
+    Ok(res?.0)
+}
+
+/// Parser that transforms parsed value with a failing function, created with
+/// [`parse`](Parser::parse)
+pub struct ParseWith<T, P, F, E, R> {
+    pub(crate) inner: P,
+    pub(crate) inner_res: PhantomData<T>,
+    pub(crate) parse_fn: F,
+    pub(crate) res: PhantomData<R>,
+    pub(crate) err: PhantomData<E>,
+}
+
+impl<T, P, F, E, R> Parser<R> for ParseWith<T, P, F, E, R>
+where
+    P: Parser<T>,
+    F: Fn(T) -> Result<R, E>,
+    E: ToString,
+{
+    fn eval(&self, args: &mut State) -> Result<R, Error> {
+        let t = self.inner.eval(args)?;
+        match (self.parse_fn)(t) {
+            Ok(r) => Ok(r),
+            Err(e) => Err(Error(Message::ParseFailed(args.current, e.to_string()))),
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        self.inner.meta()
+    }
+}
+
+/// Parser that substitutes missing value but not parse failure, created with
+/// [`fallback`](Parser::fallback).
+pub struct ParseFallback<P, T> {
+    pub(crate) inner: P,
+    pub(crate) value: T,
+    pub(crate) value_str: String,
+}
+
+impl<P, T> Parser<T> for ParseFallback<P, T>
+where
+    P: Parser<T>,
+    T: Clone,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        let mut clone = args.clone();
+        match self.inner.eval(&mut clone) {
+            Ok(ok) => {
+                std::mem::swap(args, &mut clone);
+                Ok(ok)
+            }
+            Err(Error(e)) => {
+                #[cfg(feature = "autocomplete")]
+                args.swap_comps(&mut clone);
+                if e.can_catch() {
+                    Ok(self.value.clone())
+                } else {
+                    Err(Error(e))
+                }
+            }
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        let m = Meta::Optional(Box::new(self.inner.meta()));
+        if self.value_str.is_empty() {
+            m
+        } else {
+            let buf = Doc::from(self.value_str.as_str());
+            Meta::Suffix(Box::new(m), Box::new(buf))
+        }
+    }
+}
+
+impl<P, T: std::fmt::Display> ParseFallback<P, T> {
+    /// Show [`fallback`](Parser::fallback) value in `--help` using [`Display`](std::fmt::Display)
+    /// representation
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/dis_fallback.md"))]
+    #[must_use]
+    pub fn display_fallback(mut self) -> Self {
+        self.value_str = format!("[default: {}]", self.value);
+        self
+    }
+}
+
+impl<P, T: std::fmt::Debug> ParseFallback<P, T> {
+    /// Show [`fallback`](Parser::fallback) value in `--help` using [`Debug`](std::fmt::Debug)
+    /// representation
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/deb_fallback_with.md"))]
+    #[must_use]
+    pub fn debug_fallback(mut self) -> Self {
+        self.value_str = format!("[default: {:?}]", self.value);
+        self
+    }
+}
+
+impl<P, T: std::fmt::Display, F, E> ParseFallbackWith<T, P, F, E>
+where
+    F: Fn() -> Result<T, E>,
+{
+    /// Show [`fallback_with`](Parser::fallback_with) value in `--help` using [`Display`](std::fmt::Display)
+    /// representation
+    ///
+    /// If fallback function fails - no value will show up
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/dis_fallback_with.md"))]
+    #[must_use]
+    pub fn display_fallback(mut self) -> Self {
+        if let Ok(val) = (self.fallback)() {
+            self.value_str = format!("[default: {}]", val);
+        }
+        self
+    }
+}
+
+impl<P, T: std::fmt::Debug, F, E> ParseFallbackWith<T, P, F, E>
+where
+    F: Fn() -> Result<T, E>,
+{
+    /// Show [`fallback_with`](Parser::fallback_with) value in `--help` using [`Debug`](std::fmt::Debug)
+    /// representation
+    ///
+    /// If fallback function fails - no value will show up
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/deb_fallback.md"))]
+    #[must_use]
+    pub fn debug_fallback(mut self) -> Self {
+        if let Ok(val) = (self.fallback)() {
+            self.value_str = format!("[default: {:?}]", val);
+        }
+        self
+    }
+}
+
+/// Parser fails with a message if check returns false, created with [`guard`](Parser::guard).
+pub struct ParseGuard<P, F> {
+    pub(crate) inner: P,
+    pub(crate) check: F,
+    pub(crate) message: &'static str,
+}
+
+impl<T, P, F> Parser<T> for ParseGuard<P, F>
+where
+    P: Parser<T>,
+    F: Fn(&T) -> bool,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        let t = self.inner.eval(args)?;
+        if (self.check)(&t) {
+            Ok(t)
+        } else {
+            Err(Error(Message::GuardFailed(args.current, self.message)))
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        self.inner.meta()
+    }
+}
+
+/// Apply inner parser as many times as it succeeds while consuming something and return this
+/// number
+pub struct ParseCount<P, T> {
+    pub(crate) inner: P,
+    pub(crate) ctx: PhantomData<T>,
+}
+
+impl<T, P> Parser<usize> for ParseCount<P, T>
+where
+    P: Parser<T>,
+{
+    fn eval(&self, args: &mut State) -> Result<usize, Error> {
+        let mut res = 0;
+        let mut current = args.len();
+        let mut len = usize::MAX;
+        while (parse_option(&self.inner, &mut len, args, false)?).is_some() {
+            res += 1;
+            if current == args.len() {
+                break;
+            }
+            current = args.len();
+        }
+        Ok(res)
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::Many(Box::new(Meta::Optional(Box::new(self.inner.meta()))))
+    }
+}
+
+/// Apply inner parser as many times as it succeeds while consuming something and return this
+/// number
+pub struct ParseLast<P> {
+    pub(crate) inner: P,
+}
+
+impl<T, P> Parser<T> for ParseLast<P>
+where
+    P: Parser<T>,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        let mut last = None;
+        let mut current = args.len();
+        let mut len = usize::MAX;
+        while let Some(val) = parse_option(&self.inner, &mut len, args, false)? {
+            last = Some(val);
+            if current == args.len() {
+                break;
+            }
+            current = args.len();
+        }
+        if let Some(last) = last {
+            Ok(last)
+        } else {
+            self.inner.eval(args)
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::Many(Box::new(Meta::Required(Box::new(self.inner.meta()))))
+    }
+}
+
+/// Apply inner parser, return a value in `Some` if items requested by it are all present, restore
+/// and return `None` if any are missing. Created with [`optional`](Parser::optional). Implements
+/// [`catch`](ParseOptional::catch)
+pub struct ParseOptional<P> {
+    pub(crate) inner: P,
+    pub(crate) catch: bool,
+}
+
+impl<T, P> Parser<Option<T>> for ParseOptional<P>
+where
+    P: Parser<T>,
+{
+    fn eval(&self, args: &mut State) -> Result<Option<T>, Error> {
+        let mut len = usize::MAX;
+        parse_option(&self.inner, &mut len, args, self.catch)
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::Optional(Box::new(self.inner.meta()))
+    }
+}
+
+impl<P> ParseOptional<P> {
+    #[must_use]
+    /// Handle parse failures for optional parsers
+    ///
+    /// Can be useful to decide to skip parsing of some items on a command line.
+    /// When parser succeeds - `catch` version would return a value as usual
+    /// if it fails - `catch` would restore all the consumed values and return None.
+    ///
+    /// There's several structures that implement this attribute: [`ParseOptional`], [`ParseMany`]
+    /// and [`ParseSome`], behavior should be identical for all of them.
+    ///
+    /// Those examples are very artificial and designed to show what difference `catch` makes, to
+    /// actually parse arguments like in examples you should [`parse`](Parser::parse) or construct
+    /// enum with alternative branches
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/optional_catch.md"))]
+    pub fn catch(mut self) -> Self {
+        self.catch = true;
+        self
+    }
+}
+
+/// Apply inner parser several times and collect results into `Vec`, created with
+/// [`many`](Parser::many), implements [`catch`](ParseMany::catch).
+pub struct ParseMany<P> {
+    pub(crate) inner: P,
+    pub(crate) catch: bool,
+}
+
+impl<P> ParseMany<P> {
+    #[must_use]
+    /// Handle parse failures
+    ///
+    /// Can be useful to decide to skip parsing of some items on a command line
+    /// When parser succeeds - `catch` version would return a value as usual
+    /// if it fails - `catch` would restore all the consumed values and return None.
+    ///
+    /// There's several structures that implement this attribute: [`ParseOptional`], [`ParseMany`]
+    /// and [`ParseSome`], behavior should be identical for all of them.
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/many_catch.md"))]
+    pub fn catch(mut self) -> Self {
+        self.catch = true;
+        self
+    }
+}
+
+/// try to parse
+fn parse_option<P, T>(
+    parser: &P,
+    len: &mut usize,
+    args: &mut State,
+    catch: bool,
+) -> Result<Option<T>, Error>
+where
+    P: Parser<T>,
+{
+    let mut orig_args = args.clone();
+    match parser.eval(args) {
+        // we keep including values for as long as we consume values from the argument
+        // list or at least one value
+        Ok(val) => Ok(if args.len() < *len {
+            *len = args.len();
+            Some(val)
+        } else {
+            None
+        }),
+        Err(Error(err)) => {
+            // this is safe to return Ok(None) in following scenarios
+            // when inner parser never consumed anything and
+            // 1. produced Error::Missing
+            // 2. produced Error::Message(_, true)
+            // 3. produced Error::Message and catch is enabled
+            //
+            // In all other scenarios we should return the original error
+            //
+            // When parser returns Ok(None) we should return the original arguments so if there's
+            // anything left unconsumed - this won't be lost.
+
+            let missing = matches!(err, Message::Missing(_));
+
+            if catch || (missing && orig_args.len() == args.len()) || (!missing && err.can_catch())
+            {
+                std::mem::swap(&mut orig_args, args);
+                #[cfg(feature = "autocomplete")]
+                if orig_args.comp_mut().is_some() {
+                    args.swap_comps(&mut orig_args);
+                }
+                Ok(None)
+            } else {
+                Err(Error(err))
+            }
+        }
+    }
+}
+
+impl<T, P> Parser<Vec<T>> for ParseMany<P>
+where
+    P: Parser<T>,
+{
+    fn eval(&self, args: &mut State) -> Result<Vec<T>, Error> {
+        let mut len = usize::MAX;
+        std::iter::from_fn(|| parse_option(&self.inner, &mut len, args, self.catch).transpose())
+            .collect::<Result<Vec<T>, Error>>()
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::Many(Box::new(Meta::Optional(Box::new(self.inner.meta()))))
+    }
+}
+
+/// Parser that returns a given value without consuming anything, created with
+/// [`pure`](crate::pure).
+pub struct ParsePure<T>(pub(crate) T);
+impl<T: Clone + 'static> Parser<T> for ParsePure<T> {
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        args.current = None;
+        Ok(self.0.clone())
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::Skip
+    }
+}
+
+pub struct ParsePureWith<T, F, E>(pub(crate) F)
+where
+    F: Fn() -> Result<T, E>,
+    E: ToString;
+impl<T: Clone + 'static, F: Fn() -> Result<T, E>, E: ToString> Parser<T>
+    for ParsePureWith<T, F, E>
+{
+    fn eval(&self, _args: &mut State) -> Result<T, Error> {
+        match (self.0)() {
+            Ok(ok) => Ok(ok),
+            Err(e) => Err(Error(Message::PureFailed(e.to_string()))),
+        }
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::Skip
+    }
+}
+
+/// Parser that fails without consuming any input, created with [`fail`](crate::fail).
+pub struct ParseFail<T> {
+    pub(crate) field1: &'static str,
+    pub(crate) field2: PhantomData<T>,
+}
+impl<T> Parser<T> for ParseFail<T> {
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        args.current = None;
+        Err(Error(Message::ParseFail(self.field1)))
+    }
+
+    fn meta(&self) -> Meta {
+        Meta::Skip
+    }
+}
+
+/// Parser that transforms parsed value with a function, created with [`map`](Parser::map).
+pub struct ParseMap<T, P, F, R> {
+    pub(crate) inner: P,
+    pub(crate) inner_res: PhantomData<T>,
+    pub(crate) map_fn: F,
+    pub(crate) res: PhantomData<R>,
+}
+impl<P, T, F, R> Parser<R> for ParseMap<T, P, F, R>
+where
+    F: Fn(T) -> R,
+    P: Parser<T> + Sized,
+{
+    fn eval(&self, args: &mut State) -> Result<R, Error> {
+        let t = self.inner.eval(args)?;
+        Ok((self.map_fn)(t))
+    }
+
+    fn meta(&self) -> Meta {
+        self.inner.meta()
+    }
+}
+
+/// Create parser from a function, [`construct!`](crate::construct!) uses it internally
+pub struct ParseCon<P> {
+    /// inner parser closure
+    pub inner: P,
+    /// metas for inner parsers
+    pub meta: Meta,
+    /// To produce a better error messages while parsing constructed values
+    /// we want to look at all the items so values that can be consumed are consumed
+    /// autocomplete relies on the same logic
+    ///
+    /// However when dealing with adjacent restriction detecting the first item relies on failing
+    /// fast
+    pub failfast: bool,
+}
+
+impl<T, P> Parser<T> for ParseCon<P>
+where
+    P: Fn(bool, &mut State) -> Result<T, Error>,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        let res = (self.inner)(self.failfast, args);
+        args.current = None;
+        res
+    }
+
+    fn meta(&self) -> Meta {
+        self.meta.clone()
+    }
+}
+
+impl<T> ParseCon<T> {
+    #[must_use]
+
+    /// Automagically restrict the inner parser scope to accept adjacent values only
+    ///
+    /// `adjacent` can solve surprisingly wide variety of problems: sequential command chaining,
+    /// multi-value arguments, option-structs to name a few. If you want to run a parser on a
+    /// sequential subset of arguments - `adjacent` might be able to help you. Check the examples
+    /// for better intuition.
+    ///
+    /// Let's consider two examples with consumed items marked in bold and constructor containing
+    /// parsers for `-c` and `-d`.
+    ///
+    /// - <code>**-a** -b **-c** -d</code>
+    /// - <code>**-a** **-c** -b -d</code>
+    ///
+    /// In the first example `-b` breaks the adjacency for all the consumed items so parsing will fail,
+    /// while here in the second one all the consumed items are adjacent to each other so
+    /// parsing will succeed.
+    ///
+    /// # Multi-value arguments
+    ///
+    /// Parsing things like `--point X Y Z`
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_0.md"))]
+    ///
+    /// # Structure groups
+    ///
+    /// Parsing things like `--rect --width W --height H --rect --height H --width W`
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_1.md"))]
+    ///
+    /// # Chaining commands
+    /// This example explains [`adjacent`](crate::params::ParseCommand::adjacent), but the same idea holds.
+    /// Parsing things like `cmd1 --arg1 cmd2 --arg2 --arg3 cmd3 --flag`
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_command.md"))]
+    ///
+    /// # Capturing everything between markers
+    ///
+    /// Parsing things like `find . --exec foo {} -bar ; --more`
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_3.md"))]
+    ///
+    /// # Multi-value arguments with optional flags
+    ///
+    /// Parsing things like `--foo ARG1 --flag --inner ARG2`
+    ///
+    /// So you can parse things while parsing things. Not sure why you might need this, but you can
+    /// :)
+    ///
+    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_4.md"))]
+    ///
+    /// # Performance and other considerations
+    ///
+    /// `bpaf` can run adjacently restricted parsers multiple times to refine the guesses. It's
+    /// best not to have complex inter-fields verification since they might trip up the detection
+    /// logic: instead of restricting, for example "sum of two fields to be 5 or greater" *inside* the
+    /// `adjacent` parser, you can restrict it *outside*, once `adjacent` done the parsing.
+    ///
+    /// There's also similar method [`adjacent`](crate::parsers::ParseArgument) that allows to restrict argument
+    /// parser to work only for arguments where both key and a value are in the same shell word:
+    /// `-f=bar` or `-fbar`, but not `-f bar`.
+    pub fn adjacent(mut self) -> ParseAdjacent<Self> {
+        self.failfast = true;
+        ParseAdjacent { inner: self }
+    }
+}
+
+/// Parser that replaces metavar placeholders with actual info in shell completion
+#[cfg(feature = "autocomplete")]
+pub struct ParseComp<P, F> {
+    pub(crate) inner: P,
+    pub(crate) op: F,
+    pub(crate) group: Option<String>,
+}
+
+#[cfg(feature = "autocomplete")]
+impl<P, F> ParseComp<P, F> {
+    #[must_use]
+    /// Attach group name to parsed values
+    pub fn group(mut self, group: impl Into<String>) -> Self {
+        self.group = Some(group.into());
+        self
+    }
+}
+
+#[cfg(feature = "autocomplete")]
+impl<P, T, F, M> Parser<T> for ParseComp<P, F>
+where
+    P: Parser<T> + Sized,
+    M: Into<String>,
+    F: Fn(&T) -> Vec<(M, Option<M>)>,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        // stash old
+        let mut comp_items = Vec::new();
+        args.swap_comps_with(&mut comp_items);
+
+        let res = self.inner.eval(args);
+
+        // restore old, now metavars added by inner parser, if any, are in comp_items
+        args.swap_comps_with(&mut comp_items);
+
+        if let Some(comp) = &mut args.comp_mut() {
+            if res.is_err() {
+                comp.extend_comps(comp_items);
+                return res;
+            }
+        }
+
+        let res = res?;
+
+        // completion function generates suggestions based on the parsed inner value, for
+        // that `res` must contain a parsed value
+        let depth = args.depth();
+        if let Some(comp) = &mut args.comp_mut() {
+            for ci in comp_items {
+                let is_meta = ci.is_metavar();
+                if let Some(is_arg) = is_meta {
+                    let suggestions = (self.op)(&res);
+                    // strip metavar when completion makes a single good suggestion
+                    if suggestions.len() != 1 {
+                        comp.push_comp(ci);
+                    }
+                    for (replacement, description) in suggestions {
+                        let group = self.group.clone();
+                        comp.push_value(
+                            replacement.into(),
+                            description.map(Into::into),
+                            group,
+                            depth,
+                            is_arg,
+                        );
+                    }
+                } else {
+                    comp.push_comp(ci);
+                }
+            }
+        }
+        Ok(res)
+    }
+
+    fn meta(&self) -> Meta {
+        self.inner.meta()
+    }
+}
+
+/*
+#[cfg(feature = "autocomplete")]
+pub struct ParseCompStyle<P> {
+    pub(crate) inner: P,
+    pub(crate) style: CompleteDecor,
+}
+
+#[cfg(feature = "autocomplete")]
+impl<P, T> Parser<T> for ParseCompStyle<P>
+where
+    P: Parser<T> + Sized,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        let mut comp_items = Vec::new();
+        args.swap_comps_with(&mut comp_items);
+        let res = self.inner.eval(args);
+        args.swap_comps_with(&mut comp_items);
+        args.extend_with_style(self.style, &mut comp_items);
+        res
+    }
+
+    fn meta(&self) -> Meta {
+        self.inner.meta()
+    }
+}*/
+
+pub struct ParseAdjacent<P> {
+    pub(crate) inner: P,
+}
+impl<P, T> Parser<T> for ParseAdjacent<P>
+where
+    P: Parser<T> + Sized,
+{
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        let original_scope = args.scope();
+
+        let first_item;
+        let inner_meta = self.inner.meta();
+        let mut best_error = if let Some(item) = Meta::first_item(&inner_meta) {
+            first_item = item;
+            let missing_item = MissingItem {
+                item: item.clone(),
+                position: original_scope.start,
+                scope: original_scope.clone(),
+            };
+            Message::Missing(vec![missing_item])
+        } else {
+            unreachable!("bpaf usage BUG: adjacent should start with a required argument");
+        };
+        let mut best_args = args.clone();
+        let mut best_consumed = 0;
+
+        for (start, width, mut this_arg) in args.ranges(first_item) {
+            // since we only want to parse things to the right of the first item we perform
+            // parsing in two passes:
+            // - try to run the parser showing only single argument available at all the indices
+            // - try to run the parser showing starting at that argument and to the right of it
+            // this means constructing argument parsers from req flag and positional works as
+            // expected:
+            // consider examples "42 -n" and "-n 42"
+            // without multi step approach first command line also parses into 42
+            let mut scratch = this_arg.clone();
+            scratch.set_scope(start..start + width);
+            let before = scratch.len();
+
+            // nothing to consume, might as well skip this segment right now
+            // it will most likely fail, but it doesn't matter, we are only looking for the
+            // left most match
+            if before == 0 {
+                continue;
+            }
+
+            let _ = self.inner.eval(&mut scratch);
+
+            if before == scratch.len() {
+                // failed to consume anything which means we don't start parsing at this point
+                continue;
+            }
+
+            this_arg.set_scope(start..original_scope.end);
+            let before = this_arg.len();
+
+            // values consumed by adjacent must be actually adjacent - if a scope contains
+            // already parsed values inside we need to trim it
+            if original_scope.end - start > before {
+                this_arg.set_scope(this_arg.adjacently_available_from(start));
+            }
+
+            loop {
+                match self.inner.eval(&mut this_arg) {
+                    Ok(res) => {
+                        // there's a smaller adjacent scope, we must try it before returning.
+                        if let Some(adj_scope) = this_arg.adjacent_scope(args) {
+                            this_arg = args.clone();
+                            this_arg.set_scope(adj_scope);
+                        } else {
+                            std::mem::swap(args, &mut this_arg);
+                            args.set_scope(original_scope);
+                            return Ok(res);
+                        }
+                    }
+                    Err(Error(err)) => {
+                        let consumed = before - this_arg.len();
+                        if consumed > best_consumed {
+                            best_consumed = consumed;
+                            std::mem::swap(&mut best_args, &mut this_arg);
+                            best_error = err;
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        std::mem::swap(args, &mut best_args);
+        Err(Error(best_error))
+    }
+
+    fn meta(&self) -> Meta {
+        let meta = self.inner.meta();
+        Meta::Adjacent(Box::new(meta))
+    }
+}
+
+impl<T> Parser<T> for Box<dyn Parser<T>> {
+    fn eval(&self, args: &mut State) -> Result<T, Error> {
+        self.as_ref().eval(args)
+    }
+    fn meta(&self) -> Meta {
+        self.as_ref().meta()
+    }
+}
+
\ No newline at end of file diff --git a/static.files/COPYRIGHT-23e9bde6c69aea69.txt b/static.files/COPYRIGHT-23e9bde6c69aea69.txt new file mode 100644 index 00000000..1447df79 --- /dev/null +++ b/static.files/COPYRIGHT-23e9bde6c69aea69.txt @@ -0,0 +1,50 @@ +# REUSE-IgnoreStart + +These documentation pages include resources by third parties. This copyright +file applies only to those resources. The following third party resources are +included, and carry their own copyright notices and license terms: + +* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2): + + Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ + with Reserved Font Name Fira Sans. + + Copyright (c) 2014, Telefonica S.A. + + Licensed under the SIL Open Font License, Version 1.1. + See FiraSans-LICENSE.txt. + +* rustdoc.css, main.js, and playpen.js: + + Copyright 2015 The Rust Developers. + Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or + the MIT license (LICENSE-MIT.txt) at your option. + +* normalize.css: + + Copyright (c) Nicolas Gallagher and Jonathan Neal. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* Source Code Pro (SourceCodePro-Regular.ttf.woff2, + SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2): + + Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark + of Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceCodePro-LICENSE.txt. + +* Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2, + SourceSerif4-It.ttf.woff2): + + Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name + 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United + States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerif4-LICENSE.md. + +This copyright file is intended to be distributed with rustdoc output. + +# REUSE-IgnoreEnd diff --git a/static.files/FiraSans-LICENSE-db4b642586e02d97.txt b/static.files/FiraSans-LICENSE-db4b642586e02d97.txt new file mode 100644 index 00000000..d7e9c149 --- /dev/null +++ b/static.files/FiraSans-LICENSE-db4b642586e02d97.txt @@ -0,0 +1,98 @@ +// REUSE-IgnoreStart + +Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A. +with Reserved Font Name < Fira >, + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 b/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 new file mode 100644 index 00000000..7a1e5fc5 Binary files /dev/null and b/static.files/FiraSans-Medium-8f9a781e4970d388.woff2 differ diff --git a/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 b/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 new file mode 100644 index 00000000..e766e06c Binary files /dev/null and b/static.files/FiraSans-Regular-018c141bf0843ffd.woff2 differ diff --git a/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt b/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt new file mode 100644 index 00000000..16fe87b0 --- /dev/null +++ b/static.files/LICENSE-APACHE-b91fa81cba47b86a.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/static.files/LICENSE-MIT-65090b722b3f6c56.txt b/static.files/LICENSE-MIT-65090b722b3f6c56.txt new file mode 100644 index 00000000..31aa7938 --- /dev/null +++ b/static.files/LICENSE-MIT-65090b722b3f6c56.txt @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 b/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 new file mode 100644 index 00000000..1866ad4b Binary files /dev/null and b/static.files/NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2 differ diff --git a/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt b/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt new file mode 100644 index 00000000..4b3edc29 --- /dev/null +++ b/static.files/NanumBarunGothic-LICENSE-18c5adf4b52b4041.txt @@ -0,0 +1,103 @@ +// REUSE-IgnoreStart + +Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/), + +with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, +NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, +Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco, +NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic, +Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 b/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 new file mode 100644 index 00000000..462c34ef Binary files /dev/null and b/static.files/SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 differ diff --git a/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt b/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt new file mode 100644 index 00000000..0d2941e1 --- /dev/null +++ b/static.files/SourceCodePro-LICENSE-d180d465a756484a.txt @@ -0,0 +1,97 @@ +// REUSE-IgnoreStart + +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 b/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 new file mode 100644 index 00000000..10b558e0 Binary files /dev/null and b/static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2 differ diff --git a/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 b/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 new file mode 100644 index 00000000..5ec64eef Binary files /dev/null and b/static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2 differ diff --git a/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 b/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 new file mode 100644 index 00000000..181a07f6 Binary files /dev/null and b/static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2 differ diff --git a/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 b/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 new file mode 100644 index 00000000..2ae08a7b Binary files /dev/null and b/static.files/SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2 differ diff --git a/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md b/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md new file mode 100644 index 00000000..175fa4f4 --- /dev/null +++ b/static.files/SourceSerif4-LICENSE-3bb119e13b1258b7.md @@ -0,0 +1,98 @@ + + +Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. +Copyright 2014 - 2023 Adobe (http://www.adobe.com/), with Reserved Font Name ‘Source’. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + + diff --git a/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 b/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 new file mode 100644 index 00000000..0263fc30 Binary files /dev/null and b/static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2 differ diff --git a/static.files/clipboard-7571035ce49a181d.svg b/static.files/clipboard-7571035ce49a181d.svg new file mode 100644 index 00000000..8adbd996 --- /dev/null +++ b/static.files/clipboard-7571035ce49a181d.svg @@ -0,0 +1 @@ + diff --git a/static.files/favicon-16x16-8b506e7a72182f1c.png b/static.files/favicon-16x16-8b506e7a72182f1c.png new file mode 100644 index 00000000..ea4b45ca Binary files /dev/null and b/static.files/favicon-16x16-8b506e7a72182f1c.png differ diff --git a/static.files/favicon-2c020d218678b618.svg b/static.files/favicon-2c020d218678b618.svg new file mode 100644 index 00000000..8b34b511 --- /dev/null +++ b/static.files/favicon-2c020d218678b618.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/static.files/favicon-32x32-422f7d1d52889060.png b/static.files/favicon-32x32-422f7d1d52889060.png new file mode 100644 index 00000000..69b8613c Binary files /dev/null and b/static.files/favicon-32x32-422f7d1d52889060.png differ diff --git a/static.files/main-48f368f3872407c8.js b/static.files/main-48f368f3872407c8.js new file mode 100644 index 00000000..987fae42 --- /dev/null +++ b/static.files/main-48f368f3872407c8.js @@ -0,0 +1,11 @@ +"use strict";window.RUSTDOC_TOOLTIP_HOVER_MS=300;window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS=450;function resourcePath(basename,extension){return getVar("root-path")+basename+getVar("resource-suffix")+extension}function hideMain(){addClass(document.getElementById(MAIN_ID),"hidden")}function showMain(){removeClass(document.getElementById(MAIN_ID),"hidden")}function blurHandler(event,parentElem,hideCallback){if(!parentElem.contains(document.activeElement)&&!parentElem.contains(event.relatedTarget)){hideCallback()}}window.rootPath=getVar("root-path");window.currentCrate=getVar("current-crate");function setMobileTopbar(){const mobileTopbar=document.querySelector(".mobile-topbar");const locationTitle=document.querySelector(".sidebar h2.location");if(mobileTopbar){const mobileTitle=document.createElement("h2");mobileTitle.className="location";if(hasClass(document.querySelector(".rustdoc"),"crate")){mobileTitle.innerText=`Crate ${window.currentCrate}`}else if(locationTitle){mobileTitle.innerHTML=locationTitle.innerHTML}mobileTopbar.appendChild(mobileTitle)}}function getVirtualKey(ev){if("key"in ev&&typeof ev.key!=="undefined"){return ev.key}const c=ev.charCode||ev.keyCode;if(c===27){return"Escape"}return String.fromCharCode(c)}const MAIN_ID="main-content";const SETTINGS_BUTTON_ID="settings-menu";const ALTERNATIVE_DISPLAY_ID="alternative-display";const NOT_DISPLAYED_ID="not-displayed";const HELP_BUTTON_ID="help-button";function getSettingsButton(){return document.getElementById(SETTINGS_BUTTON_ID)}function getHelpButton(){return document.getElementById(HELP_BUTTON_ID)}function getNakedUrl(){return window.location.href.split("?")[0].split("#")[0]}function insertAfter(newNode,referenceNode){referenceNode.parentNode.insertBefore(newNode,referenceNode.nextSibling)}function getOrCreateSection(id,classes){let el=document.getElementById(id);if(!el){el=document.createElement("section");el.id=id;el.className=classes;insertAfter(el,document.getElementById(MAIN_ID))}return el}function getAlternativeDisplayElem(){return getOrCreateSection(ALTERNATIVE_DISPLAY_ID,"content hidden")}function getNotDisplayedElem(){return getOrCreateSection(NOT_DISPLAYED_ID,"hidden")}function switchDisplayedElement(elemToDisplay){const el=getAlternativeDisplayElem();if(el.children.length>0){getNotDisplayedElem().appendChild(el.firstElementChild)}if(elemToDisplay===null){addClass(el,"hidden");showMain();return}el.appendChild(elemToDisplay);hideMain();removeClass(el,"hidden")}function browserSupportsHistoryApi(){return window.history&&typeof window.history.pushState==="function"}function preLoadCss(cssUrl){const link=document.createElement("link");link.href=cssUrl;link.rel="preload";link.as="style";document.getElementsByTagName("head")[0].appendChild(link)}(function(){const isHelpPage=window.location.pathname.endsWith("/help.html");function loadScript(url){const script=document.createElement("script");script.src=url;document.head.append(script)}getSettingsButton().onclick=event=>{if(event.ctrlKey||event.altKey||event.metaKey){return}window.hideAllModals(false);addClass(getSettingsButton(),"rotate");event.preventDefault();loadScript(getVar("static-root-path")+getVar("settings-js"));setTimeout(()=>{const themes=getVar("themes").split(",");for(const theme of themes){if(theme!==""){preLoadCss(getVar("root-path")+theme+".css")}}},0)};window.searchState={loadingText:"Loading search results...",input:document.getElementsByClassName("search-input")[0],outputElement:()=>{let el=document.getElementById("search");if(!el){el=document.createElement("section");el.id="search";getNotDisplayedElem().appendChild(el)}return el},title:document.title,titleBeforeSearch:document.title,timeout:null,currentTab:0,focusedByTab:[null,null,null],clearInputTimeout:()=>{if(searchState.timeout!==null){clearTimeout(searchState.timeout);searchState.timeout=null}},isDisplayed:()=>searchState.outputElement().parentElement.id===ALTERNATIVE_DISPLAY_ID,focus:()=>{searchState.input.focus()},defocus:()=>{searchState.input.blur()},showResults:search=>{if(search===null||typeof search==="undefined"){search=searchState.outputElement()}switchDisplayedElement(search);searchState.mouseMovedAfterSearch=false;document.title=searchState.title},removeQueryParameters:()=>{document.title=searchState.titleBeforeSearch;if(browserSupportsHistoryApi()){history.replaceState(null,"",getNakedUrl()+window.location.hash)}},hideResults:()=>{switchDisplayedElement(null);searchState.removeQueryParameters()},getQueryStringParams:()=>{const params={};window.location.search.substring(1).split("&").map(s=>{const pair=s.split("=").map(x=>x.replace(/\+/g," "));params[decodeURIComponent(pair[0])]=typeof pair[1]==="undefined"?null:decodeURIComponent(pair[1])});return params},setup:()=>{const search_input=searchState.input;if(!searchState.input){return}let searchLoaded=false;function loadSearch(){if(!searchLoaded){searchLoaded=true;loadScript(getVar("static-root-path")+getVar("search-js"));loadScript(resourcePath("search-index",".js"))}}search_input.addEventListener("focus",()=>{search_input.origPlaceholder=search_input.placeholder;search_input.placeholder="Type your search here.";loadSearch()});if(search_input.value!==""){loadSearch()}const params=searchState.getQueryStringParams();if(params.search!==undefined){searchState.setLoadingSearch();loadSearch()}},setLoadingSearch:()=>{const search=searchState.outputElement();search.innerHTML="

"+searchState.loadingText+"

";searchState.showResults(search)},};const toggleAllDocsId="toggle-all-docs";let savedHash="";function handleHashes(ev){if(ev!==null&&searchState.isDisplayed()&&ev.newURL){switchDisplayedElement(null);const hash=ev.newURL.slice(ev.newURL.indexOf("#")+1);if(browserSupportsHistoryApi()){history.replaceState(null,"",getNakedUrl()+window.location.search+"#"+hash)}const elem=document.getElementById(hash);if(elem){elem.scrollIntoView()}}const pageId=window.location.hash.replace(/^#/,"");if(savedHash!==pageId){savedHash=pageId;if(pageId!==""){expandSection(pageId)}}if(savedHash.startsWith("impl-")){const splitAt=savedHash.indexOf("/");if(splitAt!==-1){const implId=savedHash.slice(0,splitAt);const assocId=savedHash.slice(splitAt+1);const implElem=document.getElementById(implId);if(implElem&&implElem.parentElement.tagName==="SUMMARY"&&implElem.parentElement.parentElement.tagName==="DETAILS"){onEachLazy(implElem.parentElement.parentElement.querySelectorAll(`[id^="${assocId}"]`),item=>{const numbered=/([^-]+)-([0-9]+)/.exec(item.id);if(item.id===assocId||(numbered&&numbered[1]===assocId)){openParentDetails(item);item.scrollIntoView();setTimeout(()=>{window.location.replace("#"+item.id)},0)}})}}}}function onHashChange(ev){hideSidebar();handleHashes(ev)}function openParentDetails(elem){while(elem){if(elem.tagName==="DETAILS"){elem.open=true}elem=elem.parentNode}}function expandSection(id){openParentDetails(document.getElementById(id))}function handleEscape(ev){searchState.clearInputTimeout();searchState.hideResults();ev.preventDefault();searchState.defocus();window.hideAllModals(true)}function handleShortcut(ev){const disableShortcuts=getSettingValue("disable-shortcuts")==="true";if(ev.ctrlKey||ev.altKey||ev.metaKey||disableShortcuts){return}if(document.activeElement.tagName==="INPUT"&&document.activeElement.type!=="checkbox"&&document.activeElement.type!=="radio"){switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break}}else{switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break;case"s":case"S":ev.preventDefault();searchState.focus();break;case"+":ev.preventDefault();expandAllDocs();break;case"-":ev.preventDefault();collapseAllDocs();break;case"?":showHelp();break;default:break}}}document.addEventListener("keypress",handleShortcut);document.addEventListener("keydown",handleShortcut);function addSidebarItems(){if(!window.SIDEBAR_ITEMS){return}const sidebar=document.getElementsByClassName("sidebar-elems")[0];function block(shortty,id,longty){const filtered=window.SIDEBAR_ITEMS[shortty];if(!filtered){return}const modpath=hasClass(document.querySelector(".rustdoc"),"mod")?"../":"";const h3=document.createElement("h3");h3.innerHTML=`${longty}`;const ul=document.createElement("ul");ul.className="block "+shortty;for(const name of filtered){let path;if(shortty==="mod"){path=`${modpath}${name}/index.html`}else{path=`${modpath}${shortty}.${name}.html`}let current_page=document.location.href.toString();if(current_page.endsWith("/")){current_page+="index.html"}const link=document.createElement("a");link.href=path;if(path===current_page){link.className="current"}link.textContent=name;const li=document.createElement("li");li.appendChild(link);ul.appendChild(li)}sidebar.appendChild(h3);sidebar.appendChild(ul)}if(sidebar){block("primitive","primitives","Primitive Types");block("mod","modules","Modules");block("macro","macros","Macros");block("struct","structs","Structs");block("enum","enums","Enums");block("constant","constants","Constants");block("static","static","Statics");block("trait","traits","Traits");block("fn","functions","Functions");block("type","types","Type Aliases");block("union","unions","Unions");block("foreigntype","foreign-types","Foreign Types");block("keyword","keywords","Keywords");block("opaque","opaque-types","Opaque Types");block("attr","attributes","Attribute Macros");block("derive","derives","Derive Macros");block("traitalias","trait-aliases","Trait Aliases")}}window.register_implementors=imp=>{const implementors=document.getElementById("implementors-list");const synthetic_implementors=document.getElementById("synthetic-implementors-list");const inlined_types=new Set();const TEXT_IDX=0;const SYNTHETIC_IDX=1;const TYPES_IDX=2;if(synthetic_implementors){onEachLazy(synthetic_implementors.getElementsByClassName("impl"),el=>{const aliases=el.getAttribute("data-aliases");if(!aliases){return}aliases.split(",").forEach(alias=>{inlined_types.add(alias)})})}let currentNbImpls=implementors.getElementsByClassName("impl").length;const traitName=document.querySelector(".main-heading h1 > .trait").textContent;const baseIdName="impl-"+traitName+"-";const libs=Object.getOwnPropertyNames(imp);const script=document.querySelector("script[data-ignore-extern-crates]");const ignoreExternCrates=new Set((script?script.getAttribute("data-ignore-extern-crates"):"").split(","));for(const lib of libs){if(lib===window.currentCrate||ignoreExternCrates.has(lib)){continue}const structs=imp[lib];struct_loop:for(const struct of structs){const list=struct[SYNTHETIC_IDX]?synthetic_implementors:implementors;if(struct[SYNTHETIC_IDX]){for(const struct_type of struct[TYPES_IDX]){if(inlined_types.has(struct_type)){continue struct_loop}inlined_types.add(struct_type)}}const code=document.createElement("h3");code.innerHTML=struct[TEXT_IDX];addClass(code,"code-header");onEachLazy(code.getElementsByTagName("a"),elem=>{const href=elem.getAttribute("href");if(href&&!href.startsWith("#")&&!/^(?:[a-z+]+:)?\/\//.test(href)){elem.setAttribute("href",window.rootPath+href)}});const currentId=baseIdName+currentNbImpls;const anchor=document.createElement("a");anchor.href="#"+currentId;addClass(anchor,"anchor");const display=document.createElement("div");display.id=currentId;addClass(display,"impl");display.appendChild(anchor);display.appendChild(code);list.appendChild(display);currentNbImpls+=1}}};if(window.pending_implementors){window.register_implementors(window.pending_implementors)}window.register_type_impls=imp=>{if(!imp||!imp[window.currentCrate]){return}window.pending_type_impls=null;const idMap=new Map();let implementations=document.getElementById("implementations-list");let trait_implementations=document.getElementById("trait-implementations-list");let trait_implementations_header=document.getElementById("trait-implementations");const script=document.querySelector("script[data-self-path]");const selfPath=script?script.getAttribute("data-self-path"):null;const mainContent=document.querySelector("#main-content");const sidebarSection=document.querySelector(".sidebar section");let methods=document.querySelector(".sidebar .block.method");let associatedTypes=document.querySelector(".sidebar .block.associatedtype");let associatedConstants=document.querySelector(".sidebar .block.associatedconstant");let sidebarTraitList=document.querySelector(".sidebar .block.trait-implementation");for(const impList of imp[window.currentCrate]){const types=impList.slice(2);const text=impList[0];const isTrait=impList[1]!==0;const traitName=impList[1];if(types.indexOf(selfPath)===-1){continue}let outputList=isTrait?trait_implementations:implementations;if(outputList===null){const outputListName=isTrait?"Trait Implementations":"Implementations";const outputListId=isTrait?"trait-implementations-list":"implementations-list";const outputListHeaderId=isTrait?"trait-implementations":"implementations";const outputListHeader=document.createElement("h2");outputListHeader.id=outputListHeaderId;outputListHeader.innerText=outputListName;outputList=document.createElement("div");outputList.id=outputListId;if(isTrait){const link=document.createElement("a");link.href=`#${outputListHeaderId}`;link.innerText="Trait Implementations";const h=document.createElement("h3");h.appendChild(link);trait_implementations=outputList;trait_implementations_header=outputListHeader;sidebarSection.appendChild(h);sidebarTraitList=document.createElement("ul");sidebarTraitList.className="block trait-implementation";sidebarSection.appendChild(sidebarTraitList);mainContent.appendChild(outputListHeader);mainContent.appendChild(outputList)}else{implementations=outputList;if(trait_implementations){mainContent.insertBefore(outputListHeader,trait_implementations_header);mainContent.insertBefore(outputList,trait_implementations_header)}else{const mainContent=document.querySelector("#main-content");mainContent.appendChild(outputListHeader);mainContent.appendChild(outputList)}}}const template=document.createElement("template");template.innerHTML=text;onEachLazy(template.content.querySelectorAll("a"),elem=>{const href=elem.getAttribute("href");if(href&&!href.startsWith("#")&&!/^(?:[a-z+]+:)?\/\//.test(href)){elem.setAttribute("href",window.rootPath+href)}});onEachLazy(template.content.querySelectorAll("[id]"),el=>{let i=0;if(idMap.has(el.id)){i=idMap.get(el.id)}else if(document.getElementById(el.id)){i=1;while(document.getElementById(`${el.id}-${2 * i}`)){i=2*i}while(document.getElementById(`${el.id}-${i}`)){i+=1}}if(i!==0){const oldHref=`#${el.id}`;const newHref=`#${el.id}-${i}`;el.id=`${el.id}-${i}`;onEachLazy(template.content.querySelectorAll("a[href]"),link=>{if(link.getAttribute("href")===oldHref){link.href=newHref}})}idMap.set(el.id,i+1)});const templateAssocItems=template.content.querySelectorAll("section.tymethod, "+"section.method, section.associatedtype, section.associatedconstant");if(isTrait){const li=document.createElement("li");const a=document.createElement("a");a.href=`#${template.content.querySelector(".impl").id}`;a.textContent=traitName;li.appendChild(a);sidebarTraitList.append(li)}else{onEachLazy(templateAssocItems,item=>{let block=hasClass(item,"associatedtype")?associatedTypes:(hasClass(item,"associatedconstant")?associatedConstants:(methods));if(!block){const blockTitle=hasClass(item,"associatedtype")?"Associated Types":(hasClass(item,"associatedconstant")?"Associated Constants":("Methods"));const blockClass=hasClass(item,"associatedtype")?"associatedtype":(hasClass(item,"associatedconstant")?"associatedconstant":("method"));const blockHeader=document.createElement("h3");const blockLink=document.createElement("a");blockLink.href="#implementations";blockLink.innerText=blockTitle;blockHeader.appendChild(blockLink);block=document.createElement("ul");block.className=`block ${blockClass}`;const insertionReference=methods||sidebarTraitList;if(insertionReference){const insertionReferenceH=insertionReference.previousElementSibling;sidebarSection.insertBefore(blockHeader,insertionReferenceH);sidebarSection.insertBefore(block,insertionReferenceH)}else{sidebarSection.appendChild(blockHeader);sidebarSection.appendChild(block)}if(hasClass(item,"associatedtype")){associatedTypes=block}else if(hasClass(item,"associatedconstant")){associatedConstants=block}else{methods=block}}const li=document.createElement("li");const a=document.createElement("a");a.innerText=item.id.split("-")[0].split(".")[1];a.href=`#${item.id}`;li.appendChild(a);block.appendChild(li)})}outputList.appendChild(template.content)}for(const list of[methods,associatedTypes,associatedConstants,sidebarTraitList]){if(!list){continue}const newChildren=Array.prototype.slice.call(list.children);newChildren.sort((a,b)=>{const aI=a.innerText;const bI=b.innerText;return aIbI?1:0});list.replaceChildren(...newChildren)}};if(window.pending_type_impls){window.register_type_impls(window.pending_type_impls)}function addSidebarCrates(){if(!window.ALL_CRATES){return}const sidebarElems=document.getElementsByClassName("sidebar-elems")[0];if(!sidebarElems){return}const h3=document.createElement("h3");h3.innerHTML="Crates";const ul=document.createElement("ul");ul.className="block crate";for(const crate of window.ALL_CRATES){const link=document.createElement("a");link.href=window.rootPath+crate+"/index.html";link.textContent=crate;const li=document.createElement("li");if(window.rootPath!=="./"&&crate===window.currentCrate){li.className="current"}li.appendChild(link);ul.appendChild(li)}sidebarElems.appendChild(h3);sidebarElems.appendChild(ul)}function expandAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);removeClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("toggle"),e=>{if(!hasClass(e,"type-contents-toggle")&&!hasClass(e,"more-examples-toggle")){e.open=true}});innerToggle.title="collapse all docs";innerToggle.children[0].innerText="\u2212"}function collapseAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);addClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("toggle"),e=>{if(e.parentNode.id!=="implementations-list"||(!hasClass(e,"implementors-toggle")&&!hasClass(e,"type-contents-toggle"))){e.open=false}});innerToggle.title="expand all docs";innerToggle.children[0].innerText="+"}function toggleAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);if(!innerToggle){return}if(hasClass(innerToggle,"will-expand")){expandAllDocs()}else{collapseAllDocs()}}(function(){const toggles=document.getElementById(toggleAllDocsId);if(toggles){toggles.onclick=toggleAllDocs}const hideMethodDocs=getSettingValue("auto-hide-method-docs")==="true";const hideImplementations=getSettingValue("auto-hide-trait-implementations")==="true";const hideLargeItemContents=getSettingValue("auto-hide-large-items")!=="false";function setImplementorsTogglesOpen(id,open){const list=document.getElementById(id);if(list!==null){onEachLazy(list.getElementsByClassName("implementors-toggle"),e=>{e.open=open})}}if(hideImplementations){setImplementorsTogglesOpen("trait-implementations-list",false);setImplementorsTogglesOpen("blanket-implementations-list",false)}onEachLazy(document.getElementsByClassName("toggle"),e=>{if(!hideLargeItemContents&&hasClass(e,"type-contents-toggle")){e.open=true}if(hideMethodDocs&&hasClass(e,"method-toggle")){e.open=false}})}());window.rustdoc_add_line_numbers_to_examples=()=>{onEachLazy(document.getElementsByClassName("rust-example-rendered"),x=>{const parent=x.parentNode;const line_numbers=parent.querySelectorAll(".example-line-numbers");if(line_numbers.length>0){return}const count=x.textContent.split("\n").length;const elems=[];for(let i=0;i{onEachLazy(document.getElementsByClassName("rust-example-rendered"),x=>{const parent=x.parentNode;const line_numbers=parent.querySelectorAll(".example-line-numbers");for(const node of line_numbers){parent.removeChild(node)}})};if(getSettingValue("line-numbers")==="true"){window.rustdoc_add_line_numbers_to_examples()}function showSidebar(){window.hideAllModals(false);const sidebar=document.getElementsByClassName("sidebar")[0];addClass(sidebar,"shown")}function hideSidebar(){const sidebar=document.getElementsByClassName("sidebar")[0];removeClass(sidebar,"shown")}window.addEventListener("resize",()=>{if(window.CURRENT_TOOLTIP_ELEMENT){const base=window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;const force_visible=base.TOOLTIP_FORCE_VISIBLE;hideTooltip(false);if(force_visible){showTooltip(base);base.TOOLTIP_FORCE_VISIBLE=true}}});const mainElem=document.getElementById(MAIN_ID);if(mainElem){mainElem.addEventListener("click",hideSidebar)}onEachLazy(document.querySelectorAll("a[href^='#']"),el=>{el.addEventListener("click",()=>{expandSection(el.hash.slice(1));hideSidebar()})});onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"),el=>{el.addEventListener("click",e=>{if(e.target.tagName!=="SUMMARY"&&e.target.tagName!=="A"){e.preventDefault()}})});function showTooltip(e){const notable_ty=e.getAttribute("data-notable-ty");if(!window.NOTABLE_TRAITS&¬able_ty){const data=document.getElementById("notable-traits-data");if(data){window.NOTABLE_TRAITS=JSON.parse(data.innerText)}else{throw new Error("showTooltip() called with notable without any notable traits!")}}if(window.CURRENT_TOOLTIP_ELEMENT&&window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE===e){clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);return}window.hideAllModals(false);const wrapper=document.createElement("div");if(notable_ty){wrapper.innerHTML="
"+window.NOTABLE_TRAITS[notable_ty]+"
"}else{if(e.getAttribute("title")!==null){e.setAttribute("data-title",e.getAttribute("title"));e.removeAttribute("title")}if(e.getAttribute("data-title")!==null){const titleContent=document.createElement("div");titleContent.className="content";titleContent.appendChild(document.createTextNode(e.getAttribute("data-title")));wrapper.appendChild(titleContent)}}wrapper.className="tooltip popover";const focusCatcher=document.createElement("div");focusCatcher.setAttribute("tabindex","0");focusCatcher.onfocus=hideTooltip;wrapper.appendChild(focusCatcher);const pos=e.getBoundingClientRect();wrapper.style.top=(pos.top+window.scrollY+pos.height)+"px";wrapper.style.left=0;wrapper.style.right="auto";wrapper.style.visibility="hidden";const body=document.getElementsByTagName("body")[0];body.appendChild(wrapper);const wrapperPos=wrapper.getBoundingClientRect();const finalPos=pos.left+window.scrollX-wrapperPos.width+24;if(finalPos>0){wrapper.style.left=finalPos+"px"}else{wrapper.style.setProperty("--popover-arrow-offset",(wrapperPos.right-pos.right+4)+"px")}wrapper.style.visibility="";window.CURRENT_TOOLTIP_ELEMENT=wrapper;window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE=e;clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);wrapper.onpointerenter=ev=>{if(ev.pointerType!=="mouse"){return}clearTooltipHoverTimeout(e)};wrapper.onpointerleave=ev=>{if(ev.pointerType!=="mouse"){return}if(!e.TOOLTIP_FORCE_VISIBLE&&!e.contains(ev.relatedTarget)){setTooltipHoverTimeout(e,false);addClass(wrapper,"fade-out")}}}function setTooltipHoverTimeout(element,show){clearTooltipHoverTimeout(element);if(!show&&!window.CURRENT_TOOLTIP_ELEMENT){return}if(show&&window.CURRENT_TOOLTIP_ELEMENT){return}if(window.CURRENT_TOOLTIP_ELEMENT&&window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE!==element){return}element.TOOLTIP_HOVER_TIMEOUT=setTimeout(()=>{if(show){showTooltip(element)}else if(!element.TOOLTIP_FORCE_VISIBLE){hideTooltip(false)}},show?window.RUSTDOC_TOOLTIP_HOVER_MS:window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS)}function clearTooltipHoverTimeout(element){if(element.TOOLTIP_HOVER_TIMEOUT!==undefined){removeClass(window.CURRENT_TOOLTIP_ELEMENT,"fade-out");clearTimeout(element.TOOLTIP_HOVER_TIMEOUT);delete element.TOOLTIP_HOVER_TIMEOUT}}function tooltipBlurHandler(event){if(window.CURRENT_TOOLTIP_ELEMENT&&!window.CURRENT_TOOLTIP_ELEMENT.contains(document.activeElement)&&!window.CURRENT_TOOLTIP_ELEMENT.contains(event.relatedTarget)&&!window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(document.activeElement)&&!window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(event.relatedTarget)){setTimeout(()=>hideTooltip(false),0)}}function hideTooltip(focus){if(window.CURRENT_TOOLTIP_ELEMENT){if(window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE){if(focus){window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus()}window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE=false}const body=document.getElementsByTagName("body")[0];body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);window.CURRENT_TOOLTIP_ELEMENT=null}}onEachLazy(document.getElementsByClassName("tooltip"),e=>{e.onclick=()=>{e.TOOLTIP_FORCE_VISIBLE=e.TOOLTIP_FORCE_VISIBLE?false:true;if(window.CURRENT_TOOLTIP_ELEMENT&&!e.TOOLTIP_FORCE_VISIBLE){hideTooltip(true)}else{showTooltip(e);window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex","0");window.CURRENT_TOOLTIP_ELEMENT.focus();window.CURRENT_TOOLTIP_ELEMENT.onblur=tooltipBlurHandler}return false};e.onpointerenter=ev=>{if(ev.pointerType!=="mouse"){return}setTooltipHoverTimeout(e,true)};e.onpointermove=ev=>{if(ev.pointerType!=="mouse"){return}setTooltipHoverTimeout(e,true)};e.onpointerleave=ev=>{if(ev.pointerType!=="mouse"){return}if(!e.TOOLTIP_FORCE_VISIBLE&&window.CURRENT_TOOLTIP_ELEMENT&&!window.CURRENT_TOOLTIP_ELEMENT.contains(ev.relatedTarget)){setTooltipHoverTimeout(e,false);addClass(window.CURRENT_TOOLTIP_ELEMENT,"fade-out")}}});const sidebar_menu_toggle=document.getElementsByClassName("sidebar-menu-toggle")[0];if(sidebar_menu_toggle){sidebar_menu_toggle.addEventListener("click",()=>{const sidebar=document.getElementsByClassName("sidebar")[0];if(!hasClass(sidebar,"shown")){showSidebar()}else{hideSidebar()}})}function helpBlurHandler(event){blurHandler(event,getHelpButton(),window.hidePopoverMenus)}function buildHelpMenu(){const book_info=document.createElement("span");const channel=getVar("channel");book_info.className="top";book_info.innerHTML=`You can find more information in \ +the rustdoc book.`;const shortcuts=[["?","Show this help dialog"],["S","Focus the search field"],["↑","Move up in search results"],["↓","Move down in search results"],["← / →","Switch result tab (when results focused)"],["⏎","Go to active search result"],["+","Expand all sections"],["-","Collapse all sections"],].map(x=>"
"+x[0].split(" ").map((y,index)=>((index&1)===0?""+y+"":" "+y+" ")).join("")+"
"+x[1]+"
").join("");const div_shortcuts=document.createElement("div");addClass(div_shortcuts,"shortcuts");div_shortcuts.innerHTML="

Keyboard Shortcuts

"+shortcuts+"
";const infos=[`For a full list of all search features, take a look here.`,"Prefix searches with a type followed by a colon (e.g., fn:) to \ + restrict the search to a given item kind.","Accepted kinds are: fn, mod, struct, \ + enum, trait, type, macro, \ + and const.","Search functions by type signature (e.g., vec -> usize or \ + -> vec or String, enum:Cow -> bool)","You can look for items with an exact name by putting double quotes around \ + your request: \"string\"","Look for functions that accept or return \ + slices and \ + arrays by writing \ + square brackets (e.g., -> [u8] or [] -> Option)","Look for items inside another one by searching for a path: vec::Vec",].map(x=>"

"+x+"

").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="

Search Tricks

"+infos;const rustdoc_version=document.createElement("span");rustdoc_version.className="bottom";const rustdoc_version_code=document.createElement("code");rustdoc_version_code.innerText="rustdoc "+getVar("rustdoc-version");rustdoc_version.appendChild(rustdoc_version_code);const container=document.createElement("div");if(!isHelpPage){container.className="popover"}container.id="help";container.style.display="none";const side_by_side=document.createElement("div");side_by_side.className="side-by-side";side_by_side.appendChild(div_shortcuts);side_by_side.appendChild(div_infos);container.appendChild(book_info);container.appendChild(side_by_side);container.appendChild(rustdoc_version);if(isHelpPage){const help_section=document.createElement("section");help_section.appendChild(container);document.getElementById("main-content").appendChild(help_section);container.style.display="block"}else{const help_button=getHelpButton();help_button.appendChild(container);container.onblur=helpBlurHandler;help_button.onblur=helpBlurHandler;help_button.children[0].onblur=helpBlurHandler}return container}window.hideAllModals=switchFocus=>{hideSidebar();window.hidePopoverMenus();hideTooltip(switchFocus)};window.hidePopoverMenus=()=>{onEachLazy(document.querySelectorAll(".search-form .popover"),elem=>{elem.style.display="none"})};function getHelpMenu(buildNeeded){let menu=getHelpButton().querySelector(".popover");if(!menu&&buildNeeded){menu=buildHelpMenu()}return menu}function showHelp(){getHelpButton().querySelector("a").focus();const menu=getHelpMenu(true);if(menu.style.display==="none"){window.hideAllModals();menu.style.display=""}}if(isHelpPage){showHelp();document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click",event=>{const target=event.target;if(target.tagName!=="A"||target.parentElement.id!==HELP_BUTTON_ID||event.ctrlKey||event.altKey||event.metaKey){return}event.preventDefault()})}else{document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click",event=>{const target=event.target;if(target.tagName!=="A"||target.parentElement.id!==HELP_BUTTON_ID||event.ctrlKey||event.altKey||event.metaKey){return}event.preventDefault();const menu=getHelpMenu(true);const shouldShowHelp=menu.style.display==="none";if(shouldShowHelp){showHelp()}else{window.hidePopoverMenus()}})}setMobileTopbar();addSidebarItems();addSidebarCrates();onHashChange(null);window.addEventListener("hashchange",onHashChange);searchState.setup()}());(function(){const SIDEBAR_MIN=100;const SIDEBAR_MAX=500;const RUSTDOC_MOBILE_BREAKPOINT=700;const BODY_MIN=400;const SIDEBAR_VANISH_THRESHOLD=SIDEBAR_MIN/2;const sidebarButton=document.getElementById("sidebar-button");if(sidebarButton){sidebarButton.addEventListener("click",e=>{removeClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","false");if(document.querySelector(".rustdoc.src")){window.rustdocToggleSrcSidebar()}e.preventDefault()})}let currentPointerId=null;let desiredSidebarSize=null;let pendingSidebarResizingFrame=false;const resizer=document.querySelector(".sidebar-resizer");const sidebar=document.querySelector(".sidebar");if(!resizer||!sidebar){return}const isSrcPage=hasClass(document.body,"src");function hideSidebar(){if(isSrcPage){window.rustdocCloseSourceSidebar();updateLocalStorage("src-sidebar-width",null);document.documentElement.style.removeProperty("--src-sidebar-width");sidebar.style.removeProperty("--src-sidebar-width");resizer.style.removeProperty("--src-sidebar-width")}else{addClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","true");updateLocalStorage("desktop-sidebar-width",null);document.documentElement.style.removeProperty("--desktop-sidebar-width");sidebar.style.removeProperty("--desktop-sidebar-width");resizer.style.removeProperty("--desktop-sidebar-width")}}function showSidebar(){if(isSrcPage){window.rustdocShowSourceSidebar()}else{removeClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","false")}}function changeSidebarSize(size){if(isSrcPage){updateLocalStorage("src-sidebar-width",size);sidebar.style.setProperty("--src-sidebar-width",size+"px");resizer.style.setProperty("--src-sidebar-width",size+"px")}else{updateLocalStorage("desktop-sidebar-width",size);sidebar.style.setProperty("--desktop-sidebar-width",size+"px");resizer.style.setProperty("--desktop-sidebar-width",size+"px")}}function isSidebarHidden(){return isSrcPage?!hasClass(document.documentElement,"src-sidebar-expanded"):hasClass(document.documentElement,"hide-sidebar")}function resize(e){if(currentPointerId===null||currentPointerId!==e.pointerId){return}e.preventDefault();const pos=e.clientX-3;if(pos=SIDEBAR_MIN){if(isSidebarHidden()){showSidebar()}const constrainedPos=Math.min(pos,window.innerWidth-BODY_MIN,SIDEBAR_MAX);changeSidebarSize(constrainedPos);desiredSidebarSize=constrainedPos;if(pendingSidebarResizingFrame!==false){clearTimeout(pendingSidebarResizingFrame)}pendingSidebarResizingFrame=setTimeout(()=>{if(currentPointerId===null||pendingSidebarResizingFrame===false){return}pendingSidebarResizingFrame=false;document.documentElement.style.setProperty("--resizing-sidebar-width",desiredSidebarSize+"px")},100)}}window.addEventListener("resize",()=>{if(window.innerWidth=(window.innerWidth-BODY_MIN)){changeSidebarSize(window.innerWidth-BODY_MIN)}else if(desiredSidebarSize!==null&&desiredSidebarSize>SIDEBAR_MIN){changeSidebarSize(desiredSidebarSize)}});function stopResize(e){if(currentPointerId===null){return}if(e){e.preventDefault()}desiredSidebarSize=sidebar.getBoundingClientRect().width;removeClass(resizer,"active");window.removeEventListener("pointermove",resize,false);window.removeEventListener("pointerup",stopResize,false);removeClass(document.documentElement,"sidebar-resizing");document.documentElement.style.removeProperty("--resizing-sidebar-width");if(resizer.releasePointerCapture){resizer.releasePointerCapture(currentPointerId);currentPointerId=null}}function initResize(e){if(currentPointerId!==null||e.altKey||e.ctrlKey||e.metaKey||e.button!==0){return}if(resizer.setPointerCapture){resizer.setPointerCapture(e.pointerId);if(!resizer.hasPointerCapture(e.pointerId)){resizer.releasePointerCapture(e.pointerId);return}currentPointerId=e.pointerId}window.hideAllModals(false);e.preventDefault();window.addEventListener("pointermove",resize,false);window.addEventListener("pointercancel",stopResize,false);window.addEventListener("pointerup",stopResize,false);addClass(resizer,"active");addClass(document.documentElement,"sidebar-resizing");const pos=e.clientX-sidebar.offsetLeft-3;document.documentElement.style.setProperty("--resizing-sidebar-width",pos+"px");desiredSidebarSize=null}resizer.addEventListener("pointerdown",initResize,false)}());(function(){let reset_button_timeout=null;const but=document.getElementById("copy-path");if(!but){return}but.onclick=()=>{const parent=but.parentElement;const path=[];onEach(parent.childNodes,child=>{if(child.tagName==="A"){path.push(child.textContent)}});const el=document.createElement("textarea");el.value=path.join("::");el.setAttribute("readonly","");el.style.position="absolute";el.style.left="-9999px";document.body.appendChild(el);el.select();document.execCommand("copy");document.body.removeChild(el);but.children[0].style.display="none";let tmp;if(but.childNodes.length<2){tmp=document.createTextNode("✓");but.appendChild(tmp)}else{onEachLazy(but.childNodes,e=>{if(e.nodeType===Node.TEXT_NODE){tmp=e;return true}});tmp.textContent="✓"}if(reset_button_timeout!==null){window.clearTimeout(reset_button_timeout)}function reset_button(){tmp.textContent="";reset_button_timeout=null;but.children[0].style.display=""}reset_button_timeout=window.setTimeout(reset_button,1000)}}()) \ No newline at end of file diff --git a/static.files/normalize-76eba96aa4d2e634.css b/static.files/normalize-76eba96aa4d2e634.css new file mode 100644 index 00000000..469959f1 --- /dev/null +++ b/static.files/normalize-76eba96aa4d2e634.css @@ -0,0 +1,2 @@ + /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type="button"],[type="reset"],[type="submit"],button{-webkit-appearance:button}[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} \ No newline at end of file diff --git a/static.files/noscript-04d5337699b92874.css b/static.files/noscript-04d5337699b92874.css new file mode 100644 index 00000000..fbd55f57 --- /dev/null +++ b/static.files/noscript-04d5337699b92874.css @@ -0,0 +1 @@ + #main-content .attributes{margin-left:0 !important;}#copy-path,#sidebar-button,.sidebar-resizer{display:none !important;}nav.sub{display:none;}.src .sidebar{display:none;}.notable-traits{display:none;}:root{--main-background-color:white;--main-color:black;--settings-input-color:#2196f3;--settings-input-border-color:#717171;--settings-button-color:#000;--settings-button-border-focus:#717171;--sidebar-background-color:#f5f5f5;--sidebar-background-color-hover:#e0e0e0;--code-block-background-color:#f5f5f5;--scrollbar-track-background-color:#dcdcdc;--scrollbar-thumb-background-color:rgba(36,37,39,0.6);--scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;--headings-border-bottom-color:#ddd;--border-color:#e0e0e0;--button-background-color:#fff;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:none;--mobile-sidebar-menu-filter:none;--search-input-focused-border-color:#66afe9;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(35%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ad378a;--trait-link-color:#6e4fc9;--assoc-item-link-color:#3873ad;--function-link-color:#ad7c37;--macro-link-color:#068000;--keyword-link-color:#3873ad;--mod-link-color:#3873ad;--link-color:#3873ad;--sidebar-link-color:#356da4;--sidebar-current-link-background-color:#fff;--search-result-link-focus-background-color:#ccc;--search-result-border-color:#aaa3;--search-color:#000;--search-error-code-background-color:#d0cccc;--search-results-alias-color:#000;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#e6e6e6;--search-tab-button-not-selected-background:#e6e6e6;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#fff;--stab-background-color:#fff5d6;--stab-code-color:#000;--code-highlight-kw-color:#8959a8;--code-highlight-kw-2-color:#4271ae;--code-highlight-lifetime-color:#b76514;--code-highlight-prelude-color:#4271ae;--code-highlight-prelude-val-color:#c82829;--code-highlight-number-color:#718c00;--code-highlight-string-color:#718c00;--code-highlight-literal-color:#c82829;--code-highlight-attribute-color:#c82829;--code-highlight-self-color:#c82829;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8e908c;--code-highlight-doc-comment-color:#4d4d4c;--src-line-numbers-span-color:#c67e2d;--src-line-number-highlighted-background-color:#fdffd3;--test-arrow-color:#f5f5f5;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#f5f5f5;--test-arrow-hover-background-color:rgb(78,139,202);--target-background-color:#fdffd3;--target-border-color:#ad7c37;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:initial;--crate-search-div-filter:invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);--crate-search-div-hover-filter:invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);--crate-search-hover-border:#717171;--src-sidebar-background-selected:#fff;--src-sidebar-background-hover:#e0e0e0;--table-alt-row-background-color:#f5f5f5;--codeblock-link-background:#eee;--scrape-example-toggle-line-background:#ccc;--scrape-example-toggle-line-hover-background:#999;--scrape-example-code-line-highlight:#fcffd6;--scrape-example-code-line-highlight-focus:#f6fdb0;--scrape-example-help-border-color:#555;--scrape-example-help-color:#333;--scrape-example-help-hover-border-color:#000;--scrape-example-help-hover-color:#000;--scrape-example-code-wrapper-background-start:rgba(255,255,255,1);--scrape-example-code-wrapper-background-end:rgba(255,255,255,0);--sidebar-resizer-hover:hsl(207,90%,66%);--sidebar-resizer-active:hsl(207,90%,54%);}@media (prefers-color-scheme:dark){:root{--main-background-color:#353535;--main-color:#ddd;--settings-input-color:#2196f3;--settings-input-border-color:#999;--settings-button-color:#000;--settings-button-border-focus:#ffb900;--sidebar-background-color:#505050;--sidebar-background-color-hover:#676767;--code-block-background-color:#2A2A2A;--scrollbar-track-background-color:#717171;--scrollbar-thumb-background-color:rgba(32,34,37,.6);--scrollbar-color:rgba(32,34,37,.6) #5a5a5a;--headings-border-bottom-color:#d2d2d2;--border-color:#e0e0e0;--button-background-color:#f0f0f0;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#008dfd;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(65%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#2dbfb8;--trait-link-color:#b78cf2;--assoc-item-link-color:#d2991d;--function-link-color:#2bab63;--macro-link-color:#09bd00;--keyword-link-color:#d2991d;--mod-link-color:#d2991d;--link-color:#d2991d;--sidebar-link-color:#fdbf35;--sidebar-current-link-background-color:#444;--search-result-link-focus-background-color:#616161;--search-result-border-color:#aaa3;--search-color:#111;--search-error-code-background-color:#484848;--search-results-alias-color:#fff;--search-results-grey-color:#ccc;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#252525;--search-tab-button-not-selected-background:#252525;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#353535;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ab8ac1;--code-highlight-kw-2-color:#769acb;--code-highlight-lifetime-color:#d97f26;--code-highlight-prelude-color:#769acb;--code-highlight-prelude-val-color:#ee6868;--code-highlight-number-color:#83a300;--code-highlight-string-color:#83a300;--code-highlight-literal-color:#ee6868;--code-highlight-attribute-color:#ee6868;--code-highlight-self-color:#ee6868;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8d8d8b;--code-highlight-doc-comment-color:#8ca375;--src-line-numbers-span-color:#3b91e2;--src-line-number-highlighted-background-color:#0a042f;--test-arrow-color:#dedede;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#dedede;--test-arrow-hover-background-color:#4e8bca;--target-background-color:#494a3d;--target-border-color:#bb7410;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);--crate-search-div-hover-filter:invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);--crate-search-hover-border:#2196f3;--src-sidebar-background-selected:#333;--src-sidebar-background-hover:#444;--table-alt-row-background-color:#2a2a2a;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(53,53,53,1);--scrape-example-code-wrapper-background-end:rgba(53,53,53,0);--sidebar-resizer-hover:hsl(207,30%,54%);--sidebar-resizer-active:hsl(207,90%,54%);}} \ No newline at end of file diff --git a/static.files/rust-logo-151179464ae7ed46.svg b/static.files/rust-logo-151179464ae7ed46.svg new file mode 100644 index 00000000..62424d8f --- /dev/null +++ b/static.files/rust-logo-151179464ae7ed46.svg @@ -0,0 +1,61 @@ + + + diff --git a/static.files/rustdoc-5bc39a1768837dd0.css b/static.files/rustdoc-5bc39a1768837dd0.css new file mode 100644 index 00000000..175164ef --- /dev/null +++ b/static.files/rustdoc-5bc39a1768837dd0.css @@ -0,0 +1,24 @@ + :root{--nav-sub-mobile-padding:8px;--search-typename-width:6.75rem;--desktop-sidebar-width:200px;--src-sidebar-width:300px;--desktop-sidebar-z-index:100;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:400;src:local('Fira Sans'),url("FiraSans-Regular-018c141bf0843ffd.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:500;src:local('Fira Sans Medium'),url("FiraSans-Medium-8f9a781e4970d388.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:400;src:local('Source Serif 4'),url("SourceSerif4-Regular-46f98efaafac5295.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:italic;font-weight:400;src:local('Source Serif 4 Italic'),url("SourceSerif4-It-acdfaf1a8af734b1.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:700;src:local('Source Serif 4 Bold'),url("SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:400;src:url("SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:italic;font-weight:400;src:url("SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:600;src:url("SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'NanumBarunGothic';src:url("NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2") format("woff2");font-display:swap;unicode-range:U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF;}*{box-sizing:border-box;}body{font:1rem/1.5 "Source Serif 4",NanumBarunGothic,serif;margin:0;position:relative;overflow-wrap:break-word;overflow-wrap:anywhere;font-feature-settings:"kern","liga";background-color:var(--main-background-color);color:var(--main-color);}h1{font-size:1.5rem;}h2{font-size:1.375rem;}h3{font-size:1.25rem;}h1,h2,h3,h4,h5,h6{font-weight:500;}h1,h2,h3,h4{margin:25px 0 15px 0;padding-bottom:6px;}.docblock h3,.docblock h4,h5,h6{margin:15px 0 5px 0;}.docblock>h2:first-child,.docblock>h3:first-child,.docblock>h4:first-child,.docblock>h5:first-child,.docblock>h6:first-child{margin-top:0;}.main-heading h1{margin:0;padding:0;flex-grow:1;overflow-wrap:break-word;overflow-wrap:anywhere;}.main-heading{display:flex;flex-wrap:wrap;padding-bottom:6px;margin-bottom:15px;}.content h2,.top-doc .docblock>h3,.top-doc .docblock>h4{border-bottom:1px solid var(--headings-border-bottom-color);}h1,h2{line-height:1.25;padding-top:3px;padding-bottom:9px;}h3.code-header{font-size:1.125rem;}h4.code-header{font-size:1rem;}.code-header{font-weight:600;margin:0;padding:0;white-space:pre-wrap;}#crate-search,h1,h2,h3,h4,h5,h6,.sidebar,.mobile-topbar,.search-input,.search-results .result-name,.item-name>a,.out-of-band,span.since,a.src,#help-button>a,summary.hideme,.scraped-example-list,ul.all-items{font-family:"Fira Sans",Arial,NanumBarunGothic,sans-serif;}#toggle-all-docs,a.anchor,.section-header a,#src-sidebar a,.rust a,.sidebar h2 a,.sidebar h3 a,.mobile-topbar h2 a,h1 a,.search-results a,.stab,.result-name i{color:var(--main-color);}span.enum,a.enum,span.struct,a.struct,span.union,a.union,span.primitive,a.primitive,span.type,a.type,span.foreigntype,a.foreigntype{color:var(--type-link-color);}span.trait,a.trait,span.traitalias,a.traitalias{color:var(--trait-link-color);}span.associatedtype,a.associatedtype,span.constant,a.constant,span.static,a.static{color:var(--assoc-item-link-color);}span.fn,a.fn,span.method,a.method,span.tymethod,a.tymethod{color:var(--function-link-color);}span.attr,a.attr,span.derive,a.derive,span.macro,a.macro{color:var(--macro-link-color);}span.mod,a.mod{color:var(--mod-link-color);}span.keyword,a.keyword{color:var(--keyword-link-color);}a{color:var(--link-color);text-decoration:none;}ol,ul{padding-left:24px;}ul ul,ol ul,ul ol,ol ol{margin-bottom:.625em;}p,.docblock>.warning{margin:0 0 .75em 0;}p:last-child,.docblock>.warning:last-child{margin:0;}button{padding:1px 6px;cursor:pointer;}button#toggle-all-docs{padding:0;background:none;border:none;-webkit-appearance:none;opacity:1;}.rustdoc{display:flex;flex-direction:row;flex-wrap:nowrap;}main{position:relative;flex-grow:1;padding:10px 15px 40px 45px;min-width:0;}.src main{padding:15px;}.width-limiter{max-width:960px;margin-right:auto;}details:not(.toggle) summary{margin-bottom:.6em;}code,pre,a.test-arrow,.code-header{font-family:"Source Code Pro",monospace;}.docblock code,.docblock-short code{border-radius:3px;padding:0 0.125em;}.docblock pre code,.docblock-short pre code{padding:0;}pre{padding:14px;line-height:1.5;}pre.item-decl{overflow-x:auto;}.item-decl .type-contents-toggle{contain:initial;}.src .content pre{padding:20px;}.rustdoc.src .example-wrap pre.src-line-numbers{padding:20px 0 20px 4px;}img{max-width:100%;}.logo-container{line-height:0;display:block;}.rust-logo{filter:var(--rust-logo-filter);}.sidebar{font-size:0.875rem;flex:0 0 var(--desktop-sidebar-width);width:var(--desktop-sidebar-width);overflow-y:scroll;overscroll-behavior:contain;position:sticky;height:100vh;top:0;left:0;z-index:var(--desktop-sidebar-z-index);}.rustdoc.src .sidebar{flex-basis:50px;width:50px;border-right:1px solid;overflow-x:hidden;overflow-y:hidden;}.hide-sidebar .sidebar,.hide-sidebar .sidebar-resizer{display:none;}.sidebar-resizer{touch-action:none;width:9px;cursor:col-resize;z-index:calc(var(--desktop-sidebar-z-index) + 1);position:fixed;height:100%;left:calc(var(--desktop-sidebar-width) + 1px);}.rustdoc.src .sidebar-resizer{left:49px;}.src-sidebar-expanded .src .sidebar-resizer{left:var(--src-sidebar-width);}.sidebar-resizing{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;}.sidebar-resizing*{cursor:col-resize !important;}.sidebar-resizing .sidebar{position:fixed;}.sidebar-resizing>body{padding-left:var(--resizing-sidebar-width);}.sidebar-resizer:hover,.sidebar-resizer:active,.sidebar-resizer:focus,.sidebar-resizer.active{width:10px;margin:0;left:var(--desktop-sidebar-width);border-left:solid 1px var(--sidebar-resizer-hover);}.src-sidebar-expanded .rustdoc.src .sidebar-resizer:hover,.src-sidebar-expanded .rustdoc.src .sidebar-resizer:active,.src-sidebar-expanded .rustdoc.src .sidebar-resizer:focus,.src-sidebar-expanded .rustdoc.src .sidebar-resizer.active{left:calc(var(--src-sidebar-width) - 1px);}@media (pointer:coarse){.sidebar-resizer{display:none !important;}}.sidebar-resizer.active{padding:0 140px;width:2px;margin-left:-140px;border-left:none;}.sidebar-resizer.active:before{border-left:solid 2px var(--sidebar-resizer-active);display:block;height:100%;content:"";}.sidebar,.mobile-topbar,.sidebar-menu-toggle,#src-sidebar{background-color:var(--sidebar-background-color);}.src .sidebar>*{visibility:hidden;}.src-sidebar-expanded .src .sidebar{overflow-y:auto;flex-basis:var(--src-sidebar-width);width:var(--src-sidebar-width);}.src-sidebar-expanded .src .sidebar>*{visibility:visible;}#all-types{margin-top:1em;}*{scrollbar-width:initial;scrollbar-color:var(--scrollbar-color);}.sidebar{scrollbar-width:thin;scrollbar-color:var(--scrollbar-color);}::-webkit-scrollbar{width:12px;}.sidebar::-webkit-scrollbar{width:8px;}::-webkit-scrollbar-track{-webkit-box-shadow:inset 0;background-color:var(--scrollbar-track-background-color);}.sidebar::-webkit-scrollbar-track{background-color:var(--scrollbar-track-background-color);}::-webkit-scrollbar-thumb,.sidebar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-background-color);}.hidden{display:none !important;}.logo-container>img{height:48px;width:48px;}ul.block,.block li{padding:0;margin:0;list-style:none;}.sidebar-elems a,.sidebar>h2 a{display:block;padding:0.25rem;margin-left:-0.25rem;margin-right:0.25rem;}.sidebar h2{overflow-wrap:anywhere;padding:0;margin:0.7rem 0;}.sidebar h3{font-size:1.125rem;padding:0;margin:0;}.sidebar-elems,.sidebar>.version,.sidebar>h2{padding-left:24px;}.sidebar a{color:var(--sidebar-link-color);}.sidebar .current,.sidebar .current a,.sidebar-crate a.logo-container:hover+h2 a,.sidebar a:hover:not(.logo-container){background-color:var(--sidebar-current-link-background-color);}.sidebar-elems .block{margin-bottom:2em;}.sidebar-elems .block li a{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;}.sidebar-crate{display:flex;align-items:center;justify-content:center;margin:14px 32px 1rem;row-gap:10px;column-gap:32px;flex-wrap:wrap;}.sidebar-crate h2{flex-grow:1;margin:0 -8px;align-self:start;}.sidebar-crate .logo-container{margin:0 -16px 0 -16px;text-align:center;}.sidebar-crate h2 a{display:block;margin:0 calc(-24px + 0.25rem) 0 -0.2rem;padding:calc((16px - 0.57rem ) / 2 ) 0.25rem;padding-left:0.2rem;}.sidebar-crate h2 .version{display:block;font-weight:normal;font-size:1rem;overflow-wrap:break-word;}.sidebar-crate+.version{margin-top:-1rem;margin-bottom:1rem;}.mobile-topbar{display:none;}.rustdoc .example-wrap{display:flex;position:relative;margin-bottom:10px;}.rustdoc .example-wrap:last-child{margin-bottom:0px;}.rustdoc .example-wrap pre{margin:0;flex-grow:1;}.rustdoc:not(.src) .example-wrap pre{overflow:auto hidden;}.rustdoc .example-wrap pre.example-line-numbers,.rustdoc .example-wrap pre.src-line-numbers{flex-grow:0;min-width:fit-content;overflow:initial;text-align:right;-webkit-user-select:none;user-select:none;padding:14px 8px;color:var(--src-line-numbers-span-color);}.rustdoc .example-wrap pre.src-line-numbers{padding:14px 0;}.src-line-numbers a,.src-line-numbers span{color:var(--src-line-numbers-span-color);padding:0 8px;}.src-line-numbers :target{background-color:transparent;border-right:none;padding:0 8px;}.src-line-numbers .line-highlighted{background-color:var(--src-line-number-highlighted-background-color);}.search-loading{text-align:center;}.docblock-short{overflow-wrap:break-word;overflow-wrap:anywhere;}.docblock :not(pre)>code,.docblock-short code{white-space:pre-wrap;}.top-doc .docblock h2{font-size:1.375rem;}.top-doc .docblock h3{font-size:1.25rem;}.top-doc .docblock h4,.top-doc .docblock h5{font-size:1.125rem;}.top-doc .docblock h6{font-size:1rem;}.docblock h5{font-size:1rem;}.docblock h6{font-size:0.875rem;}.docblock{margin-left:24px;position:relative;}.docblock>:not(.more-examples-toggle):not(.example-wrap){max-width:100%;overflow-x:auto;}.out-of-band{flex-grow:0;font-size:1.125rem;}.docblock code,.docblock-short code,pre,.rustdoc.src .example-wrap{background-color:var(--code-block-background-color);}#main-content{position:relative;}.docblock table{margin:.5em 0;border-collapse:collapse;}.docblock table td,.docblock table th{padding:.5em;border:1px solid var(--border-color);}.docblock table tbody tr:nth-child(2n){background:var(--table-alt-row-background-color);}div.where{white-space:pre-wrap;font-size:0.875rem;}.item-info{display:block;margin-left:24px;}.item-info code{font-size:0.875rem;}#main-content>.item-info{margin-left:0;}nav.sub{flex-grow:1;flex-flow:row nowrap;margin:4px 0 25px 0;display:flex;align-items:center;}.search-form{position:relative;display:flex;height:34px;flex-grow:1;}.src nav.sub{margin:0 0 15px 0;}.section-header{display:block;position:relative;}.section-header:hover>.anchor,.impl:hover>.anchor,.trait-impl:hover>.anchor,.variant:hover>.anchor{display:initial;}.anchor{display:none;position:absolute;left:-0.5em;background:none !important;}.anchor.field{left:-5px;}.section-header>.anchor{left:-15px;padding-right:8px;}h2.section-header>.anchor{padding-right:6px;}a.doc-anchor{color:var(--main-color);display:none;position:absolute;left:-17px;padding-right:5px;padding-left:3px;}*:hover>.doc-anchor{display:block;}.top-doc>.docblock>*:first-child>.doc-anchor{display:none !important;}.main-heading a:hover,.example-wrap .rust a:hover,.all-items a:hover,.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover:not(.doc-anchor),.docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,.item-info a{text-decoration:underline;}.crate.block li.current a{font-weight:500;}table,.item-table{overflow-wrap:break-word;}.item-table{display:table;padding:0;margin:0;}.item-table>li{display:table-row;}.item-table>li>div{display:table-cell;}.item-table>li>.item-name{padding-right:1.25rem;}.search-results-title{margin-top:0;white-space:nowrap;display:flex;align-items:baseline;}#crate-search-div{position:relative;min-width:5em;}#crate-search{min-width:115px;padding:0 23px 0 4px;max-width:100%;text-overflow:ellipsis;border:1px solid var(--border-color);border-radius:4px;outline:none;cursor:pointer;-moz-appearance:none;-webkit-appearance:none;text-indent:0.01px;background-color:var(--main-background-color);color:inherit;line-height:1.5;font-weight:500;}#crate-search:hover,#crate-search:focus{border-color:var(--crate-search-hover-border);}#crate-search-div::after{pointer-events:none;width:100%;height:100%;position:absolute;top:0;left:0;content:"";background-repeat:no-repeat;background-size:20px;background-position:calc(100% - 2px) 56%;background-image:url('data:image/svg+xml, \ + ');filter:var(--crate-search-div-filter);}#crate-search-div:hover::after,#crate-search-div:focus-within::after{filter:var(--crate-search-div-hover-filter);}#crate-search>option{font-size:1rem;}.search-input{-webkit-appearance:none;outline:none;border:1px solid var(--border-color);border-radius:2px;padding:8px;font-size:1rem;flex-grow:1;background-color:var(--button-background-color);color:var(--search-color);}.search-input:focus{border-color:var(--search-input-focused-border-color);}.search-results{display:none;}.search-results.active{display:block;}.search-results>a{display:flex;margin-left:2px;margin-right:2px;border-bottom:1px solid var(--search-result-border-color);gap:1em;}.search-results>a>div.desc{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;flex:2;}.search-results a:hover,.search-results a:focus{background-color:var(--search-result-link-focus-background-color);}.search-results .result-name{display:flex;align-items:center;justify-content:start;flex:3;}.search-results .result-name .alias{color:var(--search-results-alias-color);}.search-results .result-name .grey{color:var(--search-results-grey-color);}.search-results .result-name .typename{color:var(--search-results-grey-color);font-size:0.875rem;width:var(--search-typename-width);}.search-results .result-name .path{word-break:break-all;max-width:calc(100% - var(--search-typename-width));display:inline-block;}.search-results .result-name .path>*{display:inline;}.popover{position:absolute;top:100%;right:0;z-index:calc(var(--desktop-sidebar-z-index) + 1);margin-top:7px;border-radius:3px;border:1px solid var(--border-color);background-color:var(--main-background-color);color:var(--main-color);--popover-arrow-offset:11px;}.popover::before{content:'';position:absolute;right:var(--popover-arrow-offset);border:solid var(--border-color);border-width:1px 1px 0 0;background-color:var(--main-background-color);padding:4px;transform:rotate(-45deg);top:-5px;}.setting-line{margin:1.2em 0.6em;}.setting-radio input,.setting-check input{margin-right:0.3em;height:1.2rem;width:1.2rem;border:2px solid var(--settings-input-border-color);outline:none;-webkit-appearance:none;cursor:pointer;}.setting-radio input{border-radius:50%;}.setting-radio span,.setting-check span{padding-bottom:1px;}.setting-radio{margin-top:0.1em;margin-bottom:0.1em;min-width:3.8em;padding:0.3em;display:inline-flex;align-items:center;cursor:pointer;}.setting-radio+.setting-radio{margin-left:0.5em;}.setting-check{margin-right:20px;display:flex;align-items:center;cursor:pointer;}.setting-radio input:checked{box-shadow:inset 0 0 0 3px var(--main-background-color);background-color:var(--settings-input-color);}.setting-check input:checked{background-color:var(--settings-input-color);border-width:1px;content:url('data:image/svg+xml,\ + \ + ');}.setting-radio input:focus,.setting-check input:focus{box-shadow:0 0 1px 1px var(--settings-input-color);}.setting-radio input:checked:focus{box-shadow:inset 0 0 0 3px var(--main-background-color),0 0 2px 2px var(--settings-input-color);}.setting-radio input:hover,.setting-check input:hover{border-color:var(--settings-input-color) !important;}#help.popover{max-width:600px;--popover-arrow-offset:48px;}#help dt{float:left;clear:left;margin-right:0.5rem;}#help span.top,#help span.bottom{text-align:center;display:block;font-size:1.125rem;}#help span.top{margin:10px 0;border-bottom:1px solid var(--border-color);padding-bottom:4px;margin-bottom:6px;}#help span.bottom{clear:both;border-top:1px solid var(--border-color);}.side-by-side>div{width:50%;float:left;padding:0 20px 20px 17px;}.item-info .stab{display:block;padding:3px;margin-bottom:5px;}.item-name .stab{margin-left:0.3125em;}.stab{padding:0 2px;font-size:0.875rem;font-weight:normal;color:var(--main-color);background-color:var(--stab-background-color);width:fit-content;white-space:pre-wrap;border-radius:3px;display:inline;vertical-align:baseline;}.stab.portability>code{background:none;color:var(--stab-code-color);}.stab .emoji,.item-info .stab::before{font-size:1.25rem;}.stab .emoji{margin-right:0.3rem;}.item-info .stab::before{content:"\0";width:0;display:inline-block;color:transparent;}.emoji{text-shadow:1px 0 0 black,-1px 0 0 black,0 1px 0 black,0 -1px 0 black;}.since{font-weight:normal;font-size:initial;}.rightside{padding-left:12px;float:right;}.rightside:not(a),.out-of-band{color:var(--right-side-color);}pre.rust{tab-size:4;-moz-tab-size:4;}pre.rust .kw{color:var(--code-highlight-kw-color);}pre.rust .kw-2{color:var(--code-highlight-kw-2-color);}pre.rust .lifetime{color:var(--code-highlight-lifetime-color);}pre.rust .prelude-ty{color:var(--code-highlight-prelude-color);}pre.rust .prelude-val{color:var(--code-highlight-prelude-val-color);}pre.rust .string{color:var(--code-highlight-string-color);}pre.rust .number{color:var(--code-highlight-number-color);}pre.rust .bool-val{color:var(--code-highlight-literal-color);}pre.rust .self{color:var(--code-highlight-self-color);}pre.rust .attr{color:var(--code-highlight-attribute-color);}pre.rust .macro,pre.rust .macro-nonterminal{color:var(--code-highlight-macro-color);}pre.rust .question-mark{font-weight:bold;color:var(--code-highlight-question-mark-color);}pre.rust .comment{color:var(--code-highlight-comment-color);}pre.rust .doccomment{color:var(--code-highlight-doc-comment-color);}.rustdoc.src .example-wrap pre.rust a{background:var(--codeblock-link-background);}.example-wrap.compile_fail,.example-wrap.should_panic{border-left:2px solid var(--codeblock-error-color);}.ignore.example-wrap{border-left:2px solid var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover,.example-wrap.should_panic:hover{border-left:2px solid var(--codeblock-error-hover-color);}.example-wrap.ignore:hover{border-left:2px solid var(--codeblock-ignore-hover-color);}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip{color:var(--codeblock-error-color);}.example-wrap.ignore .tooltip{color:var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover .tooltip,.example-wrap.should_panic:hover .tooltip{color:var(--codeblock-error-hover-color);}.example-wrap.ignore:hover .tooltip{color:var(--codeblock-ignore-hover-color);}.example-wrap .tooltip{position:absolute;display:block;left:-25px;top:5px;margin:0;line-height:1;}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip,.example-wrap.ignore .tooltip{font-weight:bold;font-size:1.25rem;}.content .docblock .warning{border-left:2px solid var(--warning-border-color);padding:14px;position:relative;overflow-x:visible !important;}.content .docblock .warning::before{color:var(--warning-border-color);content:"ⓘ";position:absolute;left:-25px;top:5px;font-weight:bold;font-size:1.25rem;}.top-doc>.docblock>.warning:first-child::before{top:20px;}a.test-arrow{visibility:hidden;position:absolute;padding:5px 10px 5px 10px;border-radius:5px;font-size:1.375rem;top:5px;right:5px;z-index:1;color:var(--test-arrow-color);background-color:var(--test-arrow-background-color);}a.test-arrow:hover{color:var(--test-arrow-hover-color);background-color:var(--test-arrow-hover-background-color);}.example-wrap:hover .test-arrow{visibility:visible;}.code-attribute{font-weight:300;color:var(--code-attribute-color);}.item-spacer{width:100%;height:12px;display:block;}.out-of-band>span.since{font-size:1.25rem;}.sub-variant h4{font-size:1rem;font-weight:400;margin-top:0;margin-bottom:0;}.sub-variant{margin-left:24px;margin-bottom:40px;}.sub-variant>.sub-variant-field{margin-left:24px;}:target{padding-right:3px;background-color:var(--target-background-color);border-right:3px solid var(--target-border-color);}.code-header a.tooltip{color:inherit;margin-right:15px;position:relative;}.code-header a.tooltip:hover{color:var(--link-color);}a.tooltip:hover::after{position:absolute;top:calc(100% - 10px);left:-15px;right:-15px;height:20px;content:"\00a0";}.fade-out{opacity:0;transition:opacity 0.45s cubic-bezier(0,0,0.1,1.0);}.popover.tooltip .content{margin:0.25em 0.5em;}.popover.tooltip .content pre,.popover.tooltip .content code{background:transparent;margin:0;padding:0;font-size:1.25rem;white-space:pre-wrap;}.popover.tooltip .content>h3:first-child{margin:0 0 5px 0;}.search-failed{text-align:center;margin-top:20px;display:none;}.search-failed.active{display:block;}.search-failed>ul{text-align:left;max-width:570px;margin-left:auto;margin-right:auto;}#search-tabs{display:flex;flex-direction:row;gap:1px;margin-bottom:4px;}#search-tabs button{text-align:center;font-size:1.125rem;border:0;border-top:2px solid;flex:1;line-height:1.5;color:inherit;}#search-tabs button:not(.selected){background-color:var(--search-tab-button-not-selected-background);border-top-color:var(--search-tab-button-not-selected-border-top-color);}#search-tabs button:hover,#search-tabs button.selected{background-color:var(--search-tab-button-selected-background);border-top-color:var(--search-tab-button-selected-border-top-color);}#search-tabs .count{font-size:1rem;font-variant-numeric:tabular-nums;color:var(--search-tab-title-count-color);}#search .error code{border-radius:3px;background-color:var(--search-error-code-background-color);}.search-corrections{font-weight:normal;}#src-sidebar{width:100%;overflow:auto;}#src-sidebar div.files>a:hover,details.dir-entry summary:hover,#src-sidebar div.files>a:focus,details.dir-entry summary:focus{background-color:var(--src-sidebar-background-hover);}#src-sidebar div.files>a.selected{background-color:var(--src-sidebar-background-selected);}.src-sidebar-title{position:sticky;top:0;display:flex;padding:8px 8px 0 48px;margin-bottom:7px;background:var(--sidebar-background-color);border-bottom:1px solid var(--border-color);}#settings-menu,#help-button{margin-left:4px;display:flex;}#sidebar-button{display:none;line-height:0;}.hide-sidebar #sidebar-button,.src #sidebar-button{display:flex;margin-right:4px;position:fixed;left:6px;height:34px;width:34px;background-color:var(--main-background-color);z-index:1;}.src #sidebar-button{left:8px;z-index:calc(var(--desktop-sidebar-z-index) + 1);}.hide-sidebar .src #sidebar-button{position:static;}#settings-menu>a,#help-button>a,#sidebar-button>a{display:flex;align-items:center;justify-content:center;background-color:var(--button-background-color);border:1px solid var(--border-color);border-radius:2px;color:var(--settings-button-color);font-size:20px;width:33px;}#settings-menu>a:hover,#settings-menu>a:focus,#help-button>a:hover,#help-button>a:focus,#sidebar-button>a:hover,#sidebar-button>a:focus{border-color:var(--settings-button-border-focus);}#sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');width:22px;height:22px;}#copy-path{color:var(--copy-path-button-color);background:var(--main-background-color);height:34px;margin-left:10px;padding:0;padding-left:2px;border:0;width:33px;}#copy-path>img{filter:var(--copy-path-img-filter);}#copy-path:hover>img{filter:var(--copy-path-img-hover-filter);}@keyframes rotating{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}#settings-menu.rotate>a img{animation:rotating 2s linear infinite;}kbd{display:inline-block;padding:3px 5px;font:15px monospace;line-height:10px;vertical-align:middle;border:solid 1px var(--border-color);border-radius:3px;color:var(--kbd-color);background-color:var(--kbd-background);box-shadow:inset 0 -1px 0 var(--kbd-box-shadow-color);}ul.all-items>li{list-style:none;}details.dir-entry{padding-left:4px;}details.dir-entry>summary{margin:0 0 0 -4px;padding:0 0 0 4px;cursor:pointer;}details.dir-entry div.folders,details.dir-entry div.files{padding-left:23px;}details.dir-entry a{display:block;}details.toggle{contain:layout;position:relative;}details.toggle>summary.hideme{cursor:pointer;font-size:1rem;}details.toggle>summary{list-style:none;outline:none;}details.toggle>summary::-webkit-details-marker,details.toggle>summary::marker{display:none;}details.toggle>summary.hideme>span{margin-left:9px;}details.toggle>summary::before{background:url('data:image/svg+xml,') no-repeat top left;content:"";cursor:pointer;width:16px;height:16px;display:inline-block;vertical-align:middle;opacity:.5;filter:var(--toggle-filter);}details.toggle>summary.hideme>span,.more-examples-toggle summary,.more-examples-toggle .hide-more{color:var(--toggles-color);}details.toggle>summary::after{content:"Expand";overflow:hidden;width:0;height:0;position:absolute;}details.toggle>summary.hideme::after{content:"";}details.toggle>summary:focus::before,details.toggle>summary:hover::before{opacity:1;}details.toggle>summary:focus-visible::before{outline:1px dotted #000;outline-offset:1px;}details.non-exhaustive{margin-bottom:8px;}details.toggle>summary.hideme::before{position:relative;}details.toggle>summary:not(.hideme)::before{position:absolute;left:-24px;top:4px;}.impl-items>details.toggle>summary:not(.hideme)::before{position:absolute;left:-24px;}details.toggle[open] >summary.hideme{position:absolute;}details.toggle[open] >summary.hideme>span{display:none;}details.toggle[open] >summary::before{background:url('data:image/svg+xml,') no-repeat top left;}details.toggle[open] >summary::after{content:"Collapse";}.docblock summary>*{display:inline-block;}.docblock>.example-wrap:first-child .tooltip{margin-top:16px;}.src #sidebar-button>a:before,.sidebar-menu-toggle:before{content:url('data:image/svg+xml,\ + ');opacity:0.75;}.sidebar-menu-toggle:hover:before,.sidebar-menu-toggle:active:before,.sidebar-menu-toggle:focus:before{opacity:1;}.src #sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');opacity:0.75;}@media (max-width:850px){#search-tabs .count{display:block;}}@media (max-width:700px){*[id]{scroll-margin-top:45px;}.rustdoc{display:block;}main{padding-left:15px;padding-top:0px;}.main-heading{flex-direction:column;}.out-of-band{text-align:left;margin-left:initial;padding:initial;}.out-of-band .since::before{content:"Since ";}.sidebar .logo-container,.sidebar .location,.sidebar-resizer{display:none;}.sidebar{position:fixed;top:45px;left:-1000px;z-index:11;height:calc(100vh - 45px);width:200px;}.src main,.rustdoc.src .sidebar{top:0;padding:0;height:100vh;border:0;}.src .search-form{margin-left:40px;}.hide-sidebar .search-form{margin-left:32px;}.hide-sidebar .src .search-form{margin-left:0;}.sidebar.shown,.src-sidebar-expanded .src .sidebar,.rustdoc:not(.src) .sidebar:focus-within{left:0;}.mobile-topbar h2{padding-bottom:0;margin:auto 0.5em auto auto;overflow:hidden;font-size:24px;}.mobile-topbar h2 a{display:block;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;}.mobile-topbar .logo-container>img{max-width:35px;max-height:35px;margin:5px 0 5px 20px;}.mobile-topbar{display:flex;flex-direction:row;position:sticky;z-index:10;font-size:2rem;height:45px;width:100%;left:0;top:0;}.hide-sidebar .mobile-topbar{display:none;}.sidebar-menu-toggle{width:45px;border:none;line-height:0;}.hide-sidebar .sidebar-menu-toggle{display:none;}.sidebar-elems{margin-top:1em;}.anchor{display:none !important;}#main-content>details.toggle>summary::before,#main-content>div>details.toggle>summary::before{left:-11px;}#copy-path,#help-button{display:none;}#sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');width:22px;height:22px;}.sidebar-menu-toggle:before{filter:var(--mobile-sidebar-menu-filter);}.sidebar-menu-toggle:hover{background:var(--main-background-color);}.item-table,.item-row,.item-table>li,.item-table>li>div,.search-results>a,.search-results>a>div{display:block;}.search-results>a{padding:5px 0px;}.search-results>a>div.desc,.item-table>li>div.desc{padding-left:2em;}.search-results .result-name{display:block;}.search-results .result-name .typename{width:initial;margin-right:0;}.search-results .result-name .typename,.search-results .result-name .path{display:inline;}.src-sidebar-expanded .src .sidebar{position:fixed;max-width:100vw;width:100vw;}.src .src-sidebar-title{padding-top:0;}details.toggle:not(.top-doc)>summary{margin-left:10px;}.impl-items>details.toggle>summary:not(.hideme)::before,#main-content>details.toggle:not(.top-doc)>summary::before,#main-content>div>details.toggle>summary::before{left:-11px;}.impl-items>.item-info{margin-left:34px;}.src nav.sub{margin:0;padding:var(--nav-sub-mobile-padding);}}@media (min-width:701px){.scraped-example-title{position:absolute;z-index:10;background:var(--main-background-color);bottom:8px;right:5px;padding:2px 4px;box-shadow:0 0 4px var(--main-background-color);}}@media print{nav.sidebar,nav.sub,.out-of-band,a.src,#copy-path,details.toggle[open] >summary::before,details.toggle>summary::before,details.toggle.top-doc>summary{display:none;}.docblock{margin-left:0;}main{padding:10px;}}@media (max-width:464px){.docblock{margin-left:12px;}.docblock code{overflow-wrap:break-word;overflow-wrap:anywhere;}nav.sub{flex-direction:column;}.search-form{align-self:stretch;}}.variant,.implementors-toggle>summary,.impl,#implementors-list>.docblock,.impl-items>section,.impl-items>.toggle>summary,.methods>section,.methods>.toggle>summary{margin-bottom:0.75em;}.variants>.docblock,.implementors-toggle>.docblock,.impl-items>.toggle[open]:not(:last-child),.methods>.toggle[open]:not(:last-child),.implementors-toggle[open]:not(:last-child){margin-bottom:2em;}#trait-implementations-list .impl-items>.toggle:not(:last-child),#synthetic-implementations-list .impl-items>.toggle:not(:last-child),#blanket-implementations-list .impl-items>.toggle:not(:last-child){margin-bottom:1em;}.scraped-example-list .scrape-help{margin-left:10px;padding:0 4px;font-weight:normal;font-size:12px;position:relative;bottom:1px;border:1px solid var(--scrape-example-help-border-color);border-radius:50px;color:var(--scrape-example-help-color);}.scraped-example-list .scrape-help:hover{border-color:var(--scrape-example-help-hover-border-color);color:var(--scrape-example-help-hover-color);}.scraped-example{position:relative;}.scraped-example .code-wrapper{position:relative;display:flex;flex-direction:row;flex-wrap:wrap;width:100%;}.scraped-example:not(.expanded) .code-wrapper{max-height:calc(1.5em * 5 + 10px);}.scraped-example:not(.expanded) .code-wrapper pre{overflow-y:hidden;padding-bottom:0;max-height:calc(1.5em * 5 + 10px);}.more-scraped-examples .scraped-example:not(.expanded) .code-wrapper,.more-scraped-examples .scraped-example:not(.expanded) .code-wrapper pre{max-height:calc(1.5em * 10 + 10px);}.scraped-example .code-wrapper .next,.scraped-example .code-wrapper .prev,.scraped-example .code-wrapper .expand{color:var(--main-color);position:absolute;top:0.25em;z-index:1;padding:0;background:none;border:none;-webkit-appearance:none;opacity:1;}.scraped-example .code-wrapper .prev{right:2.25em;}.scraped-example .code-wrapper .next{right:1.25em;}.scraped-example .code-wrapper .expand{right:0.25em;}.scraped-example:not(.expanded) .code-wrapper::before,.scraped-example:not(.expanded) .code-wrapper::after{content:" ";width:100%;height:5px;position:absolute;z-index:1;}.scraped-example:not(.expanded) .code-wrapper::before{top:0;background:linear-gradient(to bottom,var(--scrape-example-code-wrapper-background-start),var(--scrape-example-code-wrapper-background-end));}.scraped-example:not(.expanded) .code-wrapper::after{bottom:0;background:linear-gradient(to top,var(--scrape-example-code-wrapper-background-start),var(--scrape-example-code-wrapper-background-end));}.scraped-example .code-wrapper .example-wrap{width:100%;overflow-y:hidden;margin-bottom:0;}.scraped-example:not(.expanded) .code-wrapper .example-wrap{overflow-x:hidden;}.scraped-example .example-wrap .rust span.highlight{background:var(--scrape-example-code-line-highlight);}.scraped-example .example-wrap .rust span.highlight.focus{background:var(--scrape-example-code-line-highlight-focus);}.more-examples-toggle{max-width:calc(100% + 25px);margin-top:10px;margin-left:-25px;}.more-examples-toggle .hide-more{margin-left:25px;cursor:pointer;}.more-scraped-examples{margin-left:25px;position:relative;}.toggle-line{position:absolute;top:5px;bottom:0;right:calc(100% + 10px);padding:0 4px;cursor:pointer;}.toggle-line-inner{min-width:2px;height:100%;background:var(--scrape-example-toggle-line-background);}.toggle-line:hover .toggle-line-inner{background:var(--scrape-example-toggle-line-hover-background);}.more-scraped-examples .scraped-example,.example-links{margin-top:20px;}.more-scraped-examples .scraped-example:first-child{margin-top:5px;}.example-links ul{margin-bottom:0;}:root[data-theme="light"]{--main-background-color:white;--main-color:black;--settings-input-color:#2196f3;--settings-input-border-color:#717171;--settings-button-color:#000;--settings-button-border-focus:#717171;--sidebar-background-color:#f5f5f5;--sidebar-background-color-hover:#e0e0e0;--code-block-background-color:#f5f5f5;--scrollbar-track-background-color:#dcdcdc;--scrollbar-thumb-background-color:rgba(36,37,39,0.6);--scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;--headings-border-bottom-color:#ddd;--border-color:#e0e0e0;--button-background-color:#fff;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:none;--mobile-sidebar-menu-filter:none;--search-input-focused-border-color:#66afe9;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(35%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ad378a;--trait-link-color:#6e4fc9;--assoc-item-link-color:#3873ad;--function-link-color:#ad7c37;--macro-link-color:#068000;--keyword-link-color:#3873ad;--mod-link-color:#3873ad;--link-color:#3873ad;--sidebar-link-color:#356da4;--sidebar-current-link-background-color:#fff;--search-result-link-focus-background-color:#ccc;--search-result-border-color:#aaa3;--search-color:#000;--search-error-code-background-color:#d0cccc;--search-results-alias-color:#000;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#e6e6e6;--search-tab-button-not-selected-background:#e6e6e6;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#fff;--stab-background-color:#fff5d6;--stab-code-color:#000;--code-highlight-kw-color:#8959a8;--code-highlight-kw-2-color:#4271ae;--code-highlight-lifetime-color:#b76514;--code-highlight-prelude-color:#4271ae;--code-highlight-prelude-val-color:#c82829;--code-highlight-number-color:#718c00;--code-highlight-string-color:#718c00;--code-highlight-literal-color:#c82829;--code-highlight-attribute-color:#c82829;--code-highlight-self-color:#c82829;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8e908c;--code-highlight-doc-comment-color:#4d4d4c;--src-line-numbers-span-color:#c67e2d;--src-line-number-highlighted-background-color:#fdffd3;--test-arrow-color:#f5f5f5;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#f5f5f5;--test-arrow-hover-background-color:rgb(78,139,202);--target-background-color:#fdffd3;--target-border-color:#ad7c37;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:initial;--crate-search-div-filter:invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);--crate-search-div-hover-filter:invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);--crate-search-hover-border:#717171;--src-sidebar-background-selected:#fff;--src-sidebar-background-hover:#e0e0e0;--table-alt-row-background-color:#f5f5f5;--codeblock-link-background:#eee;--scrape-example-toggle-line-background:#ccc;--scrape-example-toggle-line-hover-background:#999;--scrape-example-code-line-highlight:#fcffd6;--scrape-example-code-line-highlight-focus:#f6fdb0;--scrape-example-help-border-color:#555;--scrape-example-help-color:#333;--scrape-example-help-hover-border-color:#000;--scrape-example-help-hover-color:#000;--scrape-example-code-wrapper-background-start:rgba(255,255,255,1);--scrape-example-code-wrapper-background-end:rgba(255,255,255,0);--sidebar-resizer-hover:hsl(207,90%,66%);--sidebar-resizer-active:hsl(207,90%,54%);}:root[data-theme="dark"]{--main-background-color:#353535;--main-color:#ddd;--settings-input-color:#2196f3;--settings-input-border-color:#999;--settings-button-color:#000;--settings-button-border-focus:#ffb900;--sidebar-background-color:#505050;--sidebar-background-color-hover:#676767;--code-block-background-color:#2A2A2A;--scrollbar-track-background-color:#717171;--scrollbar-thumb-background-color:rgba(32,34,37,.6);--scrollbar-color:rgba(32,34,37,.6) #5a5a5a;--headings-border-bottom-color:#d2d2d2;--border-color:#e0e0e0;--button-background-color:#f0f0f0;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#008dfd;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(65%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#2dbfb8;--trait-link-color:#b78cf2;--assoc-item-link-color:#d2991d;--function-link-color:#2bab63;--macro-link-color:#09bd00;--keyword-link-color:#d2991d;--mod-link-color:#d2991d;--link-color:#d2991d;--sidebar-link-color:#fdbf35;--sidebar-current-link-background-color:#444;--search-result-link-focus-background-color:#616161;--search-result-border-color:#aaa3;--search-color:#111;--search-error-code-background-color:#484848;--search-results-alias-color:#fff;--search-results-grey-color:#ccc;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#252525;--search-tab-button-not-selected-background:#252525;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#353535;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ab8ac1;--code-highlight-kw-2-color:#769acb;--code-highlight-lifetime-color:#d97f26;--code-highlight-prelude-color:#769acb;--code-highlight-prelude-val-color:#ee6868;--code-highlight-number-color:#83a300;--code-highlight-string-color:#83a300;--code-highlight-literal-color:#ee6868;--code-highlight-attribute-color:#ee6868;--code-highlight-self-color:#ee6868;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8d8d8b;--code-highlight-doc-comment-color:#8ca375;--src-line-numbers-span-color:#3b91e2;--src-line-number-highlighted-background-color:#0a042f;--test-arrow-color:#dedede;--test-arrow-background-color:rgba(78,139,202,0.2);--test-arrow-hover-color:#dedede;--test-arrow-hover-background-color:#4e8bca;--target-background-color:#494a3d;--target-border-color:#bb7410;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);--crate-search-div-hover-filter:invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);--crate-search-hover-border:#2196f3;--src-sidebar-background-selected:#333;--src-sidebar-background-hover:#444;--table-alt-row-background-color:#2a2a2a;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(53,53,53,1);--scrape-example-code-wrapper-background-end:rgba(53,53,53,0);--sidebar-resizer-hover:hsl(207,30%,54%);--sidebar-resizer-active:hsl(207,90%,54%);}:root[data-theme="ayu"]{--main-background-color:#0f1419;--main-color:#c5c5c5;--settings-input-color:#ffb454;--settings-input-border-color:#999;--settings-button-color:#fff;--settings-button-border-focus:#e0e0e0;--sidebar-background-color:#14191f;--sidebar-background-color-hover:rgba(70,70,70,0.33);--code-block-background-color:#191f26;--scrollbar-track-background-color:transparent;--scrollbar-thumb-background-color:#5c6773;--scrollbar-color:#5c6773 #24292f;--headings-border-bottom-color:#5c6773;--border-color:#5c6773;--button-background-color:#141920;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#5c6773;--copy-path-button-color:#fff;--copy-path-img-filter:invert(70%);--copy-path-img-hover-filter:invert(100%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ffa0a5;--trait-link-color:#39afd7;--assoc-item-link-color:#39afd7;--function-link-color:#fdd687;--macro-link-color:#a37acc;--keyword-link-color:#39afd7;--mod-link-color:#39afd7;--link-color:#39afd7;--sidebar-link-color:#53b1db;--sidebar-current-link-background-color:transparent;--search-result-link-focus-background-color:#3c3c3c;--search-result-border-color:#aaa3;--search-color:#fff;--search-error-code-background-color:#4f4c4c;--search-results-alias-color:#c5c5c5;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:none;--search-tab-button-not-selected-background:transparent !important;--search-tab-button-selected-border-top-color:none;--search-tab-button-selected-background:#141920 !important;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ff7733;--code-highlight-kw-2-color:#ff7733;--code-highlight-lifetime-color:#ff7733;--code-highlight-prelude-color:#69f2df;--code-highlight-prelude-val-color:#ff7733;--code-highlight-number-color:#b8cc52;--code-highlight-string-color:#b8cc52;--code-highlight-literal-color:#ff7733;--code-highlight-attribute-color:#e6e1cf;--code-highlight-self-color:#36a3d9;--code-highlight-macro-color:#a37acc;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#788797;--code-highlight-doc-comment-color:#a1ac88;--src-line-numbers-span-color:#5c6773;--src-line-number-highlighted-background-color:rgba(255,236,164,0.06);--test-arrow-color:#788797;--test-arrow-background-color:rgba(57,175,215,0.09);--test-arrow-hover-color:#c5c5c5;--test-arrow-hover-background-color:rgba(57,175,215,0.368);--target-background-color:rgba(255,236,164,0.06);--target-border-color:rgba(255,180,76,0.85);--kbd-color:#c5c5c5;--kbd-background:#314559;--kbd-box-shadow-color:#5c6773;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%);--crate-search-div-hover-filter:invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%);--crate-search-hover-border:#e0e0e0;--src-sidebar-background-selected:#14191f;--src-sidebar-background-hover:#14191f;--table-alt-row-background-color:#191f26;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(15,20,25,1);--scrape-example-code-wrapper-background-end:rgba(15,20,25,0);--sidebar-resizer-hover:hsl(34,50%,33%);--sidebar-resizer-active:hsl(34,100%,66%);}:root[data-theme="ayu"] h1,:root[data-theme="ayu"] h2,:root[data-theme="ayu"] h3,:root[data-theme="ayu"] h4,:where(:root[data-theme="ayu"]) h1 a,:root[data-theme="ayu"] .sidebar h2 a,:root[data-theme="ayu"] .sidebar h3 a{color:#fff;}:root[data-theme="ayu"] .docblock code{color:#ffb454;}:root[data-theme="ayu"] .docblock a>code{color:#39AFD7 !important;}:root[data-theme="ayu"] .code-header,:root[data-theme="ayu"] .docblock pre>code,:root[data-theme="ayu"] pre,:root[data-theme="ayu"] pre>code,:root[data-theme="ayu"] .item-info code,:root[data-theme="ayu"] .rustdoc.source .example-wrap{color:#e6e1cf;}:root[data-theme="ayu"] .sidebar .current,:root[data-theme="ayu"] .sidebar .current a,:root[data-theme="ayu"] .sidebar a:hover,:root[data-theme="ayu"] #src-sidebar div.files>a:hover,:root[data-theme="ayu"] details.dir-entry summary:hover,:root[data-theme="ayu"] #src-sidebar div.files>a:focus,:root[data-theme="ayu"] details.dir-entry summary:focus,:root[data-theme="ayu"] #src-sidebar div.files>a.selected{color:#ffb44c;}:root[data-theme="ayu"] .sidebar-elems .location{color:#ff7733;}:root[data-theme="ayu"] .src-line-numbers .line-highlighted{color:#708090;padding-right:7px;border-right:1px solid #ffb44c;}:root[data-theme="ayu"] .search-results a:hover,:root[data-theme="ayu"] .search-results a:focus{color:#fff !important;background-color:#3c3c3c;}:root[data-theme="ayu"] .search-results a{color:#0096cf;}:root[data-theme="ayu"] .search-results a div.desc{color:#c5c5c5;}:root[data-theme="ayu"] .result-name .primitive>i,:root[data-theme="ayu"] .result-name .keyword>i{color:#788797;}:root[data-theme="ayu"] #search-tabs>button.selected{border-bottom:1px solid #ffb44c !important;border-top:none;}:root[data-theme="ayu"] #search-tabs>button:not(.selected){border:none;background-color:transparent !important;}:root[data-theme="ayu"] #search-tabs>button:hover{border-bottom:1px solid rgba(242,151,24,0.3);}:root[data-theme="ayu"] #settings-menu>a img,:root[data-theme="ayu"] #sidebar-button>a:before{filter:invert(100);} \ No newline at end of file diff --git a/static.files/scrape-examples-ef1e698c1d417c0c.js b/static.files/scrape-examples-ef1e698c1d417c0c.js new file mode 100644 index 00000000..ba830e37 --- /dev/null +++ b/static.files/scrape-examples-ef1e698c1d417c0c.js @@ -0,0 +1 @@ +"use strict";(function(){const DEFAULT_MAX_LINES=5;const HIDDEN_MAX_LINES=10;function scrollToLoc(elt,loc,isHidden){const lines=elt.querySelector(".src-line-numbers");let scrollOffset;const maxLines=isHidden?HIDDEN_MAX_LINES:DEFAULT_MAX_LINES;if(loc[1]-loc[0]>maxLines){const line=Math.max(0,loc[0]-1);scrollOffset=lines.children[line].offsetTop}else{const wrapper=elt.querySelector(".code-wrapper");const halfHeight=wrapper.offsetHeight/2;const offsetTop=lines.children[loc[0]].offsetTop;const lastLine=lines.children[loc[1]];const offsetBot=lastLine.offsetTop+lastLine.offsetHeight;const offsetMid=(offsetTop+offsetBot)/2;scrollOffset=offsetMid-halfHeight}lines.scrollTo(0,scrollOffset);elt.querySelector(".rust").scrollTo(0,scrollOffset)}function updateScrapedExample(example,isHidden){const locs=JSON.parse(example.attributes.getNamedItem("data-locs").textContent);let locIndex=0;const highlights=Array.prototype.slice.call(example.querySelectorAll(".highlight"));const link=example.querySelector(".scraped-example-title a");if(locs.length>1){const onChangeLoc=changeIndex=>{removeClass(highlights[locIndex],"focus");changeIndex();scrollToLoc(example,locs[locIndex][0],isHidden);addClass(highlights[locIndex],"focus");const url=locs[locIndex][1];const title=locs[locIndex][2];link.href=url;link.innerHTML=title};example.querySelector(".prev").addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex-1+locs.length)%locs.length})});example.querySelector(".next").addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex+1)%locs.length})})}const expandButton=example.querySelector(".expand");if(expandButton){expandButton.addEventListener("click",()=>{if(hasClass(example,"expanded")){removeClass(example,"expanded");scrollToLoc(example,locs[0][0],isHidden)}else{addClass(example,"expanded")}})}scrollToLoc(example,locs[0][0],isHidden)}const firstExamples=document.querySelectorAll(".scraped-example-list > .scraped-example");onEachLazy(firstExamples,el=>updateScrapedExample(el,false));onEachLazy(document.querySelectorAll(".more-examples-toggle"),toggle=>{onEachLazy(toggle.querySelectorAll(".toggle-line, .hide-more"),button=>{button.addEventListener("click",()=>{toggle.open=false})});const moreExamples=toggle.querySelectorAll(".scraped-example");toggle.querySelector("summary").addEventListener("click",()=>{setTimeout(()=>{onEachLazy(moreExamples,el=>updateScrapedExample(el,true))})},{once:true})})})() \ No newline at end of file diff --git a/static.files/search-dd67cee4cfa65049.js b/static.files/search-dd67cee4cfa65049.js new file mode 100644 index 00000000..ef8bf865 --- /dev/null +++ b/static.files/search-dd67cee4cfa65049.js @@ -0,0 +1,5 @@ +"use strict";if(!Array.prototype.toSpliced){Array.prototype.toSpliced=function(){const me=this.slice();Array.prototype.splice.apply(me,arguments);return me}}(function(){const itemTypes=["keyword","primitive","mod","externcrate","import","struct","enum","fn","type","static","trait","impl","tymethod","method","structfield","variant","macro","associatedtype","constant","associatedconstant","union","foreigntype","existential","attr","derive","traitalias","generic",];const longItemTypes=["keyword","primitive type","module","extern crate","re-export","struct","enum","function","type alias","static","trait","","trait method","method","struct field","enum variant","macro","assoc type","constant","assoc const","union","foreign type","existential type","attribute macro","derive macro","trait alias",];const TY_GENERIC=itemTypes.indexOf("generic");const ROOT_PATH=typeof window!=="undefined"?window.rootPath:"../";function printTab(nb){let iter=0;let foundCurrentTab=false;let foundCurrentResultSet=false;onEachLazy(document.getElementById("search-tabs").childNodes,elem=>{if(nb===iter){addClass(elem,"selected");foundCurrentTab=true}else{removeClass(elem,"selected")}iter+=1});const isTypeSearch=(nb>0||iter===1);iter=0;onEachLazy(document.getElementById("results").childNodes,elem=>{if(nb===iter){addClass(elem,"active");foundCurrentResultSet=true}else{removeClass(elem,"active")}iter+=1});if(foundCurrentTab&&foundCurrentResultSet){searchState.currentTab=nb;const correctionsElem=document.getElementsByClassName("search-corrections");if(isTypeSearch){removeClass(correctionsElem[0],"hidden")}else{addClass(correctionsElem[0],"hidden")}}else if(nb!==0){printTab(0)}}const editDistanceState={current:[],prev:[],prevPrev:[],calculate:function calculate(a,b,limit){if(a.lengthlimit){return limit+1}while(b.length>0&&b[0]===a[0]){a=a.substring(1);b=b.substring(1)}while(b.length>0&&b[b.length-1]===a[a.length-1]){a=a.substring(0,a.length-1);b=b.substring(0,b.length-1)}if(b.length===0){return minDist}const aLength=a.length;const bLength=b.length;for(let i=0;i<=bLength;++i){this.current[i]=0;this.prev[i]=i;this.prevPrev[i]=Number.MAX_VALUE}for(let i=1;i<=aLength;++i){this.current[0]=i;const aIdx=i-1;for(let j=1;j<=bLength;++j){const bIdx=j-1;const substitutionCost=a[aIdx]===b[bIdx]?0:1;this.current[j]=Math.min(this.prev[j]+1,this.current[j-1]+1,this.prev[j-1]+substitutionCost);if((i>1)&&(j>1)&&(a[aIdx]===b[bIdx-1])&&(a[aIdx-1]===b[bIdx])){this.current[j]=Math.min(this.current[j],this.prevPrev[j-2]+1)}}const prevPrevTmp=this.prevPrev;this.prevPrev=this.prev;this.prev=this.current;this.current=prevPrevTmp}const distance=this.prev[bLength];return distance<=limit?distance:(limit+1)},};function editDistance(a,b,limit){return editDistanceState.calculate(a,b,limit)}function initSearch(rawSearchIndex){const MAX_RESULTS=200;const NO_TYPE_FILTER=-1;let searchIndex;let functionTypeFingerprint;let currentResults;let typeNameIdMap;const ALIASES=new Map();let typeNameIdOfArray;let typeNameIdOfSlice;let typeNameIdOfArrayOrSlice;let typeNameIdOfTuple;let typeNameIdOfUnit;let typeNameIdOfTupleOrUnit;function buildTypeMapIndex(name,isAssocType){if(name===""||name===null){return null}if(typeNameIdMap.has(name)){const obj=typeNameIdMap.get(name);obj.assocOnly=isAssocType&&obj.assocOnly;return obj.id}else{const id=typeNameIdMap.size;typeNameIdMap.set(name,{id,assocOnly:isAssocType});return id}}function isSpecialStartCharacter(c){return"<\"".indexOf(c)!==-1}function isEndCharacter(c){return"=,>-])".indexOf(c)!==-1}function itemTypeFromName(typename){const index=itemTypes.findIndex(i=>i===typename);if(index<0){throw["Unknown type filter ",typename]}return index}function getStringElem(query,parserState,isInGenerics){if(isInGenerics){throw["Unexpected ","\""," in generics"]}else if(query.literalSearch){throw["Cannot have more than one literal search element"]}else if(parserState.totalElems-parserState.genericsElems>0){throw["Cannot use literal search when there is more than one element"]}parserState.pos+=1;const start=parserState.pos;const end=getIdentEndPosition(parserState);if(parserState.pos>=parserState.length){throw["Unclosed ","\""]}else if(parserState.userQuery[end]!=="\""){throw["Unexpected ",parserState.userQuery[end]," in a string element"]}else if(start===end){throw["Cannot have empty string element"]}parserState.pos+=1;query.literalSearch=true}function isPathStart(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="::"}function isReturnArrow(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="->"}function isIdentCharacter(c){return(c==="_"||(c>="0"&&c<="9")||(c>="a"&&c<="z")||(c>="A"&&c<="Z"))}function isSeparatorCharacter(c){return c===","||c==="="}function isPathSeparator(c){return c===":"||c===" "}function prevIs(parserState,lookingFor){let pos=parserState.pos;while(pos>0){const c=parserState.userQuery[pos-1];if(c===lookingFor){return true}else if(c!==" "){break}pos-=1}return false}function isLastElemGeneric(elems,parserState){return(elems.length>0&&elems[elems.length-1].generics.length>0)||prevIs(parserState,">")}function skipWhitespace(parserState){while(parserState.pos0){throw["Cannot have more than one element if you use quotes"]}const typeFilter=parserState.typeFilter;parserState.typeFilter=null;if(name==="!"){if(typeFilter!==null&&typeFilter!=="primitive"){throw["Invalid search type: primitive never type ","!"," and ",typeFilter," both specified",]}if(generics.length!==0){throw["Never type ","!"," does not accept generic parameters",]}const bindingName=parserState.isInBinding;parserState.isInBinding=null;return{name:"never",id:null,fullPath:["never"],pathWithoutLast:[],pathLast:"never",normalizedPathLast:"never",generics:[],bindings:new Map(),typeFilter:"primitive",bindingName,}}const quadcolon=/::\s*::/.exec(path);if(path.startsWith("::")){throw["Paths cannot start with ","::"]}else if(path.endsWith("::")){throw["Paths cannot end with ","::"]}else if(quadcolon!==null){throw["Unexpected ",quadcolon[0]]}const pathSegments=path.split(/(?:::\s*)|(?:\s+(?:::\s*)?)/);if(pathSegments.length===0||(pathSegments.length===1&&pathSegments[0]==="")){if(generics.length>0||prevIs(parserState,">")){throw["Found generics without a path"]}else{throw["Unexpected ",parserState.userQuery[parserState.pos]]}}for(const[i,pathSegment]of pathSegments.entries()){if(pathSegment==="!"){if(i!==0){throw["Never type ","!"," is not associated item"]}pathSegments[i]="never"}}parserState.totalElems+=1;if(isInGenerics){parserState.genericsElems+=1}const bindingName=parserState.isInBinding;parserState.isInBinding=null;const bindings=new Map();const pathLast=pathSegments[pathSegments.length-1];return{name:name.trim(),id:null,fullPath:pathSegments,pathWithoutLast:pathSegments.slice(0,pathSegments.length-1),pathLast,normalizedPathLast:pathLast.replace(/_/g,""),generics:generics.filter(gen=>{if(gen.bindingName!==null){bindings.set(gen.bindingName.name,[gen,...gen.bindingName.generics]);return false}return true}),bindings,typeFilter,bindingName,}}function getIdentEndPosition(parserState){const start=parserState.pos;let end=parserState.pos;let foundExclamation=-1;while(parserState.pos0){throw["Unexpected ",c," after ",parserState.userQuery[parserState.pos-1]]}else{throw["Unexpected ",c]}}parserState.pos+=1;end=parserState.pos}if(foundExclamation!==-1&&foundExclamation!==start&&isIdentCharacter(parserState.userQuery[foundExclamation-1])){if(parserState.typeFilter===null){parserState.typeFilter="macro"}else if(parserState.typeFilter!=="macro"){throw["Invalid search type: macro ","!"," and ",parserState.typeFilter," both specified",]}end=foundExclamation}return end}function getNextElem(query,parserState,elems,isInGenerics){const generics=[];skipWhitespace(parserState);let start=parserState.pos;let end;if("[(".indexOf(parserState.userQuery[parserState.pos])!==-1){let endChar=")";let name="()";let friendlyName="tuple";if(parserState.userQuery[parserState.pos]==="["){endChar="]";name="[]";friendlyName="slice"}parserState.pos+=1;const{foundSeparator}=getItemsBefore(query,parserState,generics,endChar);const typeFilter=parserState.typeFilter;const isInBinding=parserState.isInBinding;if(typeFilter!==null&&typeFilter!=="primitive"){throw["Invalid search type: primitive ",name," and ",typeFilter," both specified",]}parserState.typeFilter=null;parserState.isInBinding=null;for(const gen of generics){if(gen.bindingName!==null){throw["Type parameter ","=",` cannot be within ${friendlyName} `,name]}}if(name==="()"&&!foundSeparator&&generics.length===1&&typeFilter===null){elems.push(generics[0])}else{parserState.totalElems+=1;if(isInGenerics){parserState.genericsElems+=1}elems.push({name:name,id:null,fullPath:[name],pathWithoutLast:[],pathLast:name,normalizedPathLast:name,generics,bindings:new Map(),typeFilter:"primitive",bindingName:isInBinding,})}}else{const isStringElem=parserState.userQuery[start]==="\"";if(isStringElem){start+=1;getStringElem(query,parserState,isInGenerics);end=parserState.pos-1}else{end=getIdentEndPosition(parserState)}if(parserState.pos=end){throw["Found generics without a path"]}parserState.pos+=1;getItemsBefore(query,parserState,generics,">")}if(isStringElem){skipWhitespace(parserState)}if(start>=end&&generics.length===0){return}if(parserState.userQuery[parserState.pos]==="="){if(parserState.isInBinding){throw["Cannot write ","="," twice in a binding"]}if(!isInGenerics){throw["Type parameter ","="," must be within generics list"]}const name=parserState.userQuery.slice(start,end).trim();if(name==="!"){throw["Type parameter ","="," key cannot be ","!"," never type"]}if(name.includes("!")){throw["Type parameter ","="," key cannot be ","!"," macro"]}if(name.includes("::")){throw["Type parameter ","="," key cannot contain ","::"," path"]}if(name.includes(":")){throw["Type parameter ","="," key cannot contain ",":"," type"]}parserState.isInBinding={name,generics}}else{elems.push(createQueryElement(query,parserState,parserState.userQuery.slice(start,end),generics,isInGenerics))}}}function getItemsBefore(query,parserState,elems,endChar){let foundStopChar=true;let foundSeparator=false;let start=parserState.pos;const oldTypeFilter=parserState.typeFilter;parserState.typeFilter=null;const oldIsInBinding=parserState.isInBinding;parserState.isInBinding=null;let extra="";if(endChar===">"){extra="<"}else if(endChar==="]"){extra="["}else if(endChar===")"){extra="("}else if(endChar===""){extra="->"}else{extra=endChar}while(parserState.pos"]}else if(prevIs(parserState,"\"")){throw["Cannot have more than one element if you use quotes"]}if(endChar!==""){throw["Expected ",",",", ","=",", or ",endChar,...extra,", found ",c,]}throw["Expected ",","," or ","=",...extra,", found ",c,]}const posBefore=parserState.pos;start=parserState.pos;getNextElem(query,parserState,elems,endChar!=="");if(endChar!==""&&parserState.pos>=parserState.length){throw["Unclosed ",extra]}if(posBefore===parserState.pos){parserState.pos+=1}foundStopChar=false}if(parserState.pos>=parserState.length&&endChar!==""){throw["Unclosed ",extra]}parserState.pos+=1;parserState.typeFilter=oldTypeFilter;parserState.isInBinding=oldIsInBinding;return{foundSeparator}}function checkExtraTypeFilterCharacters(start,parserState){const query=parserState.userQuery.slice(start,parserState.pos).trim();for(const c in query){if(!isIdentCharacter(query[c])){throw["Unexpected ",query[c]," in type filter (before ",":",")",]}}}function parseInput(query,parserState){let foundStopChar=true;let start=parserState.pos;while(parserState.pos"){if(isReturnArrow(parserState)){break}throw["Unexpected ",c," (did you mean ","->","?)"]}else if(parserState.pos>0){throw["Unexpected ",c," after ",parserState.userQuery[parserState.pos-1]]}throw["Unexpected ",c]}else if(c===":"&&!isPathStart(parserState)){if(parserState.typeFilter!==null){throw["Unexpected ",":"," (expected path after type filter ",parserState.typeFilter+":",")",]}else if(query.elems.length===0){throw["Expected type filter before ",":"]}else if(query.literalSearch){throw["Cannot use quotes on type filter"]}const typeFilterElem=query.elems.pop();checkExtraTypeFilterCharacters(start,parserState);parserState.typeFilter=typeFilterElem.name;parserState.pos+=1;parserState.totalElems-=1;query.literalSearch=false;foundStopChar=true;continue}else if(c===" "){skipWhitespace(parserState);continue}if(!foundStopChar){let extra="";if(isLastElemGeneric(query.elems,parserState)){extra=[" after ",">"]}else if(prevIs(parserState,"\"")){throw["Cannot have more than one element if you use quotes"]}if(parserState.typeFilter!==null){throw["Expected ",","," or ","->",...extra,", found ",c,]}throw["Expected ",",",", ",":"," or ","->",...extra,", found ",c,]}const before=query.elems.length;start=parserState.pos;getNextElem(query,parserState,query.elems,false);if(query.elems.length===before){parserState.pos+=1}foundStopChar=false}if(parserState.typeFilter!==null){throw["Unexpected ",":"," (expected path after type filter ",parserState.typeFilter+":",")",]}while(parserState.pos"]}break}else{parserState.pos+=1}}}function newParsedQuery(userQuery){return{original:userQuery,userQuery:userQuery.toLowerCase(),elems:[],returned:[],foundElems:0,totalElems:0,literalSearch:false,error:null,correction:null,proposeCorrectionFrom:null,proposeCorrectionTo:null,typeFingerprint:new Uint32Array(4),}}function buildUrl(search,filterCrates){let extra="?search="+encodeURIComponent(search);if(filterCrates!==null){extra+="&filter-crate="+encodeURIComponent(filterCrates)}return getNakedUrl()+extra+window.location.hash}function getFilterCrates(){const elem=document.getElementById("crate-search");if(elem&&elem.value!=="all crates"&&rawSearchIndex.has(elem.value)){return elem.value}return null}function parseQuery(userQuery){function convertTypeFilterOnElem(elem){if(elem.typeFilter!==null){let typeFilter=elem.typeFilter;if(typeFilter==="const"){typeFilter="constant"}elem.typeFilter=itemTypeFromName(typeFilter)}else{elem.typeFilter=NO_TYPE_FILTER}for(const elem2 of elem.generics){convertTypeFilterOnElem(elem2)}for(const constraints of elem.bindings.values()){for(const constraint of constraints){convertTypeFilterOnElem(constraint)}}}userQuery=userQuery.trim().replace(/\r|\n|\t/g," ");const parserState={length:userQuery.length,pos:0,totalElems:0,genericsElems:0,typeFilter:null,isInBinding:null,userQuery:userQuery.toLowerCase(),};let query=newParsedQuery(userQuery);try{parseInput(query,parserState);for(const elem of query.elems){convertTypeFilterOnElem(elem)}for(const elem of query.returned){convertTypeFilterOnElem(elem)}}catch(err){query=newParsedQuery(userQuery);query.error=err;return query}if(!query.literalSearch){query.literalSearch=parserState.totalElems>1}query.foundElems=query.elems.length+query.returned.length;query.totalElems=parserState.totalElems;return query}function createQueryResults(results_in_args,results_returned,results_others,parsedQuery){return{"in_args":results_in_args,"returned":results_returned,"others":results_others,"query":parsedQuery,}}function execQuery(parsedQuery,filterCrates,currentCrate){const results_others=new Map(),results_in_args=new Map(),results_returned=new Map();function transformResults(results){const duplicates=new Set();const out=[];for(const result of results){if(result.id!==-1){const obj=searchIndex[result.id];obj.dist=result.dist;const res=buildHrefAndPath(obj);obj.displayPath=pathSplitter(res[0]);obj.fullPath=obj.displayPath+obj.name;obj.fullPath+="|"+obj.ty;if(duplicates.has(obj.fullPath)){continue}duplicates.add(obj.fullPath);obj.href=res[1];out.push(obj);if(out.length>=MAX_RESULTS){break}}}return out}function sortResults(results,isType,preferredCrate){if(results.size===0){return[]}const userQuery=parsedQuery.userQuery;const result_list=[];for(const result of results.values()){result.item=searchIndex[result.id];result.word=searchIndex[result.id].word;result_list.push(result)}result_list.sort((aaa,bbb)=>{let a,b;a=(aaa.word!==userQuery);b=(bbb.word!==userQuery);if(a!==b){return a-b}a=(aaa.index<0);b=(bbb.index<0);if(a!==b){return a-b}a=aaa.path_dist;b=bbb.path_dist;if(a!==b){return a-b}a=aaa.index;b=bbb.index;if(a!==b){return a-b}a=(aaa.dist);b=(bbb.dist);if(a!==b){return a-b}a=aaa.item.deprecated;b=bbb.item.deprecated;if(a!==b){return a-b}a=(aaa.item.crate!==preferredCrate);b=(bbb.item.crate!==preferredCrate);if(a!==b){return a-b}a=aaa.word.length;b=bbb.word.length;if(a!==b){return a-b}a=aaa.word;b=bbb.word;if(a!==b){return(a>b?+1:-1)}a=(aaa.item.desc==="");b=(bbb.item.desc==="");if(a!==b){return a-b}a=aaa.item.ty;b=bbb.item.ty;if(a!==b){return a-b}a=aaa.item.path;b=bbb.item.path;if(a!==b){return(a>b?+1:-1)}return 0});return transformResults(result_list)}function unifyFunctionTypes(fnTypesIn,queryElems,whereClause,mgensIn,solutionCb){const mgens=mgensIn===null?null:new Map(mgensIn);if(queryElems.length===0){return!solutionCb||solutionCb(mgens)}if(!fnTypesIn||fnTypesIn.length===0){return false}const ql=queryElems.length;const fl=fnTypesIn.length;if(ql===1&&queryElems[0].generics.length===0&&queryElems[0].bindings.size===0){const queryElem=queryElems[0];for(const fnType of fnTypesIn){if(!unifyFunctionTypeIsMatchCandidate(fnType,queryElem,whereClause,mgens)){continue}if(fnType.id<0&&queryElem.id<0){if(mgens&&mgens.has(fnType.id)&&mgens.get(fnType.id)!==queryElem.id){continue}const mgensScratch=new Map(mgens);mgensScratch.set(fnType.id,queryElem.id);if(!solutionCb||solutionCb(mgensScratch)){return true}}else if(!solutionCb||solutionCb(mgens?new Map(mgens):null)){return true}}for(const fnType of fnTypesIn){if(!unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens)){continue}if(fnType.id<0){if(mgens&&mgens.has(fnType.id)&&mgens.get(fnType.id)!==0){continue}const mgensScratch=new Map(mgens);mgensScratch.set(fnType.id,0);if(unifyFunctionTypes(whereClause[(-fnType.id)-1],queryElems,whereClause,mgensScratch,solutionCb)){return true}}else if(unifyFunctionTypes([...fnType.generics,...Array.from(fnType.bindings.values()).flat()],queryElems,whereClause,mgens?new Map(mgens):null,solutionCb)){return true}}return false}const fnTypes=fnTypesIn.slice();const flast=fl-1;const qlast=ql-1;const queryElem=queryElems[qlast];let queryElemsTmp=null;for(let i=flast;i>=0;i-=1){const fnType=fnTypes[i];if(!unifyFunctionTypeIsMatchCandidate(fnType,queryElem,whereClause,mgens)){continue}let mgensScratch;if(fnType.id<0){mgensScratch=new Map(mgens);if(mgensScratch.has(fnType.id)&&mgensScratch.get(fnType.id)!==queryElem.id){continue}mgensScratch.set(fnType.id,queryElem.id)}else{mgensScratch=mgens}fnTypes[i]=fnTypes[flast];fnTypes.length=flast;if(!queryElemsTmp){queryElemsTmp=queryElems.slice(0,qlast)}const passesUnification=unifyFunctionTypes(fnTypes,queryElemsTmp,whereClause,mgensScratch,mgensScratch=>{if(fnType.generics.length===0&&queryElem.generics.length===0&&fnType.bindings.size===0&&queryElem.bindings.size===0){return!solutionCb||solutionCb(mgensScratch)}const solution=unifyFunctionTypeCheckBindings(fnType,queryElem,whereClause,mgensScratch);if(!solution){return false}const simplifiedGenerics=solution.simplifiedGenerics;for(const simplifiedMgens of solution.mgens){const passesUnification=unifyFunctionTypes(simplifiedGenerics,queryElem.generics,whereClause,simplifiedMgens,solutionCb);if(passesUnification){return true}}return false});if(passesUnification){return true}fnTypes[flast]=fnTypes[i];fnTypes[i]=fnType;fnTypes.length=fl}for(let i=flast;i>=0;i-=1){const fnType=fnTypes[i];if(!unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens)){continue}let mgensScratch;if(fnType.id<0){mgensScratch=new Map(mgens);if(mgensScratch.has(fnType.id)&&mgensScratch.get(fnType.id)!==0){continue}mgensScratch.set(fnType.id,0)}else{mgensScratch=mgens}const generics=fnType.id<0?whereClause[(-fnType.id)-1]:fnType.generics;const bindings=fnType.bindings?Array.from(fnType.bindings.values()).flat():[];const passesUnification=unifyFunctionTypes(fnTypes.toSpliced(i,1,...generics,...bindings),queryElems,whereClause,mgensScratch,solutionCb);if(passesUnification){return true}}return false}function unifyFunctionTypeIsMatchCandidate(fnType,queryElem,whereClause,mgensIn){if(!typePassesFilter(queryElem.typeFilter,fnType.ty)){return false}if(fnType.id<0&&queryElem.id<0){if(mgensIn){if(mgensIn.has(fnType.id)&&mgensIn.get(fnType.id)!==queryElem.id){return false}for(const[fid,qid]of mgensIn.entries()){if(fnType.id!==fid&&queryElem.id===qid){return false}if(fnType.id===fid&&queryElem.id!==qid){return false}}}return true}else{if(queryElem.id===typeNameIdOfArrayOrSlice&&(fnType.id===typeNameIdOfSlice||fnType.id===typeNameIdOfArray)){}else if(queryElem.id===typeNameIdOfTupleOrUnit&&(fnType.id===typeNameIdOfTuple||fnType.id===typeNameIdOfUnit)){}else if(fnType.id!==queryElem.id||queryElem.id===null){return false}if((fnType.generics.length+fnType.bindings.size)===0&&queryElem.generics.length!==0){return false}if(fnType.bindings.size0){const fnTypePath=fnType.path!==undefined&&fnType.path!==null?fnType.path.split("::"):[];if(queryElemPathLength>fnTypePath.length){return false}let i=0;for(const path of fnTypePath){if(path===queryElem.pathWithoutLast[i]){i+=1;if(i>=queryElemPathLength){break}}}if(i0){let mgensSolutionSet=[mgensIn];for(const[name,constraints]of queryElem.bindings.entries()){if(mgensSolutionSet.length===0){return false}if(!fnType.bindings.has(name)){return false}const fnTypeBindings=fnType.bindings.get(name);mgensSolutionSet=mgensSolutionSet.flatMap(mgens=>{const newSolutions=[];unifyFunctionTypes(fnTypeBindings,constraints,whereClause,mgens,newMgens=>{newSolutions.push(newMgens);return false});return newSolutions})}if(mgensSolutionSet.length===0){return false}const binds=Array.from(fnType.bindings.entries()).flatMap(entry=>{const[name,constraints]=entry;if(queryElem.bindings.has(name)){return[]}else{return constraints}});if(simplifiedGenerics.length>0){simplifiedGenerics=[...simplifiedGenerics,...binds]}else{simplifiedGenerics=binds}return{simplifiedGenerics,mgens:mgensSolutionSet}}return{simplifiedGenerics,mgens:[mgensIn]}}function unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens){if(fnType.id<0&&queryElem.id>=0){if(!whereClause){return false}if(mgens&&mgens.has(fnType.id)&&mgens.get(fnType.id)!==0){return false}const mgensTmp=new Map(mgens);mgensTmp.set(fnType.id,null);return checkIfInList(whereClause[(-fnType.id)-1],queryElem,whereClause,mgensTmp)}else if(fnType.generics.length>0||fnType.bindings.size>0){const simplifiedGenerics=[...fnType.generics,...Array.from(fnType.bindings.values()).flat(),];return checkIfInList(simplifiedGenerics,queryElem,whereClause,mgens)}return false}function checkIfInList(list,elem,whereClause,mgens){for(const entry of list){if(checkType(entry,elem,whereClause,mgens)){return true}}return false}function checkType(row,elem,whereClause,mgens){if(row.bindings.size===0&&elem.bindings.size===0){if(elem.id<0){return row.id<0||checkIfInList(row.generics,elem,whereClause,mgens)}if(row.id>0&&elem.id>0&&elem.pathWithoutLast.length===0&&typePassesFilter(elem.typeFilter,row.ty)&&elem.generics.length===0&&elem.id!==typeNameIdOfArrayOrSlice&&elem.id!==typeNameIdOfTupleOrUnit){return row.id===elem.id||checkIfInList(row.generics,elem,whereClause,mgens)}}return unifyFunctionTypes([row],[elem],whereClause,mgens)}function checkPath(contains,ty){if(contains.length===0){return 0}const maxPathEditDistance=Math.floor(contains.reduce((acc,next)=>acc+next.length,0)/3);let ret_dist=maxPathEditDistance+1;const path=ty.path.split("::");if(ty.parent&&ty.parent.name){path.push(ty.parent.name.toLowerCase())}const length=path.length;const clength=contains.length;pathiter:for(let i=length-clength;i>=0;i-=1){let dist_total=0;for(let x=0;xmaxPathEditDistance){continue pathiter}dist_total+=dist}}ret_dist=Math.min(ret_dist,Math.round(dist_total/clength))}return ret_dist>maxPathEditDistance?null:ret_dist}function typePassesFilter(filter,type){if(filter<=NO_TYPE_FILTER||filter===type)return true;const name=itemTypes[type];switch(itemTypes[filter]){case"constant":return name==="associatedconstant";case"fn":return name==="method"||name==="tymethod";case"type":return name==="primitive"||name==="associatedtype";case"trait":return name==="traitalias"}return false}function createAliasFromItem(item){return{crate:item.crate,name:item.name,path:item.path,desc:item.desc,ty:item.ty,parent:item.parent,type:item.type,is_alias:true,deprecated:item.deprecated,implDisambiguator:item.implDisambiguator,}}function handleAliases(ret,query,filterCrates,currentCrate){const lowerQuery=query.toLowerCase();const aliases=[];const crateAliases=[];if(filterCrates!==null){if(ALIASES.has(filterCrates)&&ALIASES.get(filterCrates).has(lowerQuery)){const query_aliases=ALIASES.get(filterCrates).get(lowerQuery);for(const alias of query_aliases){aliases.push(createAliasFromItem(searchIndex[alias]))}}}else{for(const[crate,crateAliasesIndex]of ALIASES){if(crateAliasesIndex.has(lowerQuery)){const pushTo=crate===currentCrate?crateAliases:aliases;const query_aliases=crateAliasesIndex.get(lowerQuery);for(const alias of query_aliases){pushTo.push(createAliasFromItem(searchIndex[alias]))}}}}const sortFunc=(aaa,bbb)=>{if(aaa.path{alias.alias=query;const res=buildHrefAndPath(alias);alias.displayPath=pathSplitter(res[0]);alias.fullPath=alias.displayPath+alias.name;alias.href=res[1];ret.others.unshift(alias);if(ret.others.length>MAX_RESULTS){ret.others.pop()}};aliases.forEach(pushFunc);crateAliases.forEach(pushFunc)}function addIntoResults(results,fullId,id,index,dist,path_dist,maxEditDistance){if(dist<=maxEditDistance||index!==-1){if(results.has(fullId)){const result=results.get(fullId);if(result.dontValidate||result.dist<=dist){return}}results.set(fullId,{id:id,index:index,dontValidate:parsedQuery.literalSearch,dist:dist,path_dist:path_dist,})}}function handleSingleArg(row,pos,elem,results_others,results_in_args,results_returned,maxEditDistance){if(!row||(filterCrates!==null&&row.crate!==filterCrates)){return}let path_dist=0;const fullId=row.id;const tfpDist=compareTypeFingerprints(fullId,parsedQuery.typeFingerprint);if(tfpDist!==null){const in_args=row.type&&row.type.inputs&&checkIfInList(row.type.inputs,elem,row.type.where_clause);const returned=row.type&&row.type.output&&checkIfInList(row.type.output,elem,row.type.where_clause);if(in_args){results_in_args.max_dist=Math.max(results_in_args.max_dist||0,tfpDist);const maxDist=results_in_args.sizenormalizedIndex&&normalizedIndex!==-1)){index=normalizedIndex}if(elem.fullPath.length>1){path_dist=checkPath(elem.pathWithoutLast,row);if(path_dist===null){return}}if(parsedQuery.literalSearch){if(row.word===elem.pathLast){addIntoResults(results_others,fullId,pos,index,0,path_dist)}return}const dist=editDistance(row.normalizedName,elem.normalizedPathLast,maxEditDistance);if(index===-1&&dist>maxEditDistance){return}addIntoResults(results_others,fullId,pos,index,dist,path_dist,maxEditDistance)}function handleArgs(row,pos,results){if(!row||(filterCrates!==null&&row.crate!==filterCrates)||!row.type){return}const tfpDist=compareTypeFingerprints(row.id,parsedQuery.typeFingerprint);if(tfpDist===null){return}if(results.size>=MAX_RESULTS&&tfpDist>results.max_dist){return}if(!unifyFunctionTypes(row.type.inputs,parsedQuery.elems,row.type.where_clause,null,mgens=>{return unifyFunctionTypes(row.type.output,parsedQuery.returned,row.type.where_clause,mgens)})){return}results.max_dist=Math.max(results.max_dist||0,tfpDist);addIntoResults(results,row.id,pos,0,tfpDist,0,Number.MAX_VALUE)}function innerRunQuery(){const queryLen=parsedQuery.elems.reduce((acc,next)=>acc+next.pathLast.length,0)+parsedQuery.returned.reduce((acc,next)=>acc+next.pathLast.length,0);const maxEditDistance=Math.floor(queryLen/3);const genericSymbols=new Map();function convertNameToId(elem,isAssocType){if(typeNameIdMap.has(elem.normalizedPathLast)&&(isAssocType||!typeNameIdMap.get(elem.normalizedPathLast).assocOnly)){elem.id=typeNameIdMap.get(elem.normalizedPathLast).id}else if(!parsedQuery.literalSearch){let match=null;let matchDist=maxEditDistance+1;let matchName="";for(const[name,{id,assocOnly}]of typeNameIdMap){const dist=editDistance(name,elem.normalizedPathLast,maxEditDistance);if(dist<=matchDist&&dist<=maxEditDistance&&(isAssocType||!assocOnly)){if(dist===matchDist&&matchName>name){continue}match=id;matchDist=dist;matchName=name}}if(match!==null){parsedQuery.correction=matchName}elem.id=match}if((elem.id===null&&parsedQuery.totalElems>1&&elem.typeFilter===-1&&elem.generics.length===0&&elem.bindings.size===0)||elem.typeFilter===TY_GENERIC){if(genericSymbols.has(elem.name)){elem.id=genericSymbols.get(elem.name)}else{elem.id=-(genericSymbols.size+1);genericSymbols.set(elem.name,elem.id)}if(elem.typeFilter===-1&&elem.name.length>=3){const maxPartDistance=Math.floor(elem.name.length/3);let matchDist=maxPartDistance+1;let matchName="";for(const name of typeNameIdMap.keys()){const dist=editDistance(name,elem.name,maxPartDistance);if(dist<=matchDist&&dist<=maxPartDistance){if(dist===matchDist&&matchName>name){continue}matchDist=dist;matchName=name}}if(matchName!==""){parsedQuery.proposeCorrectionFrom=elem.name;parsedQuery.proposeCorrectionTo=matchName}}elem.typeFilter=TY_GENERIC}if(elem.generics.length>0&&elem.typeFilter===TY_GENERIC){parsedQuery.error=["Generic type parameter ",elem.name," does not accept generic parameters",]}for(const elem2 of elem.generics){convertNameToId(elem2)}elem.bindings=new Map(Array.from(elem.bindings.entries()).map(entry=>{const[name,constraints]=entry;if(!typeNameIdMap.has(name)){parsedQuery.error=["Type parameter ",name," does not exist",];return[null,[]]}for(const elem2 of constraints){convertNameToId(elem2)}return[typeNameIdMap.get(name).id,constraints]}))}const fps=new Set();for(const elem of parsedQuery.elems){convertNameToId(elem);buildFunctionTypeFingerprint(elem,parsedQuery.typeFingerprint,fps)}for(const elem of parsedQuery.returned){convertNameToId(elem);buildFunctionTypeFingerprint(elem,parsedQuery.typeFingerprint,fps)}if(parsedQuery.foundElems===1&&parsedQuery.returned.length===0){if(parsedQuery.elems.length===1){const elem=parsedQuery.elems[0];for(let i=0,nSearchIndex=searchIndex.length;i0){const sortQ=(a,b)=>{const ag=a.generics.length===0&&a.bindings.size===0;const bg=b.generics.length===0&&b.bindings.size===0;if(ag!==bg){return ag-bg}const ai=a.id>0;const bi=b.id>0;return ai-bi};parsedQuery.elems.sort(sortQ);parsedQuery.returned.sort(sortQ);for(let i=0,nSearchIndex=searchIndex.length;i");if(tmp.endsWith("")){return tmp.slice(0,tmp.length-6)}return tmp}function addTab(array,query,display){const extraClass=display?" active":"";const output=document.createElement("div");if(array.length>0){output.className="search-results "+extraClass;array.forEach(item=>{const name=item.name;const type=itemTypes[item.ty];const longType=longItemTypes[item.ty];const typeName=longType.length!==0?`${longType}`:"?";const link=document.createElement("a");link.className="result-"+type;link.href=item.href;const resultName=document.createElement("div");resultName.className="result-name";resultName.insertAdjacentHTML("beforeend",`${typeName}`);link.appendChild(resultName);let alias=" ";if(item.is_alias){alias=`
\ +${item.alias} - see \ +
`}resultName.insertAdjacentHTML("beforeend",`
${alias}\ +${item.displayPath}${name}\ +
`);const description=document.createElement("div");description.className="desc";description.insertAdjacentHTML("beforeend",item.desc);link.appendChild(description);output.appendChild(link)})}else if(query.error===null){output.className="search-failed"+extraClass;output.innerHTML="No results :(
"+"Try on DuckDuckGo?

"+"Or try looking in one of these:"}return[output,array.length]}function makeTabHeader(tabNb,text,nbElems){const fmtNbElems=nbElems<10?`\u{2007}(${nbElems})\u{2007}\u{2007}`:nbElems<100?`\u{2007}(${nbElems})\u{2007}`:`\u{2007}(${nbElems})`;if(searchState.currentTab===tabNb){return""}return""}function showResults(results,go_to_first,filterCrates){const search=searchState.outputElement();if(go_to_first||(results.others.length===1&&getSettingValue("go-to-only-result")==="true")){window.onunload=()=>{};searchState.removeQueryParameters();const elem=document.createElement("a");elem.href=results.others[0].href;removeClass(elem,"active");document.body.appendChild(elem);elem.click();return}if(results.query===undefined){results.query=parseQuery(searchState.input.value)}currentResults=results.query.userQuery;const ret_others=addTab(results.others,results.query,true);const ret_in_args=addTab(results.in_args,results.query,false);const ret_returned=addTab(results.returned,results.query,false);let currentTab=searchState.currentTab;if((currentTab===0&&ret_others[1]===0)||(currentTab===1&&ret_in_args[1]===0)||(currentTab===2&&ret_returned[1]===0)){if(ret_others[1]!==0){currentTab=0}else if(ret_in_args[1]!==0){currentTab=1}else if(ret_returned[1]!==0){currentTab=2}}let crates="";if(rawSearchIndex.size>1){crates=" in 
"}let output=`

Results${crates}

`;if(results.query.error!==null){const error=results.query.error;error.forEach((value,index)=>{value=value.split("<").join("<").split(">").join(">");if(index%2!==0){error[index]=`${value.replaceAll(" ", " ")}`}else{error[index]=value}});output+=`

Query parser error: "${error.join("")}".

`;output+="
"+makeTabHeader(0,"In Names",ret_others[1])+"
";currentTab=0}else if(results.query.foundElems<=1&&results.query.returned.length===0){output+="
"+makeTabHeader(0,"In Names",ret_others[1])+makeTabHeader(1,"In Parameters",ret_in_args[1])+makeTabHeader(2,"In Return Types",ret_returned[1])+"
"}else{const signatureTabTitle=results.query.elems.length===0?"In Function Return Types":results.query.returned.length===0?"In Function Parameters":"In Function Signatures";output+="
"+makeTabHeader(0,signatureTabTitle,ret_others[1])+"
";currentTab=0}if(results.query.correction!==null){const orig=results.query.returned.length>0?results.query.returned[0].name:results.query.elems[0].name;output+="

"+`Type "${orig}" not found. `+"Showing results for closest type name "+`"${results.query.correction}" instead.

`}if(results.query.proposeCorrectionFrom!==null){const orig=results.query.proposeCorrectionFrom;const targ=results.query.proposeCorrectionTo;output+="

"+`Type "${orig}" not found and used as generic parameter. `+`Consider searching for "${targ}" instead.

`}const resultsElem=document.createElement("div");resultsElem.id="results";resultsElem.appendChild(ret_others[0]);resultsElem.appendChild(ret_in_args[0]);resultsElem.appendChild(ret_returned[0]);search.innerHTML=output;const crateSearch=document.getElementById("crate-search");if(crateSearch){crateSearch.addEventListener("input",updateCrate)}search.appendChild(resultsElem);searchState.showResults(search);const elems=document.getElementById("search-tabs").childNodes;searchState.focusedByTab=[];let i=0;for(const elem of elems){const j=i;elem.onclick=()=>printTab(j);searchState.focusedByTab.push(null);i+=1}printTab(currentTab)}function updateSearchHistory(url){if(!browserSupportsHistoryApi()){return}const params=searchState.getQueryStringParams();if(!history.state&&!params.search){history.pushState(null,"",url)}else{history.replaceState(null,"",url)}}function search(forced){const query=parseQuery(searchState.input.value.trim());let filterCrates=getFilterCrates();if(!forced&&query.userQuery===currentResults){if(query.userQuery.length>0){putBackSearch()}return}searchState.setLoadingSearch();const params=searchState.getQueryStringParams();if(filterCrates===null&¶ms["filter-crate"]!==undefined){filterCrates=params["filter-crate"]}searchState.title="Results for "+query.original+" - Rust";updateSearchHistory(buildUrl(query.original,filterCrates));showResults(execQuery(query,filterCrates,window.currentCrate),params.go_to_first,filterCrates)}function buildItemSearchTypeAll(types,lowercasePaths){return types.length>0?types.map(type=>buildItemSearchType(type,lowercasePaths)):EMPTY_GENERICS_ARRAY}const EMPTY_BINDINGS_MAP=new Map();const EMPTY_GENERICS_ARRAY=[];let TYPES_POOL=new Map();function buildItemSearchType(type,lowercasePaths,isAssocType){const PATH_INDEX_DATA=0;const GENERICS_DATA=1;const BINDINGS_DATA=2;let pathIndex,generics,bindings;if(typeof type==="number"){pathIndex=type;generics=EMPTY_GENERICS_ARRAY;bindings=EMPTY_BINDINGS_MAP}else{pathIndex=type[PATH_INDEX_DATA];generics=buildItemSearchTypeAll(type[GENERICS_DATA],lowercasePaths);if(type.length>BINDINGS_DATA&&type[BINDINGS_DATA].length>0){bindings=new Map(type[BINDINGS_DATA].map(binding=>{const[assocType,constraints]=binding;return[buildItemSearchType(assocType,lowercasePaths,true).id,buildItemSearchTypeAll(constraints,lowercasePaths),]}))}else{bindings=EMPTY_BINDINGS_MAP}}let result;if(pathIndex<0){result={id:pathIndex,ty:TY_GENERIC,path:null,generics,bindings,}}else if(pathIndex===0){result={id:null,ty:null,path:null,generics,bindings,}}else{const item=lowercasePaths[pathIndex-1];result={id:buildTypeMapIndex(item.name,isAssocType),ty:item.ty,path:item.path,generics,bindings,}}const cr=TYPES_POOL.get(result.id);if(cr){if(cr.generics.length===result.generics.length&&cr.generics!==result.generics&&cr.generics.every((x,i)=>result.generics[i]===x)){result.generics=cr.generics}if(cr.bindings.size===result.bindings.size&&cr.bindings!==result.bindings){let ok=true;for(const[k,v]of cr.bindings.entries()){const v2=result.bindings.get(v);if(!v2){ok=false;break}if(v!==v2&&v.length===v2.length&&v.every((x,i)=>v2[i]===x)){result.bindings.set(k,v)}else if(v!==v2){ok=false;break}}if(ok){result.bindings=cr.bindings}}if(cr.ty===result.ty&&cr.path===result.path&&cr.bindings===result.bindings&&cr.generics===result.generics&&cr.ty===result.ty){return cr}}TYPES_POOL.set(result.id,result);return result}function buildFunctionSearchType(itemFunctionDecoder,lowercasePaths){const c=itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);itemFunctionDecoder.offset+=1;const[zero,ua,la,ob,cb]=["0","@","`","{","}"].map(c=>c.charCodeAt(0));if(c===la){return null}if(c>=zero&&c>1];itemFunctionDecoder.offset+=1;return sign?-value:value}const functionSearchType=decodeList();const INPUTS_DATA=0;const OUTPUT_DATA=1;let inputs,output;if(typeof functionSearchType[INPUTS_DATA]==="number"){inputs=[buildItemSearchType(functionSearchType[INPUTS_DATA],lowercasePaths)]}else{inputs=buildItemSearchTypeAll(functionSearchType[INPUTS_DATA],lowercasePaths)}if(functionSearchType.length>1){if(typeof functionSearchType[OUTPUT_DATA]==="number"){output=[buildItemSearchType(functionSearchType[OUTPUT_DATA],lowercasePaths)]}else{output=buildItemSearchTypeAll(functionSearchType[OUTPUT_DATA],lowercasePaths)}}else{output=[]}const where_clause=[];const l=functionSearchType.length;for(let i=2;i16){itemFunctionDecoder.backrefQueue.pop()}return ret}function buildFunctionTypeFingerprint(type,output,fps){let input=type.id;if(input===typeNameIdOfArray||input===typeNameIdOfSlice){input=typeNameIdOfArrayOrSlice}if(input===typeNameIdOfTuple||input===typeNameIdOfUnit){input=typeNameIdOfTupleOrUnit}const hashint1=k=>{k=(~~k+0x7ed55d16)+(k<<12);k=(k ^ 0xc761c23c)^(k>>>19);k=(~~k+0x165667b1)+(k<<5);k=(~~k+0xd3a2646c)^(k<<9);k=(~~k+0xfd7046c5)+(k<<3);return(k ^ 0xb55a4f09)^(k>>>16)};const hashint2=k=>{k=~k+(k<<15);k ^=k>>>12;k+=k<<2;k ^=k>>>4;k=Math.imul(k,2057);return k ^(k>>16)};if(input!==null){const h0a=hashint1(input);const h0b=hashint2(input);const h1a=~~(h0a+Math.imul(h0b,2));const h1b=~~(h0a+Math.imul(h0b,3));const h2a=~~(h0a+Math.imul(h0b,4));const h2b=~~(h0a+Math.imul(h0b,5));output[0]|=(1<<(h0a%32))|(1<<(h1b%32));output[1]|=(1<<(h1a%32))|(1<<(h2b%32));output[2]|=(1<<(h2a%32))|(1<<(h0b%32));fps.add(input)}for(const g of type.generics){buildFunctionTypeFingerprint(g,output,fps)}const fb={id:null,ty:0,generics:EMPTY_GENERICS_ARRAY,bindings:EMPTY_BINDINGS_MAP,};for(const[k,v]of type.bindings.entries()){fb.id=k;fb.generics=v;buildFunctionTypeFingerprint(fb,output,fps)}output[3]=fps.size}function compareTypeFingerprints(fullId,queryFingerprint){const fh0=functionTypeFingerprint[fullId*4];const fh1=functionTypeFingerprint[(fullId*4)+1];const fh2=functionTypeFingerprint[(fullId*4)+2];const[qh0,qh1,qh2]=queryFingerprint;const[in0,in1,in2]=[fh0&qh0,fh1&qh1,fh2&qh2];if((in0 ^ qh0)||(in1 ^ qh1)||(in2 ^ qh2)){return null}return functionTypeFingerprint[(fullId*4)+3]}function buildIndex(rawSearchIndex){searchIndex=[];typeNameIdMap=new Map();const charA="A".charCodeAt(0);let currentIndex=0;let id=0;typeNameIdOfArray=buildTypeMapIndex("array");typeNameIdOfSlice=buildTypeMapIndex("slice");typeNameIdOfTuple=buildTypeMapIndex("tuple");typeNameIdOfUnit=buildTypeMapIndex("unit");typeNameIdOfArrayOrSlice=buildTypeMapIndex("[]");typeNameIdOfTupleOrUnit=buildTypeMapIndex("()");for(const crate of rawSearchIndex.values()){id+=crate.t.length+1}functionTypeFingerprint=new Uint32Array((id+1)*4);id=0;for(const[crate,crateCorpus]of rawSearchIndex){const crateRow={crate:crate,ty:3,name:crate,path:"",desc:crateCorpus.doc,parent:undefined,type:null,id:id,word:crate,normalizedName:crate.indexOf("_")===-1?crate:crate.replace(/_/g,""),deprecated:null,implDisambiguator:null,};id+=1;searchIndex.push(crateRow);currentIndex+=1;const itemTypes=crateCorpus.t;const itemNames=crateCorpus.n;const itemPaths=new Map(crateCorpus.q);const itemDescs=crateCorpus.d;const itemParentIdxs=crateCorpus.i;const itemFunctionDecoder={string:crateCorpus.f,offset:0,backrefQueue:[],};const deprecatedItems=new Set(crateCorpus.c);const implDisambiguator=new Map(crateCorpus.b);const paths=crateCorpus.p;const aliases=crateCorpus.a;const lowercasePaths=[];let len=paths.length;let lastPath=itemPaths.get(0);for(let i=0;i2){path=itemPaths.has(elem[2])?itemPaths.get(elem[2]):lastPath;lastPath=path}lowercasePaths.push({ty:ty,name:name.toLowerCase(),path:path});paths[i]={ty:ty,name:name,path:path}}lastPath="";len=itemTypes.length;for(let i=0;i0?paths[itemParentIdxs[i]-1]:undefined,type,id:id,word,normalizedName:word.indexOf("_")===-1?word:word.replace(/_/g,""),deprecated:deprecatedItems.has(i),implDisambiguator:implDisambiguator.has(i)?implDisambiguator.get(i):null,};id+=1;searchIndex.push(row);lastPath=row.path}if(aliases){const currentCrateAliases=new Map();ALIASES.set(crate,currentCrateAliases);for(const alias_name in aliases){if(!Object.prototype.hasOwnProperty.call(aliases,alias_name)){continue}let currentNameAliases;if(currentCrateAliases.has(alias_name)){currentNameAliases=currentCrateAliases.get(alias_name)}else{currentNameAliases=[];currentCrateAliases.set(alias_name,currentNameAliases)}for(const local_alias of aliases[alias_name]){currentNameAliases.push(local_alias+currentIndex)}}}currentIndex+=itemTypes.length}TYPES_POOL=new Map()}function onSearchSubmit(e){e.preventDefault();searchState.clearInputTimeout();search()}function putBackSearch(){const search_input=searchState.input;if(!searchState.input){return}if(search_input.value!==""&&!searchState.isDisplayed()){searchState.showResults();if(browserSupportsHistoryApi()){history.replaceState(null,"",buildUrl(search_input.value,getFilterCrates()))}document.title=searchState.title}}function registerSearchEvents(){const params=searchState.getQueryStringParams();if(searchState.input.value===""){searchState.input.value=params.search||""}const searchAfter500ms=()=>{searchState.clearInputTimeout();if(searchState.input.value.length===0){searchState.hideResults()}else{searchState.timeout=setTimeout(search,500)}};searchState.input.onkeyup=searchAfter500ms;searchState.input.oninput=searchAfter500ms;document.getElementsByClassName("search-form")[0].onsubmit=onSearchSubmit;searchState.input.onchange=e=>{if(e.target!==document.activeElement){return}searchState.clearInputTimeout();setTimeout(search,0)};searchState.input.onpaste=searchState.input.onchange;searchState.outputElement().addEventListener("keydown",e=>{if(e.altKey||e.ctrlKey||e.shiftKey||e.metaKey){return}if(e.which===38){const previous=document.activeElement.previousElementSibling;if(previous){previous.focus()}else{searchState.focus()}e.preventDefault()}else if(e.which===40){const next=document.activeElement.nextElementSibling;if(next){next.focus()}const rect=document.activeElement.getBoundingClientRect();if(window.innerHeight-rect.bottom{if(e.which===40){focusSearchResult();e.preventDefault()}});searchState.input.addEventListener("focus",()=>{putBackSearch()});searchState.input.addEventListener("blur",()=>{searchState.input.placeholder=searchState.input.origPlaceholder});if(browserSupportsHistoryApi()){const previousTitle=document.title;window.addEventListener("popstate",e=>{const params=searchState.getQueryStringParams();document.title=previousTitle;currentResults=null;if(params.search&¶ms.search.length>0){searchState.input.value=params.search;e.preventDefault();search()}else{searchState.input.value="";searchState.hideResults()}})}window.onpageshow=()=>{const qSearch=searchState.getQueryStringParams().search;if(searchState.input.value===""&&qSearch){searchState.input.value=qSearch}search()}}function updateCrate(ev){if(ev.target.value==="all crates"){const query=searchState.input.value.trim();updateSearchHistory(buildUrl(query,null))}currentResults=null;search(true)}buildIndex(rawSearchIndex);if(typeof window!=="undefined"){registerSearchEvents();if(window.searchState.getQueryStringParams().search){search()}}if(typeof exports!=="undefined"){exports.initSearch=initSearch;exports.execQuery=execQuery;exports.parseQuery=parseQuery}}if(typeof window!=="undefined"){window.initSearch=initSearch;if(window.searchIndex!==undefined){initSearch(window.searchIndex)}}else{initSearch(new Map())}})() \ No newline at end of file diff --git a/static.files/settings-4313503d2e1961c2.js b/static.files/settings-4313503d2e1961c2.js new file mode 100644 index 00000000..ab425fe4 --- /dev/null +++ b/static.files/settings-4313503d2e1961c2.js @@ -0,0 +1,17 @@ +"use strict";(function(){const isSettingsPage=window.location.pathname.endsWith("/settings.html");function changeSetting(settingName,value){if(settingName==="theme"){const useSystem=value==="system preference"?"true":"false";updateLocalStorage("use-system-theme",useSystem)}updateLocalStorage(settingName,value);switch(settingName){case"theme":case"preferred-dark-theme":case"preferred-light-theme":updateTheme();updateLightAndDark();break;case"line-numbers":if(value===true){window.rustdoc_add_line_numbers_to_examples()}else{window.rustdoc_remove_line_numbers_from_examples()}break;case"hide-sidebar":if(value===true){addClass(document.documentElement,"hide-sidebar")}else{removeClass(document.documentElement,"hide-sidebar")}break}}function showLightAndDark(){removeClass(document.getElementById("preferred-light-theme"),"hidden");removeClass(document.getElementById("preferred-dark-theme"),"hidden")}function hideLightAndDark(){addClass(document.getElementById("preferred-light-theme"),"hidden");addClass(document.getElementById("preferred-dark-theme"),"hidden")}function updateLightAndDark(){const useSystem=getSettingValue("use-system-theme");if(useSystem==="true"||(useSystem===null&&getSettingValue("theme")===null)){showLightAndDark()}else{hideLightAndDark()}}function setEvents(settingsElement){updateLightAndDark();onEachLazy(settingsElement.querySelectorAll("input[type=\"checkbox\"]"),toggle=>{const settingId=toggle.id;const settingValue=getSettingValue(settingId);if(settingValue!==null){toggle.checked=settingValue==="true"}toggle.onchange=()=>{changeSetting(toggle.id,toggle.checked)}});onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"),elem=>{const settingId=elem.name;let settingValue=getSettingValue(settingId);if(settingId==="theme"){const useSystem=getSettingValue("use-system-theme");if(useSystem==="true"||settingValue===null){settingValue=useSystem==="false"?"light":"system preference"}}if(settingValue!==null&&settingValue!=="null"){elem.checked=settingValue===elem.value}elem.addEventListener("change",ev=>{changeSetting(ev.target.name,ev.target.value)})})}function buildSettingsPageSections(settings){let output="";for(const setting of settings){const js_data_name=setting["js_name"];const setting_name=setting["name"];if(setting["options"]!==undefined){output+=`\ +
+
${setting_name}
+
`;onEach(setting["options"],option=>{const checked=option===setting["default"]?" checked":"";const full=`${js_data_name}-${option.replace(/ /g,"-")}`;output+=`\ + `});output+=`\ +
+
`}else{const checked=setting["default"]===true?" checked":"";output+=`\ +
\ + \ +
`}}return output}function buildSettingsPage(){const theme_names=getVar("themes").split(",").filter(t=>t);theme_names.push("light","dark","ayu");const settings=[{"name":"Theme","js_name":"theme","default":"system preference","options":theme_names.concat("system preference"),},{"name":"Preferred light theme","js_name":"preferred-light-theme","default":"light","options":theme_names,},{"name":"Preferred dark theme","js_name":"preferred-dark-theme","default":"dark","options":theme_names,},{"name":"Auto-hide item contents for large items","js_name":"auto-hide-large-items","default":true,},{"name":"Auto-hide item methods' documentation","js_name":"auto-hide-method-docs","default":false,},{"name":"Auto-hide trait implementation documentation","js_name":"auto-hide-trait-implementations","default":false,},{"name":"Directly go to item in search if there is only one result","js_name":"go-to-only-result","default":false,},{"name":"Show line numbers on code examples","js_name":"line-numbers","default":false,},{"name":"Hide persistent navigation bar","js_name":"hide-sidebar","default":false,},{"name":"Disable keyboard shortcuts","js_name":"disable-shortcuts","default":false,},];const elementKind=isSettingsPage?"section":"div";const innerHTML=`
${buildSettingsPageSections(settings)}
`;const el=document.createElement(elementKind);el.id="settings";if(!isSettingsPage){el.className="popover"}el.innerHTML=innerHTML;if(isSettingsPage){document.getElementById(MAIN_ID).appendChild(el)}else{el.setAttribute("tabindex","-1");getSettingsButton().appendChild(el)}return el}const settingsMenu=buildSettingsPage();function displaySettings(){settingsMenu.style.display="";onEachLazy(settingsMenu.querySelectorAll("input[type='checkbox']"),el=>{const val=getSettingValue(el.id);const checked=val==="true";if(checked!==el.checked&&val!==null){el.checked=checked}})}function settingsBlurHandler(event){blurHandler(event,getSettingsButton(),window.hidePopoverMenus)}if(isSettingsPage){getSettingsButton().onclick=event=>{event.preventDefault()}}else{const settingsButton=getSettingsButton();const settingsMenu=document.getElementById("settings");settingsButton.onclick=event=>{if(settingsMenu.contains(event.target)){return}event.preventDefault();const shouldDisplaySettings=settingsMenu.style.display==="none";window.hideAllModals();if(shouldDisplaySettings){displaySettings()}};settingsButton.onblur=settingsBlurHandler;settingsButton.querySelector("a").onblur=settingsBlurHandler;onEachLazy(settingsMenu.querySelectorAll("input"),el=>{el.onblur=settingsBlurHandler});settingsMenu.onblur=settingsBlurHandler}setTimeout(()=>{setEvents(settingsMenu);if(!isSettingsPage){displaySettings()}removeClass(getSettingsButton(),"rotate")},0)})() \ No newline at end of file diff --git a/static.files/src-script-e66d777a5a92e9b2.js b/static.files/src-script-e66d777a5a92e9b2.js new file mode 100644 index 00000000..d0aebb85 --- /dev/null +++ b/static.files/src-script-e66d777a5a92e9b2.js @@ -0,0 +1 @@ +"use strict";(function(){const rootPath=getVar("root-path");const NAME_OFFSET=0;const DIRS_OFFSET=1;const FILES_OFFSET=2;const RUSTDOC_MOBILE_BREAKPOINT=700;function closeSidebarIfMobile(){if(window.innerWidth{removeClass(document.documentElement,"src-sidebar-expanded");updateLocalStorage("source-sidebar-show","false")};window.rustdocShowSourceSidebar=()=>{addClass(document.documentElement,"src-sidebar-expanded");updateLocalStorage("source-sidebar-show","true")};window.rustdocToggleSrcSidebar=()=>{if(document.documentElement.classList.contains("src-sidebar-expanded")){window.rustdocCloseSourceSidebar()}else{window.rustdocShowSourceSidebar()}};function createSrcSidebar(){const container=document.querySelector("nav.sidebar");const sidebar=document.createElement("div");sidebar.id="src-sidebar";let hasFoundFile=false;for(const[key,source]of srcIndex){source[NAME_OFFSET]=key;hasFoundFile=createDirEntry(source,sidebar,"",hasFoundFile)}container.appendChild(sidebar);const selected_elem=sidebar.getElementsByClassName("selected")[0];if(typeof selected_elem!=="undefined"){selected_elem.focus()}}function highlightSrcLines(){const match=window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);if(!match){return}let from=parseInt(match[1],10);let to=from;if(typeof match[2]!=="undefined"){to=parseInt(match[2],10)}if(to{onEachLazy(e.getElementsByTagName("a"),i_e=>{removeClass(i_e,"line-highlighted")})});for(let i=from;i<=to;++i){elem=document.getElementById(i);if(!elem){break}addClass(elem,"line-highlighted")}}const handleSrcHighlight=(function(){let prev_line_id=0;const set_fragment=name=>{const x=window.scrollX,y=window.scrollY;if(browserSupportsHistoryApi()){history.replaceState(null,null,"#"+name);highlightSrcLines()}else{location.replace("#"+name)}window.scrollTo(x,y)};return ev=>{let cur_line_id=parseInt(ev.target.id,10);if(isNaN(cur_line_id)||ev.ctrlKey||ev.altKey||ev.metaKey){return}ev.preventDefault();if(ev.shiftKey&&prev_line_id){if(prev_line_id>cur_line_id){const tmp=prev_line_id;prev_line_id=cur_line_id;cur_line_id=tmp}set_fragment(prev_line_id+"-"+cur_line_id)}else{prev_line_id=cur_line_id;set_fragment(cur_line_id)}}}());window.addEventListener("hashchange",highlightSrcLines);onEachLazy(document.getElementsByClassName("src-line-numbers"),el=>{el.addEventListener("click",handleSrcHighlight)});highlightSrcLines();window.createSrcSidebar=createSrcSidebar})() \ No newline at end of file diff --git a/static.files/storage-4c98445ec4002617.js b/static.files/storage-4c98445ec4002617.js new file mode 100644 index 00000000..b378b856 --- /dev/null +++ b/static.files/storage-4c98445ec4002617.js @@ -0,0 +1 @@ +"use strict";const builtinThemes=["light","dark","ayu"];const darkThemes=["dark","ayu"];window.currentTheme=document.getElementById("themeStyle");const settingsDataset=(function(){const settingsElement=document.getElementById("default-settings");return settingsElement&&settingsElement.dataset?settingsElement.dataset:null})();function getSettingValue(settingName){const current=getCurrentValue(settingName);if(current===null&&settingsDataset!==null){const def=settingsDataset[settingName.replace(/-/g,"_")];if(def!==undefined){return def}}return current}const localStoredTheme=getSettingValue("theme");function hasClass(elem,className){return elem&&elem.classList&&elem.classList.contains(className)}function addClass(elem,className){if(elem&&elem.classList){elem.classList.add(className)}}function removeClass(elem,className){if(elem&&elem.classList){elem.classList.remove(className)}}function onEach(arr,func){for(const elem of arr){if(func(elem)){return true}}return false}function onEachLazy(lazyArray,func){return onEach(Array.prototype.slice.call(lazyArray),func)}function updateLocalStorage(name,value){try{window.localStorage.setItem("rustdoc-"+name,value)}catch(e){}}function getCurrentValue(name){try{return window.localStorage.getItem("rustdoc-"+name)}catch(e){return null}}const getVar=(function getVar(name){const el=document.querySelector("head > meta[name='rustdoc-vars']");return el?el.attributes["data-"+name].value:null});function switchTheme(newThemeName,saveTheme){const themeNames=getVar("themes").split(",").filter(t=>t);themeNames.push(...builtinThemes);if(themeNames.indexOf(newThemeName)===-1){return}if(saveTheme){updateLocalStorage("theme",newThemeName)}document.documentElement.setAttribute("data-theme",newThemeName);if(builtinThemes.indexOf(newThemeName)!==-1){if(window.currentTheme){window.currentTheme.parentNode.removeChild(window.currentTheme);window.currentTheme=null}}else{const newHref=getVar("root-path")+encodeURIComponent(newThemeName)+getVar("resource-suffix")+".css";if(!window.currentTheme){if(document.readyState==="loading"){document.write(``);window.currentTheme=document.getElementById("themeStyle")}else{window.currentTheme=document.createElement("link");window.currentTheme.rel="stylesheet";window.currentTheme.id="themeStyle";window.currentTheme.href=newHref;document.documentElement.appendChild(window.currentTheme)}}else if(newHref!==window.currentTheme.href){window.currentTheme.href=newHref}}}const updateTheme=(function(){const mql=window.matchMedia("(prefers-color-scheme: dark)");function updateTheme(){if(getSettingValue("use-system-theme")!=="false"){const lightTheme=getSettingValue("preferred-light-theme")||"light";const darkTheme=getSettingValue("preferred-dark-theme")||"dark";updateLocalStorage("use-system-theme","true");switchTheme(mql.matches?darkTheme:lightTheme,true)}else{switchTheme(getSettingValue("theme"),false)}}mql.addEventListener("change",updateTheme);return updateTheme})();if(getSettingValue("use-system-theme")!=="false"&&window.matchMedia){if(getSettingValue("use-system-theme")===null&&getSettingValue("preferred-dark-theme")===null&&darkThemes.indexOf(localStoredTheme)>=0){updateLocalStorage("preferred-dark-theme",localStoredTheme)}}updateTheme();if(getSettingValue("source-sidebar-show")==="true"){addClass(document.documentElement,"src-sidebar-expanded")}if(getSettingValue("hide-sidebar")==="true"){addClass(document.documentElement,"hide-sidebar")}function updateSidebarWidth(){const desktopSidebarWidth=getSettingValue("desktop-sidebar-width");if(desktopSidebarWidth&&desktopSidebarWidth!=="null"){document.documentElement.style.setProperty("--desktop-sidebar-width",desktopSidebarWidth+"px")}const srcSidebarWidth=getSettingValue("src-sidebar-width");if(srcSidebarWidth&&srcSidebarWidth!=="null"){document.documentElement.style.setProperty("--src-sidebar-width",srcSidebarWidth+"px")}}updateSidebarWidth();window.addEventListener("pageshow",ev=>{if(ev.persisted){setTimeout(updateTheme,0);setTimeout(updateSidebarWidth,0)}}) \ No newline at end of file diff --git a/static.files/wheel-7b819b6101059cd0.svg b/static.files/wheel-7b819b6101059cd0.svg new file mode 100644 index 00000000..83c07f63 --- /dev/null +++ b/static.files/wheel-7b819b6101059cd0.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/trait.impl/bpaf/trait.Parser.js b/trait.impl/bpaf/trait.Parser.js new file mode 100644 index 00000000..a8ae42b6 --- /dev/null +++ b/trait.impl/bpaf/trait.Parser.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/clone/trait.Clone.js b/trait.impl/core/clone/trait.Clone.js new file mode 100644 index 00000000..ca69611f --- /dev/null +++ b/trait.impl/core/clone/trait.Clone.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl Clone for NamedArg"],["impl<'a> Clone for MetaInfo<'a>"],["impl<'a> Clone for Section<'a>"],["impl Clone for Doc"],["impl Clone for ShellComp"],["impl<T: Clone> Clone for ParsePositional<T>"],["impl Clone for ParseFailure"],["impl<T: Clone> Clone for ParseFlag<T>"],["impl Clone for Style"],["impl<T: Clone> Clone for ParseArgument<T>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/cmp/trait.Eq.js b/trait.impl/core/cmp/trait.Eq.js new file mode 100644 index 00000000..ce7712fd --- /dev/null +++ b/trait.impl/core/cmp/trait.Eq.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl Eq for Style"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/cmp/trait.PartialEq.js b/trait.impl/core/cmp/trait.PartialEq.js new file mode 100644 index 00000000..b8d4148a --- /dev/null +++ b/trait.impl/core/cmp/trait.PartialEq.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl PartialEq for Style"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/convert/trait.From.js b/trait.impl/core/convert/trait.From.js new file mode 100644 index 00000000..f7302f3b --- /dev/null +++ b/trait.impl/core/convert/trait.From.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl From<&str> for Doc"],["impl<'a> From<&'a [&'a OsStr]> for Args<'a>"],["impl<const N: usize> From<&'static [(&'static str, Style); N]> for Doc"],["impl<'a> From<&'a [&'a str]> for Args<'a>"],["impl<'a> From<&'a [String]> for Args<'a>"],["impl<'a> From<&'a [OsString]> for Args<'a>"],["impl From<&[(&str, Style)]> for Doc"],["impl<const N: usize> From<&'static [&'static str; N]> for Args<'_>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/default/trait.Default.js b/trait.impl/core/default/trait.Default.js new file mode 100644 index 00000000..327bd2e2 --- /dev/null +++ b/trait.impl/core/default/trait.Default.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl Default for Doc"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/fmt/trait.Debug.js b/trait.impl/core/fmt/trait.Debug.js new file mode 100644 index 00000000..6d4f5277 --- /dev/null +++ b/trait.impl/core/fmt/trait.Debug.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl Debug for Doc"],["impl Debug for ParseFailure"],["impl Debug for ShellComp"],["impl<'a> Debug for Section<'a>"],["impl Debug for NamedArg"],["impl Debug for Style"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/fmt/trait.Display.js b/trait.impl/core/fmt/trait.Display.js new file mode 100644 index 00000000..15790f48 --- /dev/null +++ b/trait.impl/core/fmt/trait.Display.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl Display for Doc"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Copy.js b/trait.impl/core/marker/trait.Copy.js new file mode 100644 index 00000000..5cf10265 --- /dev/null +++ b/trait.impl/core/marker/trait.Copy.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl Copy for ShellComp"],["impl<'a> Copy for Section<'a>"],["impl Copy for Style"],["impl<'a> Copy for MetaInfo<'a>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Freeze.js b/trait.impl/core/marker/trait.Freeze.js new file mode 100644 index 00000000..1d72cbee --- /dev/null +++ b/trait.impl/core/marker/trait.Freeze.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl<'a> Freeze for Args<'a>",1,["bpaf::args::Args"]],["impl<'a> Freeze for Section<'a>",1,["bpaf::buffer::manpage::Section"]],["impl<'a> Freeze for MetaInfo<'a>",1,["bpaf::buffer::MetaInfo"]],["impl Freeze for Style",1,["bpaf::buffer::Style"]],["impl Freeze for Doc",1,["bpaf::buffer::Doc"]],["impl Freeze for ShellComp",1,["bpaf::complete_shell::ShellComp"]],["impl<P> Freeze for ParseCompShell<P>
where\n P: Freeze,
",1,["bpaf::complete_shell::ParseCompShell"]],["impl Freeze for ParseFailure",1,["bpaf::error::ParseFailure"]],["impl<T> Freeze for OptionParser<T>",1,["bpaf::info::OptionParser"]],["impl Freeze for NamedArg",1,["bpaf::params::NamedArg"]],["impl<T> Freeze for ParseCommand<T>",1,["bpaf::params::ParseCommand"]],["impl<T> Freeze for ParseFlag<T>
where\n T: Freeze,
",1,["bpaf::params::ParseFlag"]],["impl<T> Freeze for ParseArgument<T>",1,["bpaf::params::ParseArgument"]],["impl<T> Freeze for ParsePositional<T>",1,["bpaf::params::ParsePositional"]],["impl<T> Freeze for ParseAny<T>",1,["bpaf::params::ParseAny"]],["impl<T, P, F, E> Freeze for ParseFallbackWith<T, P, F, E>
where\n F: Freeze,\n P: Freeze,
",1,["bpaf::structs::ParseFallbackWith"]],["impl<P> Freeze for ParseSome<P>
where\n P: Freeze,
",1,["bpaf::structs::ParseSome"]],["impl<P, C, T> Freeze for ParseCollect<P, C, T>
where\n P: Freeze,
",1,["bpaf::structs::ParseCollect"]],["impl<P, T> Freeze for ParseFallback<P, T>
where\n P: Freeze,\n T: Freeze,
",1,["bpaf::structs::ParseFallback"]],["impl<P, T> Freeze for ParseCount<P, T>
where\n P: Freeze,
",1,["bpaf::structs::ParseCount"]],["impl<P> Freeze for ParseLast<P>
where\n P: Freeze,
",1,["bpaf::structs::ParseLast"]],["impl<P> Freeze for ParseOptional<P>
where\n P: Freeze,
",1,["bpaf::structs::ParseOptional"]],["impl<P> Freeze for ParseMany<P>
where\n P: Freeze,
",1,["bpaf::structs::ParseMany"]],["impl<P> Freeze for ParseCon<P>
where\n P: Freeze,
",1,["bpaf::structs::ParseCon"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Send.js b/trait.impl/core/marker/trait.Send.js new file mode 100644 index 00000000..93598601 --- /dev/null +++ b/trait.impl/core/marker/trait.Send.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl<'a> !Send for Args<'a>",1,["bpaf::args::Args"]],["impl<'a> Send for Section<'a>",1,["bpaf::buffer::manpage::Section"]],["impl<'a> Send for MetaInfo<'a>",1,["bpaf::buffer::MetaInfo"]],["impl Send for Style",1,["bpaf::buffer::Style"]],["impl Send for Doc",1,["bpaf::buffer::Doc"]],["impl Send for ShellComp",1,["bpaf::complete_shell::ShellComp"]],["impl<P> Send for ParseCompShell<P>
where\n P: Send,
",1,["bpaf::complete_shell::ParseCompShell"]],["impl Send for ParseFailure",1,["bpaf::error::ParseFailure"]],["impl<T> !Send for OptionParser<T>",1,["bpaf::info::OptionParser"]],["impl Send for NamedArg",1,["bpaf::params::NamedArg"]],["impl<T> !Send for ParseCommand<T>",1,["bpaf::params::ParseCommand"]],["impl<T> Send for ParseFlag<T>
where\n T: Send,
",1,["bpaf::params::ParseFlag"]],["impl<T> Send for ParseArgument<T>
where\n T: Send,
",1,["bpaf::params::ParseArgument"]],["impl<T> Send for ParsePositional<T>
where\n T: Send,
",1,["bpaf::params::ParsePositional"]],["impl<T> !Send for ParseAny<T>",1,["bpaf::params::ParseAny"]],["impl<T, P, F, E> Send for ParseFallbackWith<T, P, F, E>
where\n E: Send,\n F: Send,\n P: Send,\n T: Send,
",1,["bpaf::structs::ParseFallbackWith"]],["impl<P> Send for ParseSome<P>
where\n P: Send,
",1,["bpaf::structs::ParseSome"]],["impl<P, C, T> Send for ParseCollect<P, C, T>
where\n C: Send,\n P: Send,\n T: Send,
",1,["bpaf::structs::ParseCollect"]],["impl<P, T> Send for ParseFallback<P, T>
where\n P: Send,\n T: Send,
",1,["bpaf::structs::ParseFallback"]],["impl<P, T> Send for ParseCount<P, T>
where\n P: Send,\n T: Send,
",1,["bpaf::structs::ParseCount"]],["impl<P> Send for ParseLast<P>
where\n P: Send,
",1,["bpaf::structs::ParseLast"]],["impl<P> Send for ParseOptional<P>
where\n P: Send,
",1,["bpaf::structs::ParseOptional"]],["impl<P> Send for ParseMany<P>
where\n P: Send,
",1,["bpaf::structs::ParseMany"]],["impl<P> Send for ParseCon<P>
where\n P: Send,
",1,["bpaf::structs::ParseCon"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.StructuralPartialEq.js b/trait.impl/core/marker/trait.StructuralPartialEq.js new file mode 100644 index 00000000..f98197c8 --- /dev/null +++ b/trait.impl/core/marker/trait.StructuralPartialEq.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl StructuralPartialEq for Style"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Sync.js b/trait.impl/core/marker/trait.Sync.js new file mode 100644 index 00000000..68b58a75 --- /dev/null +++ b/trait.impl/core/marker/trait.Sync.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl<'a> !Sync for Args<'a>",1,["bpaf::args::Args"]],["impl<'a> Sync for Section<'a>",1,["bpaf::buffer::manpage::Section"]],["impl<'a> Sync for MetaInfo<'a>",1,["bpaf::buffer::MetaInfo"]],["impl Sync for Style",1,["bpaf::buffer::Style"]],["impl Sync for Doc",1,["bpaf::buffer::Doc"]],["impl Sync for ShellComp",1,["bpaf::complete_shell::ShellComp"]],["impl<P> Sync for ParseCompShell<P>
where\n P: Sync,
",1,["bpaf::complete_shell::ParseCompShell"]],["impl Sync for ParseFailure",1,["bpaf::error::ParseFailure"]],["impl<T> !Sync for OptionParser<T>",1,["bpaf::info::OptionParser"]],["impl Sync for NamedArg",1,["bpaf::params::NamedArg"]],["impl<T> !Sync for ParseCommand<T>",1,["bpaf::params::ParseCommand"]],["impl<T> Sync for ParseFlag<T>
where\n T: Sync,
",1,["bpaf::params::ParseFlag"]],["impl<T> Sync for ParseArgument<T>
where\n T: Sync,
",1,["bpaf::params::ParseArgument"]],["impl<T> Sync for ParsePositional<T>
where\n T: Sync,
",1,["bpaf::params::ParsePositional"]],["impl<T> !Sync for ParseAny<T>",1,["bpaf::params::ParseAny"]],["impl<T, P, F, E> Sync for ParseFallbackWith<T, P, F, E>
where\n E: Sync,\n F: Sync,\n P: Sync,\n T: Sync,
",1,["bpaf::structs::ParseFallbackWith"]],["impl<P> Sync for ParseSome<P>
where\n P: Sync,
",1,["bpaf::structs::ParseSome"]],["impl<P, C, T> Sync for ParseCollect<P, C, T>
where\n C: Sync,\n P: Sync,\n T: Sync,
",1,["bpaf::structs::ParseCollect"]],["impl<P, T> Sync for ParseFallback<P, T>
where\n P: Sync,\n T: Sync,
",1,["bpaf::structs::ParseFallback"]],["impl<P, T> Sync for ParseCount<P, T>
where\n P: Sync,\n T: Sync,
",1,["bpaf::structs::ParseCount"]],["impl<P> Sync for ParseLast<P>
where\n P: Sync,
",1,["bpaf::structs::ParseLast"]],["impl<P> Sync for ParseOptional<P>
where\n P: Sync,
",1,["bpaf::structs::ParseOptional"]],["impl<P> Sync for ParseMany<P>
where\n P: Sync,
",1,["bpaf::structs::ParseMany"]],["impl<P> Sync for ParseCon<P>
where\n P: Sync,
",1,["bpaf::structs::ParseCon"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Unpin.js b/trait.impl/core/marker/trait.Unpin.js new file mode 100644 index 00000000..b4bd4baf --- /dev/null +++ b/trait.impl/core/marker/trait.Unpin.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl<'a> Unpin for Args<'a>",1,["bpaf::args::Args"]],["impl<'a> Unpin for Section<'a>",1,["bpaf::buffer::manpage::Section"]],["impl<'a> Unpin for MetaInfo<'a>",1,["bpaf::buffer::MetaInfo"]],["impl Unpin for Style",1,["bpaf::buffer::Style"]],["impl Unpin for Doc",1,["bpaf::buffer::Doc"]],["impl Unpin for ShellComp",1,["bpaf::complete_shell::ShellComp"]],["impl<P> Unpin for ParseCompShell<P>
where\n P: Unpin,
",1,["bpaf::complete_shell::ParseCompShell"]],["impl Unpin for ParseFailure",1,["bpaf::error::ParseFailure"]],["impl<T> Unpin for OptionParser<T>",1,["bpaf::info::OptionParser"]],["impl Unpin for NamedArg",1,["bpaf::params::NamedArg"]],["impl<T> Unpin for ParseCommand<T>",1,["bpaf::params::ParseCommand"]],["impl<T> Unpin for ParseFlag<T>
where\n T: Unpin,
",1,["bpaf::params::ParseFlag"]],["impl<T> Unpin for ParseArgument<T>
where\n T: Unpin,
",1,["bpaf::params::ParseArgument"]],["impl<T> Unpin for ParsePositional<T>
where\n T: Unpin,
",1,["bpaf::params::ParsePositional"]],["impl<T> Unpin for ParseAny<T>",1,["bpaf::params::ParseAny"]],["impl<T, P, F, E> Unpin for ParseFallbackWith<T, P, F, E>
where\n E: Unpin,\n F: Unpin,\n P: Unpin,\n T: Unpin,
",1,["bpaf::structs::ParseFallbackWith"]],["impl<P> Unpin for ParseSome<P>
where\n P: Unpin,
",1,["bpaf::structs::ParseSome"]],["impl<P, C, T> Unpin for ParseCollect<P, C, T>
where\n C: Unpin,\n P: Unpin,\n T: Unpin,
",1,["bpaf::structs::ParseCollect"]],["impl<P, T> Unpin for ParseFallback<P, T>
where\n P: Unpin,\n T: Unpin,
",1,["bpaf::structs::ParseFallback"]],["impl<P, T> Unpin for ParseCount<P, T>
where\n P: Unpin,\n T: Unpin,
",1,["bpaf::structs::ParseCount"]],["impl<P> Unpin for ParseLast<P>
where\n P: Unpin,
",1,["bpaf::structs::ParseLast"]],["impl<P> Unpin for ParseOptional<P>
where\n P: Unpin,
",1,["bpaf::structs::ParseOptional"]],["impl<P> Unpin for ParseMany<P>
where\n P: Unpin,
",1,["bpaf::structs::ParseMany"]],["impl<P> Unpin for ParseCon<P>
where\n P: Unpin,
",1,["bpaf::structs::ParseCon"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js b/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js new file mode 100644 index 00000000..7a71fbfc --- /dev/null +++ b/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl<'a> !RefUnwindSafe for Args<'a>",1,["bpaf::args::Args"]],["impl<'a> RefUnwindSafe for Section<'a>",1,["bpaf::buffer::manpage::Section"]],["impl<'a> RefUnwindSafe for MetaInfo<'a>",1,["bpaf::buffer::MetaInfo"]],["impl RefUnwindSafe for Style",1,["bpaf::buffer::Style"]],["impl RefUnwindSafe for Doc",1,["bpaf::buffer::Doc"]],["impl RefUnwindSafe for ShellComp",1,["bpaf::complete_shell::ShellComp"]],["impl<P> RefUnwindSafe for ParseCompShell<P>
where\n P: RefUnwindSafe,
",1,["bpaf::complete_shell::ParseCompShell"]],["impl RefUnwindSafe for ParseFailure",1,["bpaf::error::ParseFailure"]],["impl<T> !RefUnwindSafe for OptionParser<T>",1,["bpaf::info::OptionParser"]],["impl RefUnwindSafe for NamedArg",1,["bpaf::params::NamedArg"]],["impl<T> !RefUnwindSafe for ParseCommand<T>",1,["bpaf::params::ParseCommand"]],["impl<T> RefUnwindSafe for ParseFlag<T>
where\n T: RefUnwindSafe,
",1,["bpaf::params::ParseFlag"]],["impl<T> RefUnwindSafe for ParseArgument<T>
where\n T: RefUnwindSafe,
",1,["bpaf::params::ParseArgument"]],["impl<T> RefUnwindSafe for ParsePositional<T>
where\n T: RefUnwindSafe,
",1,["bpaf::params::ParsePositional"]],["impl<T> !RefUnwindSafe for ParseAny<T>",1,["bpaf::params::ParseAny"]],["impl<T, P, F, E> RefUnwindSafe for ParseFallbackWith<T, P, F, E>",1,["bpaf::structs::ParseFallbackWith"]],["impl<P> RefUnwindSafe for ParseSome<P>
where\n P: RefUnwindSafe,
",1,["bpaf::structs::ParseSome"]],["impl<P, C, T> RefUnwindSafe for ParseCollect<P, C, T>
where\n C: RefUnwindSafe,\n P: RefUnwindSafe,\n T: RefUnwindSafe,
",1,["bpaf::structs::ParseCollect"]],["impl<P, T> RefUnwindSafe for ParseFallback<P, T>
where\n P: RefUnwindSafe,\n T: RefUnwindSafe,
",1,["bpaf::structs::ParseFallback"]],["impl<P, T> RefUnwindSafe for ParseCount<P, T>
where\n P: RefUnwindSafe,\n T: RefUnwindSafe,
",1,["bpaf::structs::ParseCount"]],["impl<P> RefUnwindSafe for ParseLast<P>
where\n P: RefUnwindSafe,
",1,["bpaf::structs::ParseLast"]],["impl<P> RefUnwindSafe for ParseOptional<P>
where\n P: RefUnwindSafe,
",1,["bpaf::structs::ParseOptional"]],["impl<P> RefUnwindSafe for ParseMany<P>
where\n P: RefUnwindSafe,
",1,["bpaf::structs::ParseMany"]],["impl<P> RefUnwindSafe for ParseCon<P>
where\n P: RefUnwindSafe,
",1,["bpaf::structs::ParseCon"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js b/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js new file mode 100644 index 00000000..be381886 --- /dev/null +++ b/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"bpaf":[["impl<'a> !UnwindSafe for Args<'a>",1,["bpaf::args::Args"]],["impl<'a> UnwindSafe for Section<'a>",1,["bpaf::buffer::manpage::Section"]],["impl<'a> UnwindSafe for MetaInfo<'a>",1,["bpaf::buffer::MetaInfo"]],["impl UnwindSafe for Style",1,["bpaf::buffer::Style"]],["impl UnwindSafe for Doc",1,["bpaf::buffer::Doc"]],["impl UnwindSafe for ShellComp",1,["bpaf::complete_shell::ShellComp"]],["impl<P> UnwindSafe for ParseCompShell<P>
where\n P: UnwindSafe,
",1,["bpaf::complete_shell::ParseCompShell"]],["impl UnwindSafe for ParseFailure",1,["bpaf::error::ParseFailure"]],["impl<T> !UnwindSafe for OptionParser<T>",1,["bpaf::info::OptionParser"]],["impl UnwindSafe for NamedArg",1,["bpaf::params::NamedArg"]],["impl<T> !UnwindSafe for ParseCommand<T>",1,["bpaf::params::ParseCommand"]],["impl<T> UnwindSafe for ParseFlag<T>
where\n T: UnwindSafe,
",1,["bpaf::params::ParseFlag"]],["impl<T> UnwindSafe for ParseArgument<T>
where\n T: UnwindSafe,
",1,["bpaf::params::ParseArgument"]],["impl<T> UnwindSafe for ParsePositional<T>
where\n T: UnwindSafe,
",1,["bpaf::params::ParsePositional"]],["impl<T> !UnwindSafe for ParseAny<T>",1,["bpaf::params::ParseAny"]],["impl<T, P, F, E> UnwindSafe for ParseFallbackWith<T, P, F, E>
where\n E: UnwindSafe,\n F: UnwindSafe,\n P: UnwindSafe,\n T: UnwindSafe,
",1,["bpaf::structs::ParseFallbackWith"]],["impl<P> UnwindSafe for ParseSome<P>
where\n P: UnwindSafe,
",1,["bpaf::structs::ParseSome"]],["impl<P, C, T> UnwindSafe for ParseCollect<P, C, T>
where\n C: UnwindSafe,\n P: UnwindSafe,\n T: UnwindSafe,
",1,["bpaf::structs::ParseCollect"]],["impl<P, T> UnwindSafe for ParseFallback<P, T>
where\n P: UnwindSafe,\n T: UnwindSafe,
",1,["bpaf::structs::ParseFallback"]],["impl<P, T> UnwindSafe for ParseCount<P, T>
where\n P: UnwindSafe,\n T: UnwindSafe,
",1,["bpaf::structs::ParseCount"]],["impl<P> UnwindSafe for ParseLast<P>
where\n P: UnwindSafe,
",1,["bpaf::structs::ParseLast"]],["impl<P> UnwindSafe for ParseOptional<P>
where\n P: UnwindSafe,
",1,["bpaf::structs::ParseOptional"]],["impl<P> UnwindSafe for ParseMany<P>
where\n P: UnwindSafe,
",1,["bpaf::structs::ParseMany"]],["impl<P> UnwindSafe for ParseCon<P>
where\n P: UnwindSafe,
",1,["bpaf::structs::ParseCon"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file