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