From 68d1d4d30a6e9ad66fb5d4401e5770c0dc610a68 Mon Sep 17 00:00:00 2001 From: Kyllingene Date: Wed, 22 Nov 2023 17:36:38 -0800 Subject: [PATCH] Improved macro docs --- src/macros/const_exprs.rs | 1 + src/macros/mod.rs | 89 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/macros/const_exprs.rs b/src/macros/const_exprs.rs index e932e23..51ae034 100644 --- a/src/macros/const_exprs.rs +++ b/src/macros/const_exprs.rs @@ -1,6 +1,7 @@ /// Compile-time string replacement. Can only substitute /// bytes for bytes (to simplify code). #[macro_export] +#[doc(hidden)] macro_rules! __replace { ( $input:expr, $from:expr, $to:expr ) => {{ const OUTPUT_LEN: usize = $input.len(); diff --git a/src/macros/mod.rs b/src/macros/mod.rs index b584168..29be299 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -1,6 +1,7 @@ pub mod const_exprs; #[macro_export] +#[doc(hidden)] macro_rules! __parse_arg { ( err => $parser:expr, $name:ident ) => { let $name = $name.get(); @@ -19,6 +20,7 @@ macro_rules! __parse_arg { } #[macro_export] +#[doc(hidden)] macro_rules! __arg_typ { ( err , $typ:ty ) => { $crate::ArgResult<$typ> @@ -34,6 +36,7 @@ macro_rules! __arg_typ { } #[macro_export] +#[doc(hidden)] macro_rules! __var_tag { ( $long:ident ) => { $crate::tag::long($crate::__replace!(stringify!($long), '_', '-')) @@ -51,6 +54,92 @@ macro_rules! __var_tag { } #[macro_export] +/// A macro to quickly define your CLI interface with struct-like syntax. +/// +/// # Example +/// +/// ``` +/// # use sarge::prelude::*; +/// // This is a normal, non-proc macro. That means sarge is still +/// // zero-dependency! The syntax may seem a little strange at first, but it +/// // should help greatly when defining your CLI interface. +/// sarge! { +/// // This is the name of our struct. +/// Args, +/// +/// // These are our arguments. Each will have a long variant matching the +/// // field name one-to-one, with one exception: all underscores are +/// // replaced by dashes at compile-time. +/// // +/// // The hashtags denote the arg 'wrapper'. No wrapper means it will be +/// // unwrapped; if the argument wasn't passed, or it failed to parse, this +/// // will panic. Thankfully, `bool` arguments are immune to both, and +/// // `String` arguments are immune to the latter. +/// +/// first: bool, // true if `--first` is passed, false otherwise +/// +/// // If you want a short variant (e.g. '-s'), you can specify one with a char +/// // literal before the name (but after the wrapper, if any): +/// 's' second: String, +/// +/// // You can also specify an environment variable counterpart. If an argument +/// // has values for both an environment variable and a CLI argument, the CLI +/// // argument takes precedence. +/// @ENV_VAR env_var: i32, +/// +/// // `#err` makes the argument an `Option>`. +/// #err foo: f32, +/// +/// // `#ok` makes the argument an `Option`, discarding any parsing errors. +/// #ok bar: f64, +/// +/// // Here's every feature in one argument: +/// // an `Option>` that can be set via `-b`, `--baz`, or `BAZ=`. +/// #err 'b' @BAZ baz: Vec, +/// } +/// +/// # macro_rules! create_args { +/// # ( $( $arg:expr ),* $(,)? ) => { +/// # [ $( $arg.to_string(), )* ] +/// # }; +/// # } +/// # +/// # macro_rules! create_env { +/// # ( $( $name:expr, $val:expr ),* $(,)? ) => { +/// # [ $( ($name.to_string(), $val.to_string()), )* ] +/// # }; +/// # } +/// +/// fn main() { +/// let args = create_args![ +/// "test", // The name of the executable. +/// "--first", +/// "-s", "Hello, World!", +/// "--bar=badnum", // The syntax `--arg=val` is valid for long tags. +/// "foobar", // This value isn't part of an argument. +/// "--baz", "1,2,3", // Remember this value... +/// ]; +/// +/// let env = create_env![ +/// "ENV_VAR", "42", +/// "BAZ", "4,5,6", // ...and this one. +/// ]; +/// +/// // Normally, you would use `::parse()` here. However, since this gets run +/// // as a test, we'll manually pass the arguments along. +/// let (args, remainder) = Args::parse_provided(&args, env.into_iter()) +/// .expect("Failed to parse arguments"); +/// +/// assert_eq!(remainder, vec!["foobar"]); +/// +/// assert!(args.first); +/// assert_eq!(args.second, "Hello, World!"); +/// assert_eq!(args.env_var, 42); +/// assert_eq!(args.foo, None); +/// assert_eq!(args.bar, None); +/// assert_eq!(args.baz, Some(Ok(vec![1, 2, 3]))); +/// } +/// ``` macro_rules! sarge { ( $v:vis $name:ident, $( $( # $spec:ident )? $( $short:literal )? $( @ $env:ident )? $av:vis $long:ident : $typ:ty ),* $(,)? ) => { $v struct $name {