pub struct OptionParser<T> {
pub(crate) inner: Box<dyn Parser<T>>,
pub(crate) info: Info,
}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.
Fields§
§inner: Box<dyn Parser<T>>§info: InfoImplementations§
Source§impl<T> OptionParser<T>
impl<T> OptionParser<T>
Sourcepub fn run(self) -> Twhere
Self: Sized,
pub fn run(self) -> Twhere
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();
}Sourcepub fn try_run(self) -> Result<T, ParseFailure>where
Self: Sized,
👎Deprecated: You should switch to equivalent parser.run_inner(Args::current_args())
pub fn try_run(self) -> Result<T, ParseFailure>where
Self: Sized,
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.
Sourcepub fn run_inner<'a>(
&self,
args: impl Into<Args<'a>>,
) -> Result<T, ParseFailure>where
Self: Sized,
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.
Sourcepub(crate) fn run_subparser(&self, args: &mut State) -> Result<T, ParseFailure>
pub(crate) fn run_subparser(&self, args: &mut State) -> Result<T, ParseFailure>
Run subparser, implementation detail
Sourcepub(crate) fn short_descr(&self) -> Option<Doc>
pub(crate) fn short_descr(&self) -> Option<Doc>
Get first line of description if Available
Used internally to avoid duplicating description for [command].
Sourcepub fn version<B: Into<Doc>>(self, version: B) -> Self
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.0Sourcepub fn descr<B: Into<Doc>>(self, descr: B) -> Self
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 footerSourcepub fn header<B: Into<Doc>>(self, header: B) -> Self
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 footerSet 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 footerSourcepub fn usage<B>(self, usage: B) -> Self
pub fn usage<B>(self, usage: B) -> Self
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
Usage: my_program [--release] [--binary=BIN] ...
- -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
Error: expected --binary=BIN, pass --help for usage information
Options { release: true, binary: "test" }
Sourcepub fn with_usage<F>(self, f: F) -> Self
pub fn with_usage<F>(self, f: F) -> 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
#[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
Usage: my_program [-r] -b=BIN
- -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
Error: expected --binary=BIN, pass --help for usage information
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();
...
}Sourcepub fn check_invariants(&self, _cosmetic: bool)
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
Sourcepub fn help_parser(self, parser: NamedArg) -> Self
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
Command with custom flags for help and version
Usage: app [-p=SPEC]
- -p=SPEC
- Package to check
- -H, --help
- Renders help information
- -v, --version
- Renders version information
Short name is now capitalized
Command with custom flags for help and version
Usage: app [-p=SPEC]
- -p=SPEC
- Package to check
- -H, --help
- Renders help information
- -v, --version
- Renders version information
and old short name no longer works.
Error: -h is not expected in this context
Same with --version parser - new description, original long name and custom short name are
both working
Version: 0.42
Version: 0.42
Sourcepub fn version_parser(self, parser: NamedArg) -> Self
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
Command with custom flags for help and version
Usage: app [-p=SPEC]
- -p=SPEC
- Package to check
- -H, --help
- Renders help information
- -v, --version
- Renders version information
Short name is now capitalized
Command with custom flags for help and version
Usage: app [-p=SPEC]
- -p=SPEC
- Package to check
- -H, --help
- Renders help information
- -v, --version
- Renders version information
and old short name no longer works.
Error: -h is not expected in this context
Same with --version parser - new description, original long name and custom short name are
both working
Version: 0.42
Version: 0.42
Sourcepub fn fallback_to_usage(self) -> Self
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();For derive macro you can specify fallback_to_usage in top level annotations
for options and for individual commands if fallback to useage is the desired behavior:
#[derive(Debug, Clone, Bpaf)]
enum Commands {
#[bpaf(command, fallback_to_usage)]
Action {
...
}
}Or
#[derive(Debug, Clone, Bpaf)]
#[bpaf(options, fallback_to_usage)]
struct Options {
...
}
fn main() {
let options = options().run(); // falls back to usage
}Sourcepub fn max_width(self, width: usize) -> Self
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>
impl<T> OptionParser<T>
Sourcepub fn command(self, name: &'static str) -> ParseCommand<T>where
T: 'static,
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
Usage: app [--flag] COMMAND ...
- --flag
- This flag is specific to the outer layer
- -h, --help
- Prints help information
- cmd, c
- Command to do something
As well as showing their own help
Command to do something
Usage: app cmd [--flag] --arg=ARG
- --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
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
Options { flag: true, cmd: Cmd { flag: false, arg: 42 } }
And this one - both inside and outside
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
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
Usage: app COMMAND ...
- -h, --help
- Prints help information
- run
- Run a binary
- build
- Compile a binary
Same as before each command gets its own help message
Run a binary
Usage: app run --bin=BIN -- [ARG]...
- ARG
- Arguments to pass to a binary
- --bin=BIN
- Name of a binary to run
- -h, --help
- Prints help information
And can be executed separately
Run { bin: "basic", args: [] }
Build { bin: "demo", release: true }