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.
Usage: app -s=SIZE (-o=PATH | -o) [-v]
- -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
(2, ToConsole, true)
And hidden means actually hidden. While error message can suggest to fix a typo to make it a valid visible argument
Error: no such flag: --verbos, did you mean --verbose?
It will not do so for hidden aliases
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
.
(10, ToFile("best.txt"), false)
If such name is not present - parser will try to consume one without, producing ToConsole
variant.
(42, ToConsole, false)
If neither is present - it fails - parser for output
expects one of its branches to succeed
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:
- 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) - If
short
orlong
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. - If
short
orlong
annotation is present with an argument - those are valuesbpaf
would use instead of the original field name - You can specify many
short
andlong
names, any past the first one of each type will become hidden aliases - If
env(arg)
annotation is present - in addition to long/short names derived according to rules 1..3bpaf
would also parse environment variablearg
which can be a string literal or an expression.
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.
Usage: app [--verbose] [-r] [-j=ARG] [-u] [-F=ARG]... --database=ARG [-q] --user=ARG
- --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
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
Error: no such flag: --quie, did you mean --quiet?
It will not do so for hidden aliases
Error: --essentia is not expected in this context
Implementations§
source§impl NamedArg
impl NamedArg
sourcepub fn short(self, short: char) -> Self
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
Options { switch: false, arg: 42, username: "Bobert" }
Help displays only visible aliases (and a current value for env arguments)
Usage: app [-s] -a=ARG -u=USER
- -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
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:
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
Error: -A is not expected in this context
sourcepub fn long(self, long: &'static str) -> Self
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
Options { switch: false, arg: 42, username: "Bobert" }
Help displays only visible aliases (and a current value for env arguments)
Usage: app [-s] -a=ARG -u=USER
- -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
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:
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
Error: -A is not expected in this context
Examples found in repository?
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
fn debug() -> impl Parser<bool> {
short('d')
.long("debug")
.help("Activate debug mode")
.switch()
}
// number of occurrences of the v/verbose flag capped at 3
fn verbose() -> impl Parser<usize> {
short('v')
.long("verbose")
.help("Increase the verbosity\nYou can specify it up to 3 times\neither as -v -v -v or as -vvv")
.req_flag(())
.many()
.map(|xs| xs.len())
.guard(|&x| x <= 3, "It doesn't get any more verbose than this")
}
// an argument, parsed and with default value
fn speed() -> impl Parser<f64> {
short('s')
.long("speed")
.help("Set speed")
.argument::<f64>("SPEED")
.fallback(42.0)
}
fn output() -> impl Parser<PathBuf> {
short('o')
.long("output")
.help("output file")
.argument::<PathBuf>("OUTPUT")
}
// no magical name transmogrifications.
fn nb_cars() -> impl Parser<u32> {
short('n').long("nb-cars").argument::<u32>("N")
}
fn files_to_process() -> impl Parser<Vec<PathBuf>> {
short('f')
.long("file")
.help("File to process")
.argument::<PathBuf>("FILE")
.many()
}
More examples
51 52 53 54 55 56 57 58 59 60 61 62 63
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()
}
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
fn main() {
let bar = short('b')
.long("bar")
.help("some bar command")
.argument::<String>("BAR")
.optional();
let bar_cmd = construct!(Foo { bar })
.to_options()
.descr("This command will try to do foo given a bar argument");
let opt = bar_cmd
.command("foo")
.help("command for doing foo")
.map(Command::Foo)
.to_options()
.run();
println!("{:#?}", opt);
}
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
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()
}
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
fn main() {
// A flag, true if used in the command line. Can be required, this one is optional
let debug = bpaf::short('d')
.long("debug")
.help("Activate debug mode")
.switch();
// an argument, parsed and with default value
let speed = bpaf::Parser::fallback(
bpaf::short('s')
.long("speed")
.help("Set speed")
.argument::<f64>("SPEED"),
42.0,
);
// packing things in a struct assumes parser for each field is in scope.
let opt = bpaf::Parser::to_options(bpaf::construct!(Out { debug, speed })).run();
println!("{:#?}", opt);
}
sourcepub fn env(self, variable: &'static str) -> Self
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
Options { switch: false, arg: 42, username: "Bobert" }
Help displays only visible aliases (and a current value for env arguments)
Usage: app [-s] -a=ARG -u=USER
- -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
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:
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
Error: -A is not expected in this context
Examples found in repository?
More examples
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
pub fn main() {
let field1 = long("field1")
.env("FIELD1")
.help("Field 1")
.argument::<u32>("ARG")
.fallback(DEFAULT_CONFIG.field1);
let field2 = long("field2")
.env("FIELD2")
.help("Field 2")
.argument::<u64>("ARG")
.fallback(DEFAULT_CONFIG.field2);
let opts = construct!(Config { field1, field2 }).to_options().run();
// At this point if you get opts - it should be taken from one of
// - the command line argument
// - the environmental variable
// - the config file
// - the hard-coded default (from config parser)
println!("{:?}", opts);
}
sourcepub fn help<M>(self, help: M) -> Self
pub fn help<M>(self, help: M) -> Self
Add a help message to a flag
/switch
/argument
bpaf
converts doc comments and string into help by following those rules:
- Everything up to the first blank line is included into a “short” help message
- Everything is included into a “long” help message
bpaf
preserves linebreaks followed by a line that starts with a space- Linebreaks are removed otherwise
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
Usage: app [-v] --name=NAME [OUTPUT]
- OUTPUT
- Save output to a file
- -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
Usage: app [-v] --name=NAME [OUTPUT]
- OUTPUT
- Save output to a file
- -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
Options { verbose: false, name: "Bob", output: Some("output.txt") }
Examples found in repository?
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
fn debug() -> impl Parser<bool> {
short('d')
.long("debug")
.help("Activate debug mode")
.switch()
}
// number of occurrences of the v/verbose flag capped at 3
fn verbose() -> impl Parser<usize> {
short('v')
.long("verbose")
.help("Increase the verbosity\nYou can specify it up to 3 times\neither as -v -v -v or as -vvv")
.req_flag(())
.many()
.map(|xs| xs.len())
.guard(|&x| x <= 3, "It doesn't get any more verbose than this")
}
// an argument, parsed and with default value
fn speed() -> impl Parser<f64> {
short('s')
.long("speed")
.help("Set speed")
.argument::<f64>("SPEED")
.fallback(42.0)
}
fn output() -> impl Parser<PathBuf> {
short('o')
.long("output")
.help("output file")
.argument::<PathBuf>("OUTPUT")
}
// no magical name transmogrifications.
fn nb_cars() -> impl Parser<u32> {
short('n').long("nb-cars").argument::<u32>("N")
}
fn files_to_process() -> impl Parser<Vec<PathBuf>> {
short('f')
.long("file")
.help("File to process")
.argument::<PathBuf>("FILE")
.many()
}
More examples
51 52 53 54 55 56 57 58 59 60 61 62 63
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()
}
- examples/env_logger.rs
- examples/many_comma_separated_args.rs
- examples/derive.rs
- examples/flatten.rs
- examples/enum_tuple.rs
- examples/customize_help.rs
- examples/xorg.rs
- examples/derive_show_asm.rs
- examples/no_import.rs
- examples/multiple_fallback.rs
- examples/rectangle.rs
- examples/csample.rs
- examples/confusing.rs
- examples/basic.rs
- examples/travel.rs
sourcepub fn switch(self) -> ParseFlag<bool>
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
Usage: app [-v] [--release] [--no-default-features]
- -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.
Options { verbose: false, release: false, default_features: true }
When value is present - switch
returns true
, flag
returns first value.
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:
Error: argument --no-default-features cannot be used multiple times in this context
Examples found in repository?
More examples
51 52 53 54 55 56 57 58 59 60 61 62 63
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()
}
24 25 26 27 28 29 30 31 32 33 34 35 36
fn main() {
let verbose = short('v').help("switch verbosity on").switch();
let user = short('u').help("daemon user").argument::<String>("USER");
let group = short('g').help("daemon group").argument::<String>("GROUP");
let daemon_opts = construct!(DaemonOpts { user, group });
let opt = construct!(Cmdline {
verbose,
daemon_opts
})
.to_options()
.run();
println!("{:?}", opt);
}
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
fn main() {
let opt = short('d')
.help("Release the dragon")
.switch()
.to_options()
.descr("I am a program and I do things")
.header("Sometimes they even work.")
.footer("Beware `-d`, dragons be here")
.with_usage(|doc| {
let mut u = Doc::default();
u.emphasis("You can call it with following flags:");
u.text(" ");
u.doc(&doc);
u
})
.run();
println!("{:?}", opt);
}
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
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()
}
sourcepub fn flag<T>(self, present: T, absent: T) -> ParseFlag<T>where
T: Clone + 'static,
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
Usage: app [--decision]
- --decision
- Positive decision
- -h, --help
- Prints help information
Presense of a long name is decoded into Yes
Options { decision: Yes }
Absense is No
Options { decision: No }
Examples found in repository?
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
fn main() {
// program takes one or more -v or --verbose flags, more flags = higher verbosity.
// parser handles number and produces a single flag.
//
// let's create it without using any single purpose magical functions
// Let's staty by creating a simple parser that handles a single -v / --verbose
// and fails otherwise;
let verbose = short('v').long("verbose").req_flag(());
// Try to apply the inner parser as many times as it succeeds, return the number
let verbose = verbose.count();
// And add a simple sanity checker.
// By this time when this parser succeeds - it will contain verbosity in 0..3 range, inclusive.
let verbose = verbose.guard(|&x| x <= 3, "it doesn't get any more verbose than 3");
// program takes --trimor --no-trimflag, but not both at once. If none is given -
// fallback value is to disable trimming. Trim enum is set accordingly
// this flag succeeds iff --no-trim is given and produces Trim::Off
let trim_off = long("no-trim").req_flag(Trim::Off);
// this flag handles two remaining cases: --trim is given (Trim::On) an fallback (Trim::Off)
let trim_on = long("trim").flag(Trim::On, Trim::Off);
// combination of previous two.
// if trim_off succeeds - trim_on never runs, otherwise trim_on tries to handle the remaining
// case before falling back to Trim:Off.
// If both --trim and --no-trim are given trim_off succeeds, trim_off never runs and --trim
// remains unused - parser fails
let trim = construct!([trim_off, trim_on]);
let parser = construct!(verbose, trim);
let opt = parser.to_options().run();
println!("{:#?}", opt);
}
sourcepub fn req_flag<T>(self, present: T) -> impl Parser<T>where
T: Clone + 'static,
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
Usage: app --agree (--intel | --att | --llvm) [--detailed | --minimal]
- --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
Error: expected --agree, pass --help for usage information
While style
takes one of several possible values
Error: expected --intel, --att, or more, pass --help for usage information
It is possible to alter the behavior using fallback
or
hide
.
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
.
Error: --llvm cannot be used at the same time as --att
Examples found in repository?
More examples
95 96 97 98 99 100 101 102 103 104 105 106
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)
})
}
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
fn opts() -> Opts {
let sensor = long("sensor").req_flag(());
let device = long("sensor-device")
.argument::<String>("DEVICE")
.complete(sensor_device_comp);
let name = long("sensor-name").argument::<String>("NAME");
// from_str needs to be replaced with `parse` that can deal with hex digits
let bus_id = long("sensor-i2c-bus").argument::<usize>("BUS");
let address = long("sensor-i2c-address").argument::<usize>("ADDRESS");
let sensors = construct!(Sensor {
sensor,
device,
name,
bus_id,
address
})
.adjacent()
.many();
construct!(Opts { sensors }).to_options().run()
}
sourcepub fn argument<T>(self, metavar: &'static str) -> ParseArgument<T>where
T: FromStr + 'static,
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
Usage: app -n=NAME [--age=AGE]
- -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
Options { name: "Bob", age: 12 }
Options { name: "Bob", age: 12 }
Options { name: "Bob", age: 18 }
Options { name: "Bob", age: 18 }
Or in case of short name - be directly adjacent to it
Options { name: "Bob", age: 18 }
For long names - this doesn’t work since parser can’t tell where name stops and argument begins:
Error: no such flag: --age12, did you mean --age?
Either way - value is required, passing just the argument name results in parse failure
Error: --name requires an argument NAME
You can further restrict it using adjacent
Examples found in repository?
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
fn speed() -> impl Parser<f64> {
short('s')
.long("speed")
.help("Set speed")
.argument::<f64>("SPEED")
.fallback(42.0)
}
fn output() -> impl Parser<PathBuf> {
short('o')
.long("output")
.help("output file")
.argument::<PathBuf>("OUTPUT")
}
// no magical name transmogrifications.
fn nb_cars() -> impl Parser<u32> {
short('n').long("nb-cars").argument::<u32>("N")
}
fn files_to_process() -> impl Parser<Vec<PathBuf>> {
short('f')
.long("file")
.help("File to process")
.argument::<PathBuf>("FILE")
.many()
}
More examples
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
fn number(name: &'static str) -> impl Parser<(String, Value)> {
let label = name.to_string();
long(name)
.argument::<usize>("NUM")
.map(move |n| (label.clone(), Value::Number(n)))
}
fn bool(name: &'static str) -> impl Parser<(String, Value)> {
let label = name.to_string();
long(name)
.switch()
.map(move |n| (label.clone(), Value::Bool(n)))
}
fn string(name: &'static str) -> impl Parser<(String, Value)> {
let label = name.to_string();
long(name)
.help("this can use a help message")
.argument::<String>("NUM")
.map(move |n| (label.clone(), Value::String(n)))
}
6 7 8 9 10 11 12 13 14 15 16 17
fn args() -> impl Parser<Vec<u16>> {
long("ports")
.help("Comma separated list of ports")
.argument::<String>("PORTS")
.parse(|s| {
s.split(',')
.map(u16::from_str)
.collect::<Result<Vec<_>, _>>()
})
.many()
.map(|nested| nested.into_iter().flatten().collect())
}
Trait Implementations§
Auto Trait Implementations§
impl Freeze for NamedArg
impl RefUnwindSafe for NamedArg
impl Send for NamedArg
impl Sync for NamedArg
impl Unpin for NamedArg
impl UnwindSafe for NamedArg
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)