bpaf/lib.rs
1#![warn(missing_docs)]
2#![allow(clippy::needless_doctest_main)]
3#![allow(clippy::redundant_else)] // not useful
4#![allow(rustdoc::redundant_explicit_links)] // two random markdown parsers I tried only supports explicit links
5#![cfg_attr(docsrs, feature(doc_auto_cfg))]
6
7//! Lightweight and flexible command line argument parser with derive and combinatoric style API
8
9//! # Quick links
10//! - [Introduction](_documentation::_0_intro) - features, design goals, restrictions
11//! - [Tutorials](_documentation::_1_tutorials) - practical learning oriented information and
12//! examples to get you started
13//! + [Types of arguments](_documentation::_1_tutorials::_0_types_of_arguments) -
14//! common types of line options and conventions (optional)
15//! + [Combinatoric API](_documentation::_1_tutorials::_1_combinatoric_api) -
16//! Parse arguments without using proc macros
17//! + [Derive API](_documentation::_1_tutorials::_2_derive_api) -
18//! Create a parser by defining a structure
19//! - [How-to and guides](_documentation::_2_howto) - assumes familiarity with the basics and
20//! explains how to concrete tasks
21//! - [Explanations](_documentation::_4_explanation) - theoretical information about abstractions
22//! used by the library, oriented for understanding
23//! - [FAQ](https://github.com/pacak/bpaf/discussions) - questions from library users
24
25//! # A quick start
26//!
27//! Add `bpaf`, optionally with derive enabled
28//!
29//! ```text
30//! $ cargo add bpaf -F derive,dull_color
31//! ```
32//!
33//! Use either derive or combinatoric API and try running it
34//!
35#![cfg_attr(not(doctest), doc = include_str!("docs2/intro.md"))]
36
37//!
38//! ## Consuming items - making `Parser`
39//!
40//! `bpaf` allows you to describe the parsers using a mix of two APIs: combinatoric and derive.
41//! Both APIs can achieve the same results, you can use one that better suits your needs. You can
42//! find documentation with more examples following those links.
43//!
44//! - For an argument with a name you define [`NamedArg`] using a combination of [`short`],
45//! [`long`] and [`env`](crate::env()). At the same time you can attach
46//! [`help`](NamedArg::help).
47//! - [`NamedArg::switch`] - simple switch that returns `true` if it's present on a command
48//! line and `false` otherwise.
49//! - [`NamedArg::flag`] - a variant of `switch` that lets you return one of two custom
50//! values, for example `Color::On` and `Color::Off`.
51//! - [`NamedArg::req_flag`] - a variant of `switch` that only only succeeds when it's name
52//! is present on a command line
53//! - [`NamedArg::argument`] - named argument containing a value, you can further
54//! customize it with [`adjacent`](crate::parsers::ParseArgument::adjacent)
55//! - [`positional`] - positional argument, you can further customize it with
56//! [`strict`](ParsePositional::strict)
57//! - [`OptionParser::command`] - subcommand parser.
58//! - [`any`] and its specialized version [`literal`] are escape hatches that can parse anything
59//! not fitting into usual classification.
60//! - [`pure`] and [`pure_with`] - a way to generate a value that can be composed without parsing
61//! it from the command line.
62//!
63//! ## Transforming and changing parsers
64//!
65//! By default primitive parsers gives you back a single `bool`, a single `PathBuf` or a single
66//! value produced by [`FromStr`] trait, etc. You can further transform it by chaining methods from
67//! [`Parser`] trait, some of those methods are applied automagically if you are using derive API.
68//!
69//! `bpaf` distinguishes two types of parse failures - "value is absent" and
70//! "value is present but invalid", most parsers listed in this section only handle the first
71//! type of failure by default, but you can use their respective `catch` method to handle the later
72//! one.
73//!
74//! - [`fallback`](Parser::fallback) and [`fallback_with`](Parser::fallback_with) - return a
75//! different value if parser fails to find what it is looking for. Generated help for former
76//! can be updated to include default value using
77//! [`display_fallback`](ParseFallback::display_fallback),
78//! [`debug_fallback`](ParseFallback::debug_fallback), or
79//! [`format_fallback`](ParseFallback::format_fallback).
80//! - [`optional`](Parser::optional) - return `None` if value is missing instead of failing, see
81//! also [`catch`](ParseOptional::catch) .
82//! - [`many`](Parser::many), [`some`](Parser::some) and [`collect`](Parser::collect) - collect
83//! multiple values into a collection, usually a vector, see their respective
84//! [`catch`](ParseMany::catch), [`catch`](ParseSome::catch) and [`catch`](ParseCollect::catch).
85//! - [`map`](Parser::map), [`parse`](Parser::parse) and [`guard`](Parser::guard) - transform
86//! and/or validate value produced by a parser
87//! - [`to_options`](Parser::to_options) - finalize the parser and prepare to run it
88//!
89//! ## Combining multiple parsers together
90//!
91//! Once you have parsers for all the primitive fields figured out you can start combining them
92//! together to produce a parser for a final result - data type you designed in the step one.
93//! For derive API you apply annotations to data types with `#[derive(Bpaf)`] and `#[bpaf(..)]`,
94//! with combinatoric API you use [`construct!`](crate::construct!) macro.
95//!
96//! All fields in a struct needs to be successfully parsed in order for the parser to succeed
97//! and only one variant from enum will consume its values at a time.
98//!
99//! You can use [`adjacent`](ParseCon::adjacent) annotation to parse multiple flags as an adjacent
100//! group allowing for more unusual scenarios such as multiple value arguments or chained commands.
101//!
102//! ## Improving user experience
103//!
104//! `bpaf` would use doc comments on fields and structures in derive mode and and values passed
105//! in various `help` methods to generate `--help` documentation, you can further improve it
106//! using those methods:
107//!
108//! - [`hide_usage`](Parser::hide_usage) and [`hide`](Parser::hide) - hide the parser from
109//! generated *Usage* line or whole generated help
110//! - [`group_help`](Parser::group_help) and [`with_group_help`](Parser::with_group_help) -
111//! add a common description shared by several parsers
112//! - [`custom_usage`](Parser::custom_usage) - customize usage for a primitive or composite parser
113//! - [`usage`](OptionParser::usage) and [`with_usage`](OptionParser::with_usage) lets you to
114//! customize whole usage line as a whole either by completely overriding it or by building around it.
115//!
116//! By default with completion enabled `bpaf` would complete names for flags, arguments and
117//! commands. You can also generate completion for argument values, possible positionals, etc.
118//! This requires enabling **autocomplete** cargo feature.
119//!
120//! - [`complete`](Parser::complete) and [`complete_shell`](Parser::complete_shell)
121//!
122//! And finally you can generate documentation for command line in markdown, html and manpage
123//! formats using [`render_markdown`](OptionParser::render_markdown),
124//! [`render_html`](OptionParser::render_html) and [`render_manpage`](OptionParser::render_manpage),
125//! for more detailed info see [`doc`] module
126//!
127//! ## Testing your parsers and running them
128//! - You can [`OptionParser::run`] the parser on the arguments passed on the command line
129//! - [`check_invariants`](OptionParser::check_invariants) checks for a few invariants in the
130//! parser `bpaf` relies on
131//! - [`run_inner`](OptionParser::run_inner) runs the parser with custom [`Args`] you can create
132//! either explicitly or implicitly using one of the [`From`] implementations, `Args` can be
133//! customized with [`set_comp`](Args::set_comp) and [`set_name`](Args::set_name).
134//! - [`ParseFailure`] contains the parse outcome, you can consume it either by hands or using one
135//! of [`exit_code`](ParseFailure::exit_code), [`unwrap_stdout`](ParseFailure::unwrap_stdout) and
136//! [`unwrap_stderr`](ParseFailure::unwrap_stderr)
137//!
138//! ## Cargo features
139//!
140//! - `derive`: adds a dependency on `bpaf_derive` crate and reexport `Bpaf` derive macro. You
141//! need to enable it to use derive API. Disabled by default.
142//!
143//! - `batteries`: helpers implemented with public `bpaf` API. Disabled by default.
144//!
145//! - `autocomplete`: enables support for shell autocompletion. Disabled by default.
146//!
147//!
148//! - `bright-color`, `dull-color`: use more colors when printing `--help` and such. Enabling
149//! either color feature adds some extra dependencies and might raise MRSV. If you are planning
150//! to use this feature in a published app - it’s best to expose them as feature flags:
151//!
152//! ```toml
153//! [features]
154//! bright-color = ["bpaf/bright-color"]
155//! dull-color = ["bpaf/dull-color"]
156//! ```
157//! Disabled by default.
158//!
159//! - `docgen`: generate documentation from help declaration, see [`OptionParser::render_markdown`] and [`doc`](crate::doc). Disabled by default.
160
161
162
163#[cfg(feature = "extradocs")]
164#[rustfmt::skip]
165#[allow(unused_imports)]
166pub mod _documentation;
167
168mod arg;
169mod args;
170#[cfg(feature = "batteries")]
171pub mod batteries;
172mod buffer;
173#[cfg(feature = "autocomplete")]
174mod complete_gen;
175#[cfg(feature = "autocomplete")]
176mod complete_run;
177#[cfg(feature = "autocomplete")]
178mod complete_shell;
179pub mod doc;
180mod error;
181mod from_os_str;
182mod info;
183mod item;
184mod meta;
185mod meta_help;
186mod meta_youmean;
187pub mod params;
188mod structs;
189#[cfg(test)]
190mod tests;
191
192pub mod parsers {
193 //! This module exposes parsers that accept further configuration with builder pattern
194 //!
195 //! In most cases you won't be using those names directly, they're only listed here to provide
196 //! access to documentation
197 #[cfg(feature = "autocomplete")]
198 #[doc(inline)]
199 pub use crate::complete_shell::ParseCompShell;
200 #[doc(inline)]
201 pub use crate::params::{
202 NamedArg, ParseAny, ParseArgument, ParseCommand, ParseFlag, ParsePositional,
203 };
204 #[doc(inline)]
205 pub use crate::structs::{
206 ParseCollect, ParseCon, ParseCount, ParseFallback, ParseFallbackWith, ParseLast, ParseMany,
207 ParseOptional, ParseSome,
208 };
209}
210
211// -------------------------------------------------------------------
212
213#[doc(inline)]
214pub use crate::{args::Args, buffer::Doc, error::ParseFailure, info::OptionParser};
215
216#[doc(hidden)]
217// used by construct macro, not part of public API
218pub use crate::{args::State, error::Error, meta::Meta, structs::ParseCon};
219
220use std::{marker::PhantomData, str::FromStr};
221
222use crate::{
223 buffer::{MetaInfo, Style},
224 item::Item,
225 params::build_positional,
226 parsers::{NamedArg, ParseAny, ParseCommand, ParsePositional},
227 structs::{
228 ParseCollect, ParseCount, ParseFail, ParseFallback, ParseFallbackWith, ParseGroupHelp,
229 ParseGuard, ParseHide, ParseLast, ParseMany, ParseMap, ParseOptional, ParseOrElse,
230 ParsePure, ParsePureWith, ParseSome, ParseUsage, ParseWith, ParseWithGroupHelp,
231 },
232};
233
234#[cfg(feature = "autocomplete")]
235pub use crate::complete_shell::ShellComp;
236#[cfg(feature = "autocomplete")]
237use structs::ParseComp;
238
239#[doc(inline)]
240#[cfg(feature = "bpaf_derive")]
241pub use bpaf_derive::Bpaf;
242
243/// Compose several parsers to produce a single result
244///
245/// # Usage reference
246/// ```rust
247/// # use bpaf::*;
248/// # { struct Res(bool, bool, bool);
249/// # let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
250/// // structs with unnamed fields:
251/// construct!(Res(a, b, c));
252/// # }
253///
254/// # { struct Res { a: bool, b: bool, c: bool }
255/// # let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
256/// // structs with named fields:
257/// construct!(Res {a, b, c});
258/// # }
259///
260/// # { enum Ty { Res(bool, bool, bool) }
261/// # let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
262/// // enums with unnamed fields:
263/// construct!(Ty::Res(a, b, c));
264/// # }
265///
266/// # { enum Ty { Res { a: bool, b: bool, c: bool } }
267/// # let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
268/// // enums with named fields:
269/// construct!(Ty::Res {a, b, c});
270/// # }
271///
272/// # { let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
273/// // tuples:
274/// construct!(a, b, c);
275/// # }
276///
277/// # { let a = short('a').switch(); let b = short('b').switch(); let c = short('c').switch();
278/// // parallel composition, tries all parsers, picks one that consumes the left most value,
279/// // or if they consume the same (or not at all) - the left most in a list
280/// construct!([a, b, c]);
281/// # }
282///
283/// // defining primitive parsers inside construct macro :)
284/// construct!(a(short('a').switch()), b(long("arg").argument::<usize>("ARG")));
285///
286/// # { let a = short('a').switch();
287/// // defining a boxed parser
288/// construct!(a);
289/// # }
290/// ```
291///
292/// # Combinatoric usage
293/// `construct!` can compose parsers sequentially or in parallel.
294///
295/// Sequential composition runs each parser and if all of them succeed you get a parser object of a
296/// new type back. Placeholder names for values inside `construct!` macro must correspond to both
297/// struct/enum names and parser names present in scope. In examples below `a` corresponds to a
298/// function and `b` corresponds to a variable name. Note parens in `a()`, you must to use them to
299/// indicate function parsers.
300///
301/// Inside the parens you can put a whole expression to use instead of
302/// having to define them in advance: `a(positional::<String>("POS"))`. Probably a good idea to use this
303/// approach only for simple parsers.
304///
305/// ```rust
306/// # use bpaf::*;
307/// struct Res (u32, u32);
308/// enum Ul { T { a: u32, b: u32 } }
309///
310/// // You can share parameters across multiple construct invocations
311/// // if defined as functions
312/// fn a() -> impl Parser<u32> {
313/// short('a').argument::<u32>("N")
314/// }
315///
316/// // You can construct structs or enums with unnamed fields
317/// fn res() -> impl Parser<Res> {
318/// let b = short('b').argument::<u32>("n");
319/// construct!(Res ( a(), b ))
320/// }
321///
322/// // You can construct structs or enums with named fields
323/// fn ult() -> impl Parser<Ul> {
324/// let b = short('b').argument::<u32>("n");
325/// construct!(Ul::T { a(), b })
326/// }
327///
328/// // You can also construct simple tuples
329/// fn tuple() -> impl Parser<(u32, u32)> {
330/// let b = short('b').argument::<u32>("n");
331/// construct!(a(), b)
332/// }
333///
334/// // You can create boxed version of parsers so the type matches as long
335/// // as return type is the same - can be useful for all sort of dynamic parsers
336/// fn boxed() -> Box<dyn Parser<u32>> {
337/// let a = short('a').argument::<u32>("n");
338/// construct!(a)
339/// }
340///
341/// // In addition to having primitives defined before using them - you can also define
342/// // them directly inside construct macro. Probably only a good idea if you have only simple
343/// // components
344/// struct Options {
345/// arg: u32,
346/// switch: bool,
347/// }
348///
349/// fn coyoda() -> impl Parser<Options> {
350/// construct!(Options {
351/// arg(short('a').argument::<u32>("ARG")),
352/// switch(short('s').switch())
353/// })
354/// }
355/// ```
356///
357/// Parallel composition picks one of several available parsers (result types must match) and returns a
358/// parser object of the same type. Similar to sequential composition you can use parsers from variables
359/// or functions:
360///
361/// ```rust
362/// # use bpaf::*;
363/// fn b() -> impl Parser<u32> {
364/// short('b').argument::<u32>("NUM")
365/// }
366///
367/// fn a_or_b() -> impl Parser<u32> {
368/// let a = short('a').argument::<u32>("NUM");
369/// // equivalent way of writing this would be `a.or_else(b())`
370/// construct!([a, b()])
371/// }
372/// ```
373///
374/// # Derive usage
375///
376/// `bpaf` would combine fields of struct or enum constructors sequentially and enum
377/// variants in parallel.
378/// ```rust
379/// # use bpaf::*;
380/// // to satisfy this parser user needs to pass both -a and -b
381/// #[derive(Debug, Clone, Bpaf)]
382/// struct Res {
383/// a: u32,
384/// b: u32,
385/// }
386///
387/// // to satisfy this parser user needs to pass one (and only one) of -a, -b, -c or -d
388/// #[derive(Debug, Clone, Bpaf)]
389/// enum Enumeraton {
390/// A { a: u32 },
391/// B { b: u32 },
392/// C { c: u32 },
393/// D { d: u32 },
394/// }
395///
396/// // here user needs to pass either both -a AND -b or both -c AND -d
397/// #[derive(Debug, Clone, Bpaf)]
398/// enum Ult {
399/// AB { a: u32, b: u32 },
400/// CD { c: u32, d: u32 }
401/// }
402/// ```
403#[macro_export]
404macro_rules! construct {
405 // construct!(Enum::Cons { a, b, c })
406 ($(::)? $ns:ident $(:: $con:ident)* { $($tokens:tt)* }) => {{ $crate::construct!(@prepare [named [$ns $(:: $con)*]] [] $($tokens)*) }};
407
408 // construct!(Enum::Cons ( a, b, c ))
409 ($(::)? $ns:ident $(:: $con:ident)* ( $($tokens:tt)* )) => {{ $crate::construct!(@prepare [pos [$ns $(:: $con)*]] [] $($tokens)*) }};
410
411 // construct!( a, b, c )
412 ($first:ident $($tokens:tt)*) => {{ $crate::construct!(@prepare [pos] [] $first $($tokens)*) }};
413
414 // construct![a, b, c]
415 ([$first:ident $($tokens:tt)*]) => {{ $crate::construct!(@prepare [alt] [] $first $($tokens)*) }};
416
417 (@prepare $ty:tt [$($fields:tt)*] $field:ident () $(, $($rest:tt)*)? ) => {{
418 let $field = $field();
419 $crate::construct!(@prepare $ty [$($fields)* $field] $($($rest)*)?)
420 }};
421 (@prepare $ty:tt [$($fields:tt)*] $field:ident ($expr:expr) $(, $($rest:tt)*)?) => {{
422 let $field = $expr;
423 $crate::construct!(@prepare $ty [$($fields)* $field] $($($rest)*)?)
424 }};
425 (@prepare $ty:tt [$($fields:tt)*] $field:ident $(, $($rest:tt)*)? ) => {{
426 $crate::construct!(@prepare $ty [$($fields)* $field] $($($rest)* )?)
427 }};
428
429 (@prepare [alt] [$first:ident $($fields:ident)*]) => {
430 #[allow(deprecated)]
431 { use $crate::Parser; $first $(.or_else($fields))* }
432 };
433
434 (@prepare $ty:tt [$($fields:tt)*]) => {
435 $crate::construct!(@fin $ty [ $($fields)* ])
436 };
437
438 (@make [named [$($con:tt)+]] [$($fields:ident)*]) => { $($con)+ { $($fields),* } };
439 (@make [pos [$($con:tt)+]] [$($fields:ident)*]) => { $($con)+ ( $($fields),* ) };
440 (@make [pos] [$($fields:ident)*]) => { ( $($fields),* ) };
441
442
443 (@fin [named [$($con:tt)+]] []) => { $crate::pure($($con)+ { })};
444 (@fin [pos [$($con:tt)+]] []) => { $crate::pure($($con)+ ( ))};
445
446 (@fin [pos] [$field:ident]) => {{
447 use $crate::Parser;
448 $field.boxed()
449 }};
450
451 (@fin $ty:tt [$front:ident $($fields:ident)*]) => {{
452 use $crate::Parser;
453 let meta = $crate::Meta::And(vec![ $front.meta(), $($fields.meta()),* ]);
454 let inner = move |failfast: bool, args: &mut $crate::State| {
455 let mut $front = $front.eval(args);
456 if failfast {
457 $front = Ok($front?);
458 }
459 $(let $fields = $fields.eval(args);)*
460 let $front = $front?;
461 $(let $fields = $fields?;)*
462
463 args.current = None;
464 ::std::result::Result::Ok::<_, $crate::Error>
465 ($crate::construct!(@make $ty [$front $($fields)*]))
466 };
467 $crate::ParseCon { inner, meta, failfast: false }
468 }};
469}
470
471/// Simple or composed argument parser
472///
473/// # Overview
474///
475/// It's best to think of an object implementing [`Parser`] trait as a container with a value
476/// inside that is composable with other `Parser` containers using [`construct!`] and the only
477/// way to extract this value is by transforming it to [`OptionParser`] with
478/// [`to_options`](Parser::to_options) and running it with [`run`](OptionParser::run). At which
479/// point you either get your value out or `bpaf` would generate a message describing a problem
480/// (missing argument, validation failure, user requested help, etc) and the program would
481/// exit.
482///
483/// Values inside can be of any type for as long as they implement `Debug`, `Clone` and
484/// there are no lifetimes other than static.
485///
486/// When consuming the values you can jump straight to a value that implements
487/// [`FromStr`] trait and then transform it into something that your program would use. Alternatively,
488/// you can consume either `String` or `OsString` and parse that by hand. It's better to perform
489/// as much parsing and validation inside the `Parser` as possible so the program itself gets
490/// strictly typed and correct value while the user gets immediate feedback on what's wrong with the
491/// arguments they pass.
492///
493/// Order of operations matters, each subsequent parser gets the output of the earlier one. Both
494/// parsers `a` and `b` would consume multiple numeric values, each less than 10, but `a`
495/// validates a single value and then consumes multiple of them already validated, while `b` first
496/// consumes and then performs validation. The former approach is usually more readable.
497/// ```rust
498/// # use bpaf::*;
499/// # fn simple() {
500/// let a = short('a').argument::<usize>("N")
501/// .guard(|&a| a < 10, "`a` must be below 10")
502/// .many();
503/// let b = short('b').argument::<usize>("N")
504/// .many()
505/// .guard(|bs| bs.iter().all(|&b| b < 10), "`b` must be below 10");
506/// # }
507/// ```
508///
509/// The same logic applies to derive API - the current type depends on the order of annotations:
510/// ```rust
511/// # use bpaf::*;
512/// # fn less_than_10(a: &usize) -> bool { true }
513/// # fn all_less_than_10(a: &Vec<usize>) -> bool { true }
514/// #[derive(Bpaf, Debug, Clone)]
515/// struct Simple {
516/// #[bpaf(argument("N"), guard(less_than_10, "`a` must be below 10"), many)]
517/// a: Vec<usize>,
518/// #[bpaf(argument("N"), many, guard(all_less_than_10, "`b` must be below 10"))]
519/// b: Vec<usize>,
520/// }
521/// ```
522///
523/// For example suppose your program needs the user to specify dimensions of a rectangle, with sides
524/// being 1..20 units long and the total area must not exceed 200 units square. A parser that
525/// consumes it might look like this:
526///
527/// ```rust
528/// # use bpaf::*;
529/// #[derive(Debug, Copy, Clone)]
530/// struct Rectangle {
531/// width: u32,
532/// height: u32,
533/// }
534///
535/// fn rectangle() -> impl Parser<Rectangle> {
536/// let invalid_size = "Sides of a rectangle must be 1..20 units long";
537/// let invalid_area = "Area of a rectangle must not exceed 200 units square";
538/// let width = long("width")
539/// .help("Width of the rectangle")
540/// .argument::<u32>("PX")
541/// .guard(|&x| 1 <= x && x <= 10, invalid_size);
542/// let height = long("height")
543/// .help("Height of the rectangle")
544/// .argument::<u32>("PX")
545/// .guard(|&x| 1 <= x && x <= 10, invalid_size);
546/// construct!(Rectangle { width, height })
547/// .guard(|&r| r.width * r.height <= 400, invalid_area)
548/// }
549/// ```
550///
551///
552/// # Derive specific considerations
553///
554/// Every method defined on this trait belongs to the `postprocessing` section of the field
555/// annotation. `bpaf` would try to figure out what chain to use for as long as there are no
556/// options changing the type: you can use [`fallback`](Parser::fallback_with),
557/// [`fallback_with`](Parser::fallback_with), [`guard`](Parser::guard), [`hide`](Parser::hide`) and
558/// [`group_help`](Parser::group_help) but not the rest of them.
559///
560/// ```rust
561/// # use bpaf::*;
562/// #[derive(Debug, Clone, Bpaf)]
563/// struct Options {
564/// // no annotation at all - `bpaf` inserts implicit `argument` and gets the right type
565/// number_1: u32,
566///
567/// // fallback isn't changing the type so `bpaf` still handles it
568/// #[bpaf(fallback(42))]
569/// number_2: u32,
570///
571/// // `bpaf` inserts implicit `argument`, `optional` and the right type
572/// number_3: Option<u32>,
573///
574/// // fails to compile: you need to specify `argument`
575/// // #[bpaf(optional)]
576/// // number_4: Option<u32>,
577///
578/// #[bpaf(argument("N"), optional)]
579/// number_5: Option<u32>,
580///
581/// // explicit consumer and a full postprocessing chain
582/// #[bpaf(argument::<u32>("N"), optional)]
583/// number_6: Option<u32>,
584/// }
585/// ```
586pub trait Parser<T> {
587 /// Evaluate inner function
588 ///
589 /// Mostly internal implementation details, you can try using it to test your parsers
590 // it's possible to move this function from the trait to the structs but having it
591 // in the trait ensures the composition always works
592 #[doc(hidden)]
593 fn eval(&self, args: &mut State) -> Result<T, Error>;
594
595 /// Included information about the parser
596 ///
597 /// Mostly internal implementation details, you can try using it to test your parsers
598 // it's possible to move this function from the trait to the structs but having it
599 // in the trait ensures the composition always works
600 #[doc(hidden)]
601 fn meta(&self) -> Meta;
602
603 // change shape
604 // {{{ many
605 /// Consume zero or more items from a command line and collect them into a [`Vec`]
606 ///
607 /// `many` preserves any parsing failures and propagates them outwards, with an extra
608 /// [`catch`](ParseMany::catch) statement you can instead stop at the first value
609 /// that failed to parse and ignore it and all the subsequent ones.
610 ///
611 /// `many` will collect at most one result that does not consume anything from the argument
612 /// list allowing using it in combination with any parsers with a fallback. After the first
613 /// one, it will keep collecting the results as long as they consume something.
614 ///
615 /// For derive usage `bpaf` would insert implicit `many` when the resulting type is a
616 /// vector.
617 ///
618 #[cfg_attr(not(doctest), doc = include_str!("docs2/many.md"))]
619 ///
620 /// # See also
621 /// [`some`](Parser::some) also collects results to a vector but requires at least one
622 /// element to succeed, [`collect`](Parser::collect) collects results into a [`FromIterator`]
623 /// structure
624 fn many(self) -> ParseMany<Self>
625 where
626 Self: Sized,
627 {
628 ParseMany {
629 inner: self,
630 catch: false,
631 }
632 }
633 // }}}
634
635 // {{{ collect
636 /// Transform parser into a collection parser
637 ///
638 /// A generic variant of [`many`](Parser::many), instead of collecting into a vector
639 /// it collects into any collection that implements [`FromIterator`] trait
640 ///
641 /// `collect` preserves any parsing failures and propagates them outwards, with extra
642 /// [`catch`](ParseCollect::catch) statement you can instead stop at the first value
643 /// that failed to parse and ignore it and all the subsequent ones.
644 ///
645 #[cfg_attr(not(doctest), doc = include_str!("docs2/collect.md"))]
646 ///
647 /// `collect` will collect at most one result that does not consume anything from the argument
648 /// list allowing using it in combination of any parsers with a fallback. After the first one
649 /// it will keep collecting the results as long as they consume something.
650 fn collect<C>(self) -> ParseCollect<Self, C, T>
651 where
652 C: FromIterator<T>,
653 Self: Sized,
654 {
655 ParseCollect {
656 inner: self,
657 catch: false,
658 ctx: PhantomData,
659 }
660 }
661 // }}}
662
663 // {{{ some
664 /// Consume one or more items from a command line and collect them into a [`Vec`]
665 ///
666 /// Takes a string used as an error message if there are no specified parameters
667 ///
668 /// `some` preserves any parsing failures and propagates them outwards, with an extra
669 /// [`catch`](ParseSome::catch) statement you can instead stop at the first value
670 /// that failed to parse and ignore it and all the subsequent ones.
671 ///
672 /// `some` will collect at most one result that does not consume anything from the argument
673 /// list allowing using it in combination with any parsers with a fallback. After the first
674 /// one, it will keep collecting the results as long as they consume something.
675 ///
676 #[cfg_attr(not(doctest), doc = include_str!("docs2/some.md"))]
677 ///
678 /// # See also
679 /// [`many`](Parser::many) also collects results to a vector but succeeds with
680 /// no matching values. [`collect`](Parser::collect) collects results into a [`FromIterator`]
681 /// structure
682 #[must_use]
683 fn some(self, message: &'static str) -> ParseSome<Self>
684 where
685 Self: Sized + Parser<T>,
686 {
687 ParseSome {
688 inner: self,
689 message,
690 catch: false,
691 }
692 }
693 // }}}
694
695 // {{{ optional
696 /// Turn a required argument into an optional one
697 ///
698 /// `optional` converts any missing items into `None` and passes the remaining parsing
699 /// failures untouched. With an extra [`catch`](ParseOptional::catch) statement, you can handle
700 /// those failures too.
701 ///
702 /// # Derive usage
703 ///
704 /// By default, `bpaf` would automatically use optional for fields of type `Option<T>`,
705 /// for as long as it's not prevented from doing so by present postprocessing options.
706 /// But it's also possible to specify it explicitly.
707 ///
708 #[cfg_attr(not(doctest), doc = include_str!("docs2/optional.md"))]
709 ///
710 #[must_use]
711 fn optional(self) -> ParseOptional<Self>
712 where
713 Self: Sized + Parser<T>,
714 {
715 ParseOptional {
716 inner: self,
717 catch: false,
718 }
719 }
720 // }}}
721
722 #[must_use]
723 /// Count how many times the inner parser succeeds, and return that number.
724 ///
725 /// When you are dealing with a parser that can succeed without consuming
726 /// anything from a command line - `bpaf` will count first such success as well.
727 ///
728 #[cfg_attr(not(doctest), doc = include_str!("docs2/count.md"))]
729 fn count(self) -> ParseCount<Self, T>
730 where
731 Self: Sized + Parser<T>,
732 {
733 ParseCount {
734 inner: self,
735 ctx: PhantomData,
736 }
737 }
738
739 #[must_use]
740 /// Apply the inner parser as many times as it succeeds, return the last value
741 ///
742 /// You can use this to allow users to pick contradicting options
743 #[cfg_attr(not(doctest), doc = include_str!("docs2/last.md"))]
744 fn last(self) -> ParseLast<Self>
745 where
746 Self: Sized + Parser<T>,
747 {
748 ParseLast { inner: self }
749 }
750
751 // parse
752 // {{{ parse
753 /// Apply a failing transformation to a contained value
754 ///
755 /// Transformation preserves the present/absent state of the value: to parse an optional value you
756 /// can either first try to `parse` it and then mark it as [`optional`](Parser::optional) or first
757 /// deal with the optionality and then parse a value wrapped in [`Option`]. In most cases
758 /// the former approach is more concise.
759 ///
760 /// Similarly, it is possible to parse multiple items with [`many`](Parser::many) or
761 /// [`some`](Parser::some) by either parsing a single item first and then turning it into a [`Vec`]
762 /// or collecting them into a [`Vec`] first and then parsing the whole vector. The former approach
763 /// is more concise.
764 ///
765 /// This is a most general of transforming parsers and you can express
766 /// [`map`](Parser::map) and [`guard`](Parser::guard) in terms of it.
767 ///
768 /// Examples are a bit artificial, to parse a value from a string you can specify
769 /// the type directly in the `argument`'s turbofish and then apply `map`.
770 ///
771 /// # Derive usage:
772 /// `parse` takes a single parameter: function name to call. Function type should match
773 /// parameter `F` used by `parse` in combinatoric API.
774 ///
775 #[cfg_attr(not(doctest), doc = include_str!("docs2/parse.md"))]
776 ///
777 fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
778 where
779 Self: Sized + Parser<T>,
780 F: Fn(T) -> Result<R, E>,
781 E: ToString,
782 {
783 ParseWith {
784 inner: self,
785 inner_res: PhantomData,
786 parse_fn: f,
787 res: PhantomData,
788 err: PhantomData,
789 }
790 }
791 // }}}
792
793 // {{{ map
794 /// Apply a pure transformation to a contained value
795 ///
796 /// A common case of the [`parse`](Parser::parse) method, exists mostly for convenience.
797 ///
798 /// # Derive usage:
799 /// The `map` takes a single parameter: function name to call. This function should transform
800 /// the value produced by the parser into a new value of the same or different type.
801 ///
802 #[cfg_attr(not(doctest), doc = include_str!("docs2/map.md"))]
803 ///
804 fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
805 where
806 Self: Sized + Parser<T>,
807 F: Fn(T) -> R + 'static,
808 {
809 ParseMap {
810 inner: self,
811 inner_res: PhantomData,
812 map_fn: map,
813 res: PhantomData,
814 }
815 }
816 // }}}
817
818 // {{{ guard
819 /// Validate or fail with a message
820 ///
821 /// If the value doesn't satisfy the constraint - the parser fails with the specified error message.
822 ///
823 /// # Derive usage
824 /// Derive variant of the `guard` takes a function name instead of a closure, mostly to keep things
825 /// clean. The second argument can be either a string literal or a constant name for a static [`str`].
826 ///
827 #[cfg_attr(not(doctest), doc = include_str!("docs2/guard.md"))]
828 ///
829 #[must_use]
830 fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
831 where
832 Self: Sized + Parser<T>,
833 F: Fn(&T) -> bool,
834 {
835 ParseGuard {
836 inner: self,
837 check,
838 message,
839 }
840 }
841 // }}}
842
843 // combine
844 // {{{ fallback
845 /// Use this value as default if the value isn't present on a command line
846 ///
847 /// Parser would still fail if the value is present but failure comes from some transformation
848 ///
849 #[cfg_attr(not(doctest), doc = include_str!("docs2/dis_fallback.md"))]
850 ///
851 /// # See also
852 /// [`fallback_with`](Parser::fallback_with) would allow to try to fallback to a value that
853 /// comes from a failing computation such as reading a file. By default, the fallback value will
854 /// not be shown in the `--help` output; you can change that by using
855 /// [`display_fallback`](ParseFallback::display_fallback),
856 /// [`debug_fallback`](ParseFallback::debug_fallback), or
857 /// [`format_fallback`](ParseFallback::format_fallback).
858 #[must_use]
859 fn fallback(self, value: T) -> ParseFallback<Self, T>
860 where
861 Self: Sized + Parser<T>,
862 {
863 ParseFallback {
864 inner: self,
865 value,
866 value_str: String::new(),
867 }
868 }
869 // }}}
870
871 // {{{ fallback_with
872 /// Use value produced by this function as default if the value isn't present
873 ///
874 /// Would still fail if the value is present but failure comes from some earlier transformation
875 ///
876 #[cfg_attr(not(doctest), doc = include_str!("docs2/dis_fallback_with.md"))]
877 ///
878 /// # See also
879 /// [`fallback`](Parser::fallback) implements similar logic expect that failures aren't expected.
880 /// By default, the fallback value will
881 /// not be shown in the `--help` output; you can change that by using
882 /// [`display_fallback`](ParseFallbackWith::display_fallback),
883 /// [`debug_fallback`](ParseFallbackWith::debug_fallback), or
884 /// [`format_fallback`](ParseFallbackWith::format_fallback).
885 #[must_use]
886 fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
887 where
888 Self: Sized + Parser<T>,
889 F: Fn() -> Result<T, E>,
890 E: ToString,
891 {
892 ParseFallbackWith {
893 inner: self,
894 inner_res: PhantomData,
895 fallback,
896 value_str: String::new(),
897 err: PhantomData,
898 }
899 }
900 // }}}
901
902 // {{{ or_else
903 /// If first parser fails - try the second one
904 ///
905 /// For parser to succeed eiter of the components needs to succeed. If both succeed - `bpaf`
906 /// would use output from one that consumed the left most value. The second flag on the command
907 /// line remains unconsumed by `or_else`.
908 ///
909 /// # Combinatoric usage:
910 /// There's two ways to write this combinator with identical results:
911 /// ```rust
912 /// # use bpaf::*;
913 /// fn a() -> impl Parser<u32> {
914 /// short('a').argument::<u32>("NUM")
915 /// }
916 ///
917 /// fn b() -> impl Parser<u32> {
918 /// short('b').argument::<u32>("NUM")
919 /// }
920 ///
921 /// fn a_or_b_comb() -> impl Parser<u32> {
922 /// construct!([a(), b()])
923 /// }
924 ///
925 /// fn a_or_b_comb2() -> impl Parser<u32> {
926 /// a().or_else(b())
927 /// }
928 /// ```
929 ///
930 /// # Example
931 /// ```console
932 /// $ app -a 12 -b 3
933 /// // 12
934 /// $ app -b 3 -a 12
935 /// // 3
936 /// $ app -b 13
937 /// // 13
938 /// $ app
939 /// // fails asking for either -a NUM or -b NUM
940 /// ```
941 ///
942 /// # Derive usage:
943 ///
944 /// `bpaf` translates enum into alternative combinations, different shapes of variants
945 /// produce different results.
946 ///
947 ///
948 /// ```bpaf
949 /// # use bpaf::*;
950 /// #[derive(Debug, Clone, Bpaf)]
951 /// enum Flag {
952 /// A { a: u32 }
953 /// B { b: u32 }
954 /// }
955 /// ```
956 ///
957 /// ```console
958 /// $ app -a 12 -b 3
959 /// // Flag::A { a: 12 }
960 /// $ app -b 3 -a 12
961 /// // Flag::B { b: 3 }
962 /// $ app -b 3
963 /// // Flag::B { b: 3 }
964 /// $ app
965 /// // fails asking for either -a NUM or -b NUM
966 /// ```
967 ///
968 /// # Performance
969 ///
970 /// `bpaf` tries to evaluate both branches regardless of the successes to produce a
971 /// better error message for combinations of mutually exclusive parsers:
972 /// Suppose program accepts one of two mutually exclusive switches `-a` and `-b`
973 /// and both are present error message should point at the second flag
974 #[doc(hidden)]
975 #[deprecated(
976 since = "0.5.0",
977 note = "instead of a.or_else(b) you should use construct!([a, b])"
978 )]
979 fn or_else<P>(self, alt: P) -> ParseOrElse<T>
980 where
981 Self: Sized + Parser<T> + 'static,
982 P: Sized + Parser<T> + 'static,
983 {
984 ParseOrElse {
985 this: Box::new(self),
986 that: Box::new(alt),
987 }
988 }
989 // }}}
990
991 // misc
992 // {{{ hide
993 /// Ignore this parser during any sort of help generation
994 ///
995 /// Best used for optional parsers or parsers with a defined fallback, usually for implementing
996 /// backward compatibility or hidden aliases
997 ///
998 #[cfg_attr(not(doctest), doc = include_str!("docs2/hide.md"))]
999 ///
1000 fn hide(self) -> ParseHide<Self>
1001 where
1002 Self: Sized + Parser<T>,
1003 {
1004 ParseHide { inner: self }
1005 }
1006 // }}}
1007
1008 /// Ignore this parser when generating a usage line
1009 ///
1010 /// Parsers hidden from usage will still show up in the available arguments list. Best used on
1011 /// optional things that augment the main application functionality but not define it.
1012 /// Alternatively, you can use [`custom_usage`](Parser::custom_usage) to replace a single
1013 /// option or a group of them with some other text.
1014 #[cfg_attr(not(doctest), doc = include_str!("docs2/hide_usage.md"))]
1015 #[must_use]
1016 fn hide_usage(self) -> ParseUsage<Self>
1017 where
1018 Self: Sized + Parser<T>,
1019 {
1020 ParseUsage {
1021 inner: self,
1022 usage: Doc::default(),
1023 }
1024 }
1025
1026 /// Customize how this parser looks like in the usage line
1027 ///
1028 #[cfg_attr(not(doctest), doc = include_str!("docs2/custom_usage.md"))]
1029 #[must_use]
1030 fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
1031 where
1032 M: Into<Doc>,
1033 Self: Sized + Parser<T>,
1034 {
1035 ParseUsage {
1036 inner: self,
1037 usage: usage.into(),
1038 }
1039 }
1040
1041 // {{{ group_help
1042 /// Attach a help message to a complex parser
1043 ///
1044 /// `bpaf` inserts the group help message before the block with all the fields
1045 /// from the inner parser and an empty line after the block.
1046 ///
1047 #[cfg_attr(not(doctest), doc = include_str!("docs2/group_help.md"))]
1048 fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
1049 where
1050 Self: Sized + Parser<T>,
1051 {
1052 ParseGroupHelp {
1053 inner: self,
1054 message: message.into(),
1055 }
1056 }
1057 // }}}
1058
1059 /// Make a help message for a complex parser from its [`MetaInfo`]
1060 ///
1061 #[cfg_attr(not(doctest), doc = include_str!("docs2/with_group_help.md"))]
1062 fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
1063 where
1064 Self: Sized + Parser<T>,
1065 F: Fn(MetaInfo) -> Doc,
1066 {
1067 ParseWithGroupHelp { inner: self, f }
1068 }
1069
1070 // {{{ comp
1071 /// Dynamic shell completion
1072 ///
1073 /// Allows to generate autocompletion information for the shell. Completer places generated input
1074 /// in place of metavar placeholders, so running `completer` on something that doesn't have a
1075 /// [`positional`] or an [`argument`](NamedArg::argument) doesn't make much sense.
1076 ///
1077 /// Takes a function as a parameter that tries to complete partial input to a full one with an
1078 /// optional description. `bpaf` would substitute a current positional item or an argument with an empty
1079 /// string if a value isn't available yet so it's best to run `complete` where parsing can't fail:
1080 /// right after [`argument`](NamedArg::argument) or [`positional`], but this isn't enforced.
1081 ///
1082 /// # Example
1083 /// ```console
1084 /// $ app --name L<TAB>
1085 /// $ app --name Lupusregina _
1086 /// ```
1087 ///
1088 #[cfg_attr(not(doctest), doc = include_str!("docs2/complete.md"))]
1089 ///
1090 /// ## A simple example
1091 ///
1092 #[cfg_attr(not(doctest), doc = include_str!("docs2/simple_dynamic.md"))]
1093 ///
1094 /// ## More detailed example
1095 ///
1096 #[cfg_attr(not(doctest), doc = include_str!("docs2/derive_show_asm.md"))]
1097 ///
1098 #[cfg(feature = "autocomplete")]
1099 fn complete<M, F>(self, op: F) -> ParseComp<Self, F>
1100 where
1101 M: Into<String>,
1102 F: Fn(&T) -> Vec<(M, Option<M>)>,
1103 Self: Sized + Parser<T>,
1104 {
1105 ParseComp {
1106 inner: self,
1107 op,
1108 group: None,
1109 }
1110 }
1111 // }}}
1112
1113 // {{{
1114 /// Static shell completion
1115 ///
1116 /// Allows to ask existing shell completion to provide some information such as a file or
1117 /// directory names or pass through existing shell completion scripts, see
1118 /// [`ShellComp`](complete_shell::ShellComp) for accessible functionality
1119 ///
1120 /// Places function calls in place of metavar placeholder, so running `complete_shell` on
1121 /// something that doesn't have a [`positional`] or [`argument`](NamedArg::argument) doesn't
1122 /// make much sense.
1123 ///
1124 /// # Example
1125 /// ```console
1126 /// $ app --output C<TAB>
1127 /// $ app --output Cargo.toml _
1128 /// ```
1129 ///
1130 /// # Combinatoric usage
1131 /// ```rust
1132 /// # use bpaf::*;
1133 /// fn output() -> impl Parser<String> {
1134 /// long("output")
1135 /// .help("Cargo.toml file to use as output")
1136 /// .argument("OUTPUT")
1137 /// .complete_shell(ShellComp::File { mask: Some("*.toml") })
1138 /// }
1139 /// ```
1140 ///
1141 /// # Derive usage
1142 /// ```rust
1143 /// # use bpaf::*;
1144 /// #[derive(Debug, Clone, Bpaf)]
1145 /// struct Options {
1146 /// /// Cargo.toml file to use as output
1147 /// #[bpaf(argument("OUTPUT"), complete_shell(ShellComp::File { mask: Some("*.toml") }))]
1148 /// output: String,
1149 /// }
1150 /// ```
1151 ///
1152 /// For multiple file types correct mask syntax is `"*.(toml|md)"`.
1153 #[cfg(feature = "autocomplete")]
1154 fn complete_shell(
1155 self,
1156 op: complete_shell::ShellComp,
1157 ) -> crate::complete_shell::ParseCompShell<Self>
1158 where
1159 Self: Sized + Parser<T>,
1160 {
1161 crate::complete_shell::ParseCompShell { inner: self, op }
1162 }
1163 // }}}
1164
1165 // consume
1166 // {{{ to_options
1167 /// Transform `Parser` into [`OptionParser`] to get ready to [`run`](OptionParser::run) it
1168 ///
1169 ///
1170 /// # Derive usage
1171 /// Add a top-level `options` annotation to generate [`OptionParser`] instead of default
1172 /// [`Parser`].
1173 ///
1174 /// In addition to `options` annotation, you can also specify either `version` or
1175 /// `version(value)` annotation. The former uses version from `cargo`, later uses the
1176 /// specified value which should be an expression of type `&'static str`, see
1177 /// [`version`](OptionParser::version).
1178 ///
1179 #[cfg_attr(not(doctest), doc = include_str!("docs2/to_options.md"))]
1180 ///
1181 /// # See also
1182 /// There's some methods implemented on [`OptionParser`] directly to customize the appearance
1183 fn to_options(self) -> OptionParser<T>
1184 where
1185 Self: Sized + Parser<T> + 'static,
1186 {
1187 OptionParser {
1188 info: info::Info::default(),
1189 inner: Box::new(self),
1190 }
1191 }
1192 // }}}
1193
1194 /// Finalize and run the parser
1195 ///
1196 /// Generally, you'd want to use [`Parser::to_options`] to finalize the parser and [`OptionParser::run`],
1197 /// but this also works for simple cases:
1198 ///
1199 /// ```no_run
1200 /// # use bpaf::*;
1201 /// fn main() {
1202 /// let name = short('n').long("name").argument::<String>("USER").run();
1203 /// // do things with name
1204 /// }
1205 /// ```
1206 fn run(self) -> T
1207 where
1208 Self: Sized + Parser<T> + 'static,
1209 {
1210 self.to_options().run()
1211 }
1212
1213 /// Create a boxed representation for a parser
1214 ///
1215 /// The boxed parser doesn't expose internal representation in its type and allows to return
1216 /// of different parsers in different conditional branches
1217 ///
1218 /// You can create it with a single argument `construct` macro or by using `boxed` annotation
1219 #[cfg_attr(not(doctest), doc = include_str!("docs2/boxed.md"))]
1220 fn boxed(self) -> Box<dyn Parser<T>>
1221 where
1222 Self: Sized + Parser<T> + 'static,
1223 {
1224 Box::new(self)
1225 }
1226}
1227
1228/// Parser that produces a fixed value
1229///
1230/// This parser produces `T` without consuming anything from the command line, which can be useful
1231/// with [`construct!`]. As with any parsers, `T` should be `Clone` and `Debug`.
1232///
1233/// Both `pure` and [`pure_with`] are designed to put values into structures, to generate fallback
1234/// you should be using [`fallback`](Parser::fallback) and [`fallback_with`](Parser::fallback_with).
1235///
1236/// See also [`pure_with`] for a pure computation that can fail.
1237///
1238#[cfg_attr(not(doctest), doc = include_str!("docs2/pure.md"))]
1239#[must_use]
1240pub fn pure<T>(val: T) -> ParsePure<T> {
1241 ParsePure(val)
1242}
1243
1244/// Wrap a calculated value into a `Parser`
1245///
1246/// This parser represents a possibly failing equivalent to [`pure`].
1247/// It produces `T` by invoking the provided callback without consuming anything from the command
1248/// line, which can be useful with [`construct!`]. As with any parsers, `T` should be `Clone`
1249/// and `Debug`.
1250///
1251/// Both [`pure`] and `pure_with` are designed to put values into structures, to generate fallback
1252/// you should be using [`fallback`](Parser::fallback) and [`fallback_with`](Parser::fallback_with).
1253///
1254/// See also [`pure`] for a pure computation that can't fail.
1255///
1256#[cfg_attr(not(doctest), doc = include_str!("docs2/pure_with.md"))]
1257pub fn pure_with<T, F, E>(val: F) -> ParsePureWith<T, F, E>
1258where
1259 F: Fn() -> Result<T, E>,
1260 E: ToString,
1261{
1262 ParsePureWith(val)
1263}
1264
1265/// Fail with a fixed error message
1266///
1267/// This parser produces `T` of any type but instead of producing it when asked - it fails
1268/// with a custom error message. Can be useful for creating custom logic
1269///
1270/// # Combinatoric usage
1271/// ```rust
1272/// # use bpaf::*;
1273/// fn must_agree() -> impl Parser<()> {
1274/// let a = long("accept").req_flag(());
1275/// let no_a = fail("You must accept the license agreement with --agree before proceeding");
1276/// construct!([a, no_a])
1277/// }
1278/// ```
1279///
1280/// # Example
1281/// ```console
1282/// $ app
1283/// // exits with "You must accept the license agreement with --agree before proceeding"
1284/// $ app --agree
1285/// // succeeds
1286/// ```
1287#[must_use]
1288pub fn fail<T>(msg: &'static str) -> ParseFail<T> {
1289 ParseFail {
1290 field1: msg,
1291 field2: PhantomData,
1292 }
1293}
1294
1295/// Parse a [`flag`](NamedArg::flag)/[`switch`](NamedArg::switch)/[`argument`](NamedArg::argument) that has a short name
1296///
1297/// You can chain multiple [`short`](NamedArg::short), [`long`](NamedArg::long) and
1298/// [`env`](NamedArg::env()) for multiple names. You can specify multiple names of the same type,
1299/// `bpaf` would use items past the first one as hidden aliases.
1300#[cfg_attr(not(doctest), doc = include_str!("docs2/short_long_env.md"))]
1301#[must_use]
1302pub fn short(short: char) -> NamedArg {
1303 NamedArg {
1304 short: vec![short],
1305 env: Vec::new(),
1306 long: Vec::new(),
1307 help: None,
1308 }
1309}
1310
1311/// Parse a [`flag`](NamedArg::flag)/[`switch`](NamedArg::switch)/[`argument`](NamedArg::argument) that has a long name
1312///
1313/// You can chain multiple [`short`](NamedArg::short), [`long`](NamedArg::long) and
1314/// [`env`](NamedArg::env()) for multiple names. You can specify multiple names of the same type,
1315/// `bpaf` would use items past the first one as hidden aliases.
1316///
1317#[cfg_attr(not(doctest), doc = include_str!("docs2/short_long_env.md"))]
1318#[must_use]
1319pub fn long(long: &'static str) -> NamedArg {
1320 NamedArg {
1321 short: Vec::new(),
1322 long: vec![long],
1323 env: Vec::new(),
1324 help: None,
1325 }
1326}
1327
1328/// Parse an environment variable
1329///
1330/// You can chain multiple [`short`](NamedArg::short), [`long`](NamedArg::long) and
1331/// [`env`](NamedArg::env()) for multiple names. You can specify multiple names of the same type,
1332/// `bpaf` would use items past the first one as hidden aliases.
1333///
1334/// For [`flag`](NamedArg::flag) and [`switch`](NamedArg::switch) environment variable being present
1335/// gives the same result as the flag being present, allowing to implement things like `NO_COLOR`
1336/// variables:
1337///
1338/// ```console
1339/// $ NO_COLOR=1 app --do-something
1340/// ```
1341///
1342/// If you don't specify a short or a long name - whole argument is going to be absent from the
1343/// help message. Use it combined with a named or positional argument to have a hidden fallback
1344/// that wouldn't leak sensitive info.
1345///
1346#[cfg_attr(not(doctest), doc = include_str!("docs2/short_long_env.md"))]
1347#[must_use]
1348pub fn env(variable: &'static str) -> NamedArg {
1349 NamedArg {
1350 short: Vec::new(),
1351 long: Vec::new(),
1352 help: None,
1353 env: vec![variable],
1354 }
1355}
1356
1357/// Parse a positional argument
1358///
1359/// For named flags and arguments ordering generally doesn't matter: most programs would
1360/// understand `-O2 -v` the same way as `-v -O2`, but for positional items order matters: in *nix
1361/// `cat hello world` and `cat world hello` would display contents of the same two files but in
1362/// a different order.
1363///
1364/// When using combinatoric API you can specify the type with turbofish, for parsing types
1365/// that don't implement [`FromStr`] you can use consume a `String`/`OsString` first and parse
1366/// it by hand.
1367/// ```no_run
1368/// # use bpaf::*;
1369/// fn parse_pos() -> impl Parser<usize> {
1370/// positional::<usize>("POS")
1371/// }
1372/// ```
1373///
1374/// # Important restriction
1375/// To parse positional arguments from a command line you should place parsers for all your
1376/// named values before parsers for positional items and commands. In derive API fields parsed as
1377/// positional items or commands should be at the end of your `struct`/`enum`. The same rule applies
1378/// to parsers with positional fields or commands inside: such parsers should go to the end as well.
1379///
1380/// Use [`check_invariants`](OptionParser::check_invariants) in your test to ensure correctness.
1381///
1382/// For example for non-positional `non_pos` and positional `pos` parsers
1383/// ```rust
1384/// # use bpaf::*;
1385/// # let non_pos = || short('n').switch();
1386/// # let pos = ||positional::<String>("POS");
1387/// let valid = construct!(non_pos(), pos());
1388/// let invalid = construct!(pos(), non_pos());
1389/// ```
1390///
1391/// **`bpaf` panics during help generation unless this restriction holds**
1392///
1393/// Without using `--` `bpaf` would only accept items that don't start with `-` as positional, you
1394/// can use [`any`] to work around this restriction.
1395///
1396/// By default `bpaf` accepts positional items with or without `--` where values permit, you can
1397/// further restrict the parser to accept positional items only on the right side of `--` using
1398/// [`strict`](ParsePositional::strict).
1399#[cfg_attr(not(doctest), doc = include_str!("docs2/positional.md"))]
1400#[must_use]
1401pub fn positional<T>(metavar: &'static str) -> ParsePositional<T> {
1402 build_positional(metavar)
1403}
1404
1405#[doc(hidden)]
1406#[deprecated = "You should switch from command(name, sub) to sub.command(name)"]
1407pub fn command<T>(name: &'static str, subparser: OptionParser<T>) -> ParseCommand<T>
1408where
1409 T: 'static,
1410{
1411 ParseCommand {
1412 longs: vec![name],
1413 shorts: Vec::new(),
1414 help: subparser.short_descr(),
1415 subparser,
1416 adjacent: false,
1417 }
1418}
1419
1420/// Parse a single arbitrary item from a command line
1421///
1422/// **`any` is designed to consume items that don't fit into the usual [`flag`](NamedArg::flag)
1423/// /[`switch`](NamedArg::switch)/[`argument`](NamedArg::argument)/[`positional`]/
1424/// [`command`](OptionParser::command) classification, in most cases you don't need to use it**
1425///
1426/// By default, `any` behaves similarly to [`positional`] so you should be using it near the
1427/// rightmost end of the consumer struct and it will only try to parse the first unconsumed item
1428/// on the command line. It is possible to lift this restriction by calling
1429/// [`anywhere`](ParseAny::anywhere) on the parser.
1430///
1431/// `check` argument is a function from any type `I` that implements `FromStr` to `T`.
1432/// Usually this should be `String` or `OsString`, but feel free to experiment. When
1433/// running `any` tries to parse an item on a command line into that `I` and applies the `check`
1434/// function. If the `check` succeeds - parser `any` succeeds and produces `T`, otherwise it behaves
1435/// as if it hasn't seen it. If `any` works in `anywhere` mode - it will try to parse all other
1436/// unconsumed items, otherwise, `any` fails.
1437///
1438/// # Use `any` to capture the remaining arguments
1439/// Normally you would use [`positional`] with [`strict`](ParsePositional::strict) annotation for
1440/// that, but using any allows you to blur the boundary between arguments for child process and self
1441/// process a bit more.
1442#[cfg_attr(not(doctest), doc = include_str!("docs2/any_simple.md"))]
1443///
1444/// # Use `any` to parse a non standard flag
1445///
1446#[cfg_attr(not(doctest), doc = include_str!("docs2/any_switch.md"))]
1447///
1448/// # Use `any` to parse a non standard argument
1449/// Normally `any` would try to display itself as a usual metavariable in the usage line and
1450/// generated help, you can customize that with [`metavar`](ParseAny::metavar) method:
1451///
1452#[cfg_attr(not(doctest), doc = include_str!("docs2/any_literal.md"))]
1453///
1454/// # See also
1455/// [`literal`] - a specialized version of `any` that tries to parse a fixed literal
1456#[must_use]
1457pub fn any<I, T, F>(metavar: &str, check: F) -> ParseAny<T>
1458where
1459 I: FromStr + 'static,
1460 F: Fn(I) -> Option<T> + 'static,
1461 <I as std::str::FromStr>::Err: std::fmt::Display,
1462{
1463 ParseAny {
1464 metavar: [(metavar, Style::Metavar)][..].into(),
1465 help: None,
1466 check: Box::new(move |os: std::ffi::OsString| {
1467 match crate::from_os_str::parse_os_str::<I>(os) {
1468 Ok(v) => check(v),
1469 Err(_) => None,
1470 }
1471 }),
1472
1473 anywhere: false,
1474 }
1475}
1476
1477/// A specialized version of [`any`] that consumes an arbitrary string
1478///
1479/// By default `literal` behaves similarly to [`positional`] so you should be using it near the
1480/// rightmost end of the consumer struct and it will only try to parse the first unconsumed
1481/// item on the command line. It is possible to lift this restriction by calling
1482/// [`anywhere`](ParseAny::anywhere) on the parser.
1483///
1484#[cfg_attr(not(doctest), doc = include_str!("docs2/any_literal.md"))]
1485///
1486/// # See also
1487/// [`any`] - a generic version of `literal` that uses function to decide if value is to be parsed
1488/// or not.
1489#[must_use]
1490pub fn literal(val: &'static str) -> ParseAny<()> {
1491 any("", move |s: String| if s == val { Some(()) } else { None })
1492 .metavar(&[(val, crate::buffer::Style::Literal)][..])
1493}
1494
1495/// Strip a command name if present at the front when used as a `cargo` command
1496///
1497// this is exactly the same as batteries::cargo_helper, but used by derive macro...
1498#[must_use]
1499#[doc(hidden)]
1500pub fn cargo_helper<P, T>(cmd: &'static str, parser: P) -> impl Parser<T>
1501where
1502 T: 'static,
1503 P: Parser<T>,
1504{
1505 let skip = literal(cmd).optional().hide();
1506 construct!(skip, parser).map(|x| x.1)
1507}
1508
1509/// Choose between several parsers specified at runtime
1510///
1511/// You can use this function to create multiple parsers that produce the same type of value at a runtime
1512/// and let bpaf to pick one that best fits best. This function is designed to work in Combinatoric
1513/// API, but you can use it in Derive API with `extern`.
1514///
1515#[cfg_attr(not(doctest), doc = include_str!("docs2/choice.md"))]
1516pub fn choice<T: 'static>(parsers: impl IntoIterator<Item = Box<dyn Parser<T>>>) -> impl Parser<T> {
1517 let mut parsers = parsers.into_iter();
1518 let mut this = match parsers.next() {
1519 None => return fail("Invalid choice usage").boxed(),
1520 Some(p) => p,
1521 };
1522 for that in parsers {
1523 this = Box::new(ParseOrElse { this, that })
1524 }
1525 this
1526}