diff options
Diffstat (limited to 'vendor/xflags/src')
-rw-r--r-- | vendor/xflags/src/lib.rs | 172 | ||||
-rw-r--r-- | vendor/xflags/src/rt.rs | 14 |
2 files changed, 137 insertions, 49 deletions
diff --git a/vendor/xflags/src/lib.rs b/vendor/xflags/src/lib.rs index ae347f511..0eda9dec4 100644 --- a/vendor/xflags/src/lib.rs +++ b/vendor/xflags/src/lib.rs @@ -1,12 +1,65 @@ -//! This crates provides a procedural macro for parsing command line arguments. +//! `xflags` provides a procedural macro for parsing command line arguments. //! //! It is intended for use in development tools, so it emphasizes fast compile //! times and convenience at the expense of features. //! -//! If you need something more fancy, consider using -//! [`clap`](https://docs.rs/clap/2.33.3/clap/) instead. +//! Rough decision tree for picking an argument parsing library: //! -//! ## Example +//! * if you need all of the features and don't care about minimalism, use +//! [clap](https://github.com/clap-rs/clap) +//! * if you want to be maximally minimal, need only basic features (eg, no help +//! generation), and want to be pedantically correct, use +//! [lexopt](https://github.com/blyxxyz/lexopt) +//! * if you want to get things done fast (eg, you want auto help, but not at +//! the cost of waiting for syn to compile), consider this crate. +//! +//! The secret sauce of xflags is that it is the opposite of a derive macro. +//! Rather than generating a command line grammar from a Rust struct, `xflags` +//! generates Rust structs based on input grammar. The grammar definition is +//! both shorter and simpler to write, and is lighter on compile times. +//! +//! Here's a complete example of `parse_or_exit!` macro which parses arguments +//! into an "anonymous" struct: +//! +//! ```no_run +//! use std::path::PathBuf; +//! +//! fn main() { +//! let flags = xflags::parse_or_exit! { +//! /// Remove directories and their contents recursively. +//! optional -r,--recursive +//! /// File or directory to remove +//! required path: PathBuf +//! }; +//! +//! println!( +//! "removing {}{}", +//! flags.path.display(), +//! if flags.recursive { "recursively" } else { "" }, +//! ) +//! } +//! ``` +//! +//! The above program, when run with `--help` argument, generates the following +//! help: +//! +//! ```text +//! ARGS: +//! <path> +//! File or directory to remove +//! +//! OPTIONS: +//! -r, --recursive +//! Remove directories and their contents recursively. +//! +//! -h, --help +//! Prints help information. +//! ``` +//! +//! For larger programs, you'd typically want to use `xflags!` macro, which +//! generates _named_ structs for you. Unlike a typical macro, `xflags` writes +//! generated code into the source file, to make it easy to understand the rust +//! types at a glance. //! //! ``` //! mod flags { @@ -15,9 +68,8 @@ //! xflags::xflags! { //! src "./examples/basic.rs" //! -//! cmd my-command +//! cmd my-command { //! required path: PathBuf -//! { //! optional -v, --verbose //! } //! } @@ -28,17 +80,16 @@ //! #[derive(Debug)] //! pub struct MyCommand { //! pub path: PathBuf, -//! //! pub verbose: bool, //! } //! //! impl MyCommand { -//! pub const HELP: &'static str = Self::HELP_; -//! +//! pub fn from_env_or_exit() -> Self { +//! Self::from_env_or_exit_() +//! } //! pub fn from_env() -> xflags::Result<Self> { //! Self::from_env_() //! } -//! //! pub fn from_vec(args: Vec<std::ffi::OsString>) -> xflags::Result<Self> { //! Self::from_vec_(args) //! } @@ -52,15 +103,15 @@ //! } //! ``` //! -//! To make the macro less opaque, `xflag` can generate `struct` describing the -//! CLI in-place. To disable this behavior, omit the `src` attribute. +//! If you'd rather use a typical proc-macro which generates hidden code, just +//! omit the src attribute. //! //! xflags correctly handles non-utf8 arguments. //! //! ## Syntax Reference //! -//! The **cmd** keyword introduces a command that accepts positional arguments -//! and switches. +//! The `xflags!` macro uses **cmd** keyword to introduce a command or +//! subcommand that accepts positional arguments and switches. //! //! ``` //! xflags::xflags! { @@ -75,9 +126,9 @@ //! ``` //! xflags::xflags! { //! cmd switches { -//! optional -h, --help -//! repeated --verbose +//! optional -q,--quiet //! required --pass-me +//! repeated --verbose //! } //! } //! ``` @@ -98,20 +149,21 @@ //! } //! ``` //! -//! Positional arguments are specified before the opening curly brace: +//! Arguments without `--` in then are are positional. //! //! ``` //! use std::{path::PathBuf, ffi::OsString}; //! //! xflags::xflags! { -//! cmd positional-arguments +//! cmd positional-arguments { //! required program: PathBuf //! repeated args: OsString -//! { } +//! } //! } //! ``` //! -//! Nesting **cmd** is allowed: +//! Nesting **cmd** is allowed. `xflag` automatically generates boilerplate +//! enums for subcommands: //! //! ```ignore //! xflags::xflags! { @@ -148,12 +200,12 @@ //! } //! //! impl App { -//! pub const HELP: &'static str = Self::HELP_; -//! +//! pub fn from_env_or_exit() -> Self { +//! Self::from_env_or_exit_() +//! } //! pub fn from_env() -> xflags::Result<Self> { //! Self::from_env_() //! } -//! //! pub fn from_vec(args: Vec<std::ffi::OsString>) -> xflags::Result<Self> { //! Self::from_vec_(args) //! } @@ -161,6 +213,9 @@ //! // generated end //! ``` //! +//! Switches are always "inherited". Both `app -v foo` and `app foo -v` produce +//! the same result. +//! //! To make subcommand name optional use the **default** keyword to mark a //! subcommand to select if no subcommand name is passed. The name of the //! default subcommand affects only the name of the generated Rust struct, it @@ -176,8 +231,8 @@ //! } //! ``` //! -//! Commands, arguments, and switches can documented. Doc comments become a part -//! of generated help: +//! Commands, arguments, and switches can be documented. Doc comments become a +//! part of generated help: //! //! ``` //! mod flags { @@ -185,14 +240,11 @@ //! //! xflags::xflags! { //! /// Run basic system diagnostics. -//! cmd healthck +//! cmd healthck { //! /// Optional configuration file. //! optional config: PathBuf -//! { //! /// Verbosity level, can be repeated multiple times. //! repeated -v, --verbose -//! /// Print the help message. -//! optional -h, --help //! } //! } //! } @@ -200,24 +252,18 @@ //! fn main() { //! match flags::Healthck::from_env() { //! Ok(flags) => { -//! if flags.help { -//! println!("{}", flags::Healthck::HELP); -//! return; -//! } //! run_checks(flags.config, flags.verbose); //! } -//! Err(err) => { -//! eprintln!("{}", err); -//! } +//! Err(err) => err.exit() //! } //! } //! //! # fn run_checks(_config: Option<std::path::PathBuf>, _verbosity: u32) {} //! ``` //! -//! The **src** keyword controlls how the code generation works. If it is -//! absent, `xflags` acts as a typical procedure macro, which generates a bunch -//! of structs and impls. +//! The **src** keyword controls how the code generation works. If it is absent, +//! `xflags` acts as a typical procedure macro, which generates a bunch of +//! structs and impls. //! //! If the **src** keyword is present, it should specify the path to the file //! with `xflags!` invocation. The path should be relative to the directory with @@ -226,7 +272,7 @@ //! directly to the specified file. //! //! By convention, `xflag!` macro should be invoked from the `flags` submodule. -//! The `flags::` preffix should be used to refer to command names. Additional +//! The `flags::` prefix should be used to refer to command names. Additional //! validation logic can go to the `flags` module: //! //! ``` @@ -250,21 +296,43 @@ //! } //! } //! ``` +//! +//! The `parse_or_exit!` macro is a syntactic sure for `xflags!`, which +//! immediately parses the argument, exiting the process if needed. +//! `parse_or_exit` only supports single top-level command and doesn't need the +//! `cmd` keyword. +//! +//! ## Limitations +//! +//! `xflags` follows +//! [Fuchsia](https://fuchsia.dev/fuchsia-src/development/api/cli#command_line_arguments) +//! conventions for command line arguments. GNU conventions such as grouping +//! short-flags (`-xyz`) or gluing short flag and a value `(-fVAL)` are not +//! supported. +//! +//! `xflags` requires the command line interface to be fully static. It's +//! impossible to include additional flags at runtime. +//! +//! Implementation is not fully robust, there might be some residual bugs in +//! edge cases. use std::fmt; /// Generates a parser for command line arguments from a DSL. /// /// See the module-level for detailed syntax specification. -pub use xflags_macros::xflags; +pub use xflags_macros::{parse_or_exit, xflags}; pub type Result<T, E = Error> = std::result::Result<T, E>; -/// This type represents an error that can occur during command line argument -/// parsing. +/// An error occurred when parssing command line arguments. +/// +/// Either the command line was syntactically invalid, or `--help` was +/// explicitly requested. #[derive(Debug)] pub struct Error { msg: String, + help: bool, } impl fmt::Display for Error { @@ -280,7 +348,23 @@ impl Error { /// /// Use this to report custom validation errors. pub fn new(message: impl Into<String>) -> Error { - Error { msg: message.into() } + Error { msg: message.into(), help: false } + } + + /// Error that carries `--help` message. + pub fn is_help(&self) -> bool { + self.help + } + + /// Prints the error and exists the process. + pub fn exit(self) -> ! { + if self.is_help() { + println!("{self}"); + std::process::exit(0) + } else { + eprintln!("{self}"); + std::process::exit(2) + } } } diff --git a/vendor/xflags/src/rt.rs b/vendor/xflags/src/rt.rs index 3c33196af..988e6cc23 100644 --- a/vendor/xflags/src/rt.rs +++ b/vendor/xflags/src/rt.rs @@ -4,7 +4,7 @@ use crate::{Error, Result}; macro_rules! format_err { ($($tt:tt)*) => { - Error { msg: format!($($tt)*) } + Error { msg: format!($($tt)*), help: false } }; } @@ -94,6 +94,14 @@ impl Parser { format_err!("unexpected argument: {:?}", arg) } + pub fn subcommand_required(&self) -> Error { + format_err!("subcommand is required") + } + + pub fn help(&self, help: &'static str) -> Error { + Error { msg: help.to_string(), help: true } + } + pub fn optional<T>(&self, flag: &str, mut vals: Vec<T>) -> Result<Option<T>> { if vals.len() > 1 { bail!("flag specified more than once: `{}`", flag) @@ -107,8 +115,4 @@ impl Parser { } vals.pop().ok_or_else(|| format_err!("flag is required: `{}`", flag)) } - - pub fn subcommand<T>(&self, cmd: Option<T>) -> Result<T> { - cmd.ok_or_else(|| format_err!("subcommand is required")) - } } |