diff --git a/README.md b/README.md index 0cfcbb2..e8e6060 100644 --- a/README.md +++ b/README.md @@ -48,17 +48,17 @@ enum Arg { // The doc strings below will be part of the `--help` text // First we define a simple flag: /// Do not transform input text to uppercase - #[option("-n", "--no-caps")] + #[arg("-n", "--no-caps")] NoCaps, - + // This option takes a value: /// Add exclamation marks to output - #[option("-e N", "--exclaim=N")] + #[arg("-e N", "--exclaim=N")] ExclamationMarks(u8), // This is a positional argument, the range specifies that // at least one positional argument must be passed. - #[positional(1..)] + #[arg("TEXT", 1..)] Text(String), } diff --git a/derive/src/argument.rs b/derive/src/argument.rs index 3854be5..7e3928a 100644 --- a/derive/src/argument.rs +++ b/derive/src/argument.rs @@ -8,18 +8,18 @@ use quote::quote; use syn::{Attribute, Fields, FieldsUnnamed, Ident, Meta, Variant}; use crate::{ - attributes::{parse_argument_attribute, ArgAttr, ArgumentsAttr}, + attributes::{ArgAttr, ArgumentsAttr}, flags::{Flags, Value}, }; -pub(crate) struct Argument { - pub(crate) ident: Ident, - pub(crate) name: String, - pub(crate) arg_type: ArgType, - pub(crate) help: String, +pub struct Argument { + pub ident: Ident, + pub name: String, + pub arg_type: ArgType, + pub help: String, } -pub(crate) enum ArgType { +pub enum ArgType { Option { flags: Flags, hidden: bool, @@ -35,7 +35,7 @@ pub(crate) enum ArgType { }, } -pub(crate) fn parse_arguments_attr(attrs: &[Attribute]) -> ArgumentsAttr { +pub fn parse_arguments_attr(attrs: &[Attribute]) -> ArgumentsAttr { for attr in attrs { if attr.path().is_ident("arguments") { return ArgumentsAttr::parse(attr).unwrap(); @@ -44,7 +44,7 @@ pub(crate) fn parse_arguments_attr(attrs: &[Attribute]) -> ArgumentsAttr { ArgumentsAttr::default() } -pub(crate) fn parse_argument(v: Variant) -> Vec { +pub fn parse_argument(v: Variant) -> Vec { let ident = v.ident; let name = ident.to_string(); let attributes = get_arg_attributes(&v.attrs).unwrap(); @@ -138,16 +138,12 @@ fn collect_help(attrs: &[Attribute]) -> String { fn get_arg_attributes(attrs: &[Attribute]) -> syn::Result> { attrs .iter() - .filter(|a| { - a.path().is_ident("option") - || a.path().is_ident("positional") - || a.path().is_ident("free") - }) - .map(parse_argument_attribute) + .filter(|a| a.path().is_ident("arg")) + .map(ArgAttr::parse) .collect() } -pub(crate) fn short_handling(args: &[Argument]) -> (TokenStream, Vec) { +pub fn short_handling(args: &[Argument]) -> (TokenStream, Vec) { let mut match_arms = Vec::new(); let mut short_flags = Vec::new(); @@ -195,7 +191,7 @@ pub(crate) fn short_handling(args: &[Argument]) -> (TokenStream, Vec) { (token_stream, short_flags) } -pub(crate) fn long_handling(args: &[Argument], help_flags: &Flags) -> TokenStream { +pub fn long_handling(args: &[Argument], help_flags: &Flags) -> TokenStream { let mut match_arms = Vec::new(); let mut options = Vec::new(); @@ -270,7 +266,7 @@ pub(crate) fn long_handling(args: &[Argument], help_flags: &Flags) -> TokenStrea ) } -pub(crate) fn free_handling(args: &[Argument]) -> TokenStream { +pub fn free_handling(args: &[Argument]) -> TokenStream { let mut if_expressions = Vec::new(); // Free arguments @@ -337,7 +333,7 @@ pub(crate) fn free_handling(args: &[Argument]) -> TokenStream { ) } -pub(crate) fn positional_handling(args: &[Argument]) -> (TokenStream, TokenStream) { +pub fn positional_handling(args: &[Argument]) -> (TokenStream, TokenStream) { let mut match_arms = Vec::new(); // The largest index of the previous argument, so the the argument after this should // belong to the next argument. diff --git a/derive/src/attributes.rs b/derive/src/attributes.rs index e8c915c..fc56dc7 100644 --- a/derive/src/attributes.rs +++ b/derive/src/attributes.rs @@ -10,83 +10,12 @@ use syn::{ use crate::flags::Flags; -pub(crate) enum ArgAttr { - Option(OptionAttr), - Positional(PositionalAttr), - Free(FreeAttr), -} - -pub(crate) fn parse_argument_attribute(attr: &Attribute) -> syn::Result { - if attr.path().is_ident("option") { - Ok(ArgAttr::Option(OptionAttr::parse(attr)?)) - } else if attr.path().is_ident("positional") { - Ok(ArgAttr::Positional(PositionalAttr::parse(attr)?)) - } else if attr.path().is_ident("free") { - Ok(ArgAttr::Free(FreeAttr::parse(attr)?)) - } else { - panic!("Internal error: invalid argument attribute"); - } -} - -pub(crate) struct ArgumentsAttr { - pub(crate) help_flags: Flags, - pub(crate) version_flags: Flags, - pub(crate) file: Option, - pub(crate) exit_code: i32, - pub(crate) parse_echo_style: bool, -} - -fn get_ident(meta: &ParseNestedMeta) -> syn::Result { - match meta.path.get_ident() { - Some(ident) => Ok(ident.to_string()), - None => Err(meta.error("expected an identifier")), - } -} - -fn assert_expr_is_array_of_litstr(expr: Expr, flag: &str) -> syn::Result> { - let arr = match expr { - syn::Expr::Array(arr) => arr, - _ => { - return Err(syn::Error::new_spanned( - expr, - format!("Argument to `{flag}` must be an array"), - )) - } - }; - - let mut strings = Vec::new(); - for elem in arr.elems { - let val = match elem { - syn::Expr::Lit(syn::ExprLit { - attrs: _, - lit: syn::Lit::Str(litstr), - }) => litstr.value(), - _ => { - return Err(syn::Error::new_spanned( - elem, - format!("Argument to `{flag}` must be an array of string literals"), - )) - } - }; - strings.push(val); - } - Ok(strings) -} - -fn parse_args( - attr: &Attribute, - mut logic: impl FnMut(ParseStream) -> syn::Result<()>, -) -> syn::Result<()> { - attr.parse_args_with(|s: ParseStream| loop { - logic(s)?; - if s.is_empty() { - return Ok(()); - } - s.parse::()?; - if s.is_empty() { - return Ok(()); - } - }) +pub struct ArgumentsAttr { + pub help_flags: Flags, + pub version_flags: Flags, + pub file: Option, + pub exit_code: i32, + pub parse_echo_style: bool, } impl Default for ArgumentsAttr { @@ -102,7 +31,7 @@ impl Default for ArgumentsAttr { } impl ArgumentsAttr { - pub(crate) fn parse(attr: &Attribute) -> syn::Result { + pub fn parse(attr: &Attribute) -> syn::Result { let mut args = ArgumentsAttr::default(); attr.parse_nested_meta(|meta| { @@ -138,27 +67,57 @@ impl ArgumentsAttr { } } +pub enum ArgAttr { + Option(OptionAttr), + Positional(PositionalAttr), + Free(FreeAttr), +} + +impl ArgAttr { + pub fn parse(attr: &Attribute) -> syn::Result { + assert!(attr.path().is_ident("arg")); + + attr.parse_args_with(|s: ParseStream| { + // Based on the first value, we determine the type of argument. + if let Ok(litstr) = s.parse::() { + let v = litstr.value(); + if v.starts_with('-') || v.contains('=') { + OptionAttr::from_args(v, s).map(Self::Option) + } else { + PositionalAttr::from_args(v, s).map(Self::Positional) + } + } else if let Ok(v) = s.parse::() { + FreeAttr::from_args(v, s).map(Self::Free) + } else { + // TODO: Improve error message + panic!("Could not determine type of argument"); + } + }) + } +} + #[derive(Default)] -pub(crate) struct OptionAttr { - pub(crate) flags: Flags, - pub(crate) parser: Option, - pub(crate) default: Option, - pub(crate) hidden: bool, - pub(crate) help: Option, +pub struct OptionAttr { + pub flags: Flags, + pub parser: Option, + pub default: Option, + pub hidden: bool, + pub help: Option, } impl OptionAttr { - pub(crate) fn parse(attr: &Attribute) -> syn::Result { + fn from_args(first_flag: String, s: ParseStream) -> syn::Result { let mut option_attr = OptionAttr::default(); + option_attr.flags.add(&first_flag); - parse_args(attr, |s: ParseStream| { + parse_args(s, |s: ParseStream| { if let Ok(litstr) = s.parse::() { option_attr.flags.add(&litstr.value()); return Ok(()); } let ident = s.parse::()?; - match ident.to_string().as_str() { + match ident.to_string().as_ref() { "parser" => { s.parse::()?; let p = s.parse::()?; @@ -192,15 +151,16 @@ impl OptionAttr { } #[derive(Default)] -pub(crate) struct FreeAttr { - pub(crate) filters: Vec, +pub struct FreeAttr { + pub filters: Vec, } impl FreeAttr { - pub(crate) fn parse(attr: &Attribute) -> syn::Result { + pub fn from_args(first_value: syn::Ident, s: ParseStream) -> syn::Result { let mut free_attr = FreeAttr::default(); + free_attr.filters.push(first_value); - parse_args(attr, |s: ParseStream| { + parse_args(s, |s: ParseStream| { let ident = s.parse::()?; free_attr.filters.push(ident); Ok(()) @@ -210,46 +170,9 @@ impl FreeAttr { } } -#[derive(Default)] -pub(crate) struct ValueAttr { - pub(crate) keys: Vec, - pub(crate) value: Option, -} - -impl ValueAttr { - pub(crate) fn parse(attr: &Attribute) -> syn::Result { - let mut value_attr = Self::default(); - - // value does not need to take arguments, so short circuit if it does not have one - if let syn::Meta::Path(_) = &attr.meta { - return Ok(value_attr); - } - - parse_args(attr, |s: ParseStream| { - if let Ok(litstr) = s.parse::() { - value_attr.keys.push(litstr.value()); - return Ok(()); - } - - let ident = s.parse::()?; - match ident.to_string().as_str() { - "value" => { - s.parse::()?; - let p = s.parse::()?; - value_attr.value = Some(p); - } - _ => return Err(s.error("unrecognized keyword in value attribute")), - } - Ok(()) - })?; - - Ok(value_attr) - } -} - -pub(crate) struct PositionalAttr { - pub(crate) num_args: RangeInclusive, - pub(crate) last: bool, +pub struct PositionalAttr { + pub num_args: RangeInclusive, + pub last: bool, } impl Default for PositionalAttr { @@ -262,9 +185,9 @@ impl Default for PositionalAttr { } impl PositionalAttr { - pub(crate) fn parse(attr: &Attribute) -> syn::Result { + pub fn from_args(_first_value: String, s: ParseStream) -> syn::Result { let mut positional_attr = Self::default(); - parse_args(attr, |s| { + parse_args(s, |s| { if (s.peek(LitInt) && s.peek2(Token![..])) || s.peek(Token![..]) { let range = s.parse::()?; // We're dealing with a range @@ -322,3 +245,99 @@ impl PositionalAttr { Ok(positional_attr) } } + +#[derive(Default)] +pub struct ValueAttr { + pub keys: Vec, + pub value: Option, +} + +impl ValueAttr { + pub fn parse(attr: &Attribute) -> syn::Result { + let mut value_attr = Self::default(); + + // value does not need to take arguments, so short circuit if it does not have one + if let syn::Meta::Path(_) = &attr.meta { + return Ok(value_attr); + } + + attr.parse_args_with(|s: ParseStream| loop { + if let Ok(litstr) = s.parse::() { + value_attr.keys.push(litstr.value()); + } else { + let ident = s.parse::()?; + match ident.to_string().as_str() { + "value" => { + s.parse::()?; + let p = s.parse::()?; + value_attr.value = Some(p); + } + _ => return Err(s.error("unrecognized keyword in value attribute")), + } + } + + if s.is_empty() { + return Ok(()); + } + s.parse::()?; + if s.is_empty() { + return Ok(()); + } + })?; + + Ok(value_attr) + } +} + +fn parse_args( + s: ParseStream, + mut logic: impl FnMut(ParseStream) -> syn::Result<()>, +) -> syn::Result<()> { + loop { + if s.is_empty() { + return Ok(()); + } + s.parse::()?; + if s.is_empty() { + return Ok(()); + } + logic(s)?; + } +} + +fn get_ident(meta: &ParseNestedMeta) -> syn::Result { + match meta.path.get_ident() { + Some(ident) => Ok(ident.to_string()), + None => Err(meta.error("expected an identifier")), + } +} + +fn assert_expr_is_array_of_litstr(expr: Expr, flag: &str) -> syn::Result> { + let arr = match expr { + syn::Expr::Array(arr) => arr, + _ => { + return Err(syn::Error::new_spanned( + expr, + format!("Argument to `{flag}` must be an array"), + )) + } + }; + + let mut strings = Vec::new(); + for elem in arr.elems { + let val = match elem { + syn::Expr::Lit(syn::ExprLit { + attrs: _, + lit: syn::Lit::Str(litstr), + }) => litstr.value(), + _ => { + return Err(syn::Error::new_spanned( + elem, + format!("Argument to `{flag}` must be an array of string literals"), + )) + } + }; + strings.push(val); + } + Ok(strings) +} diff --git a/derive/src/flags.rs b/derive/src/flags.rs index 7cab9e5..82cf489 100644 --- a/derive/src/flags.rs +++ b/derive/src/flags.rs @@ -5,27 +5,27 @@ use proc_macro2::TokenStream; use quote::quote; #[derive(Default)] -pub(crate) struct Flags { +pub struct Flags { pub short: Vec>, pub long: Vec>, pub dd_style: Vec<(String, String)>, } #[derive(Clone)] -pub(crate) enum Value { +pub enum Value { No, Optional(String), Required(String), } #[derive(Clone)] -pub(crate) struct Flag { - pub(crate) flag: T, - pub(crate) value: Value, +pub struct Flag { + pub flag: T, + pub value: Value, } impl Flags { - pub(crate) fn new>(flags: impl IntoIterator) -> Self { + pub fn new>(flags: impl IntoIterator) -> Self { let mut self_ = Self::default(); for flag in flags { self_.add(flag.as_ref()); @@ -33,7 +33,7 @@ impl Flags { self_ } - pub(crate) fn add(&mut self, flag: &str) { + pub fn add(&mut self, flag: &str) { if let Some(s) = flag.strip_prefix("--") { // There are three possible patterns: // --flag @@ -110,11 +110,11 @@ impl Flags { } } - pub(crate) fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.short.is_empty() && self.long.is_empty() && self.dd_style.is_empty() } - pub(crate) fn pat(&self) -> TokenStream { + pub fn pat(&self) -> TokenStream { let short: Vec<_> = self.short.iter().map(|f| f.flag).collect(); let long: Vec<_> = self.long.iter().map(|f| &f.flag).collect(); match (&short[..], &long[..]) { @@ -127,7 +127,7 @@ impl Flags { } } - pub(crate) fn format(&self) -> String { + pub fn format(&self) -> String { let short = self .short .iter() diff --git a/derive/src/help.rs b/derive/src/help.rs index 8348ad0..4ab16ba 100644 --- a/derive/src/help.rs +++ b/derive/src/help.rs @@ -14,7 +14,7 @@ use crate::{ use proc_macro2::TokenStream; use quote::quote; -pub(crate) fn help_handling(help_flags: &Flags) -> TokenStream { +pub fn help_handling(help_flags: &Flags) -> TokenStream { if help_flags.is_empty() { return quote!(); } @@ -28,7 +28,7 @@ pub(crate) fn help_handling(help_flags: &Flags) -> TokenStream { ) } -pub(crate) fn help_string( +pub fn help_string( args: &[Argument], help_flags: &Flags, version_flags: &Flags, @@ -144,7 +144,7 @@ fn read_help_file(file: &str) -> (String, String, String) { ) } -pub(crate) fn version_handling(version_flags: &Flags) -> TokenStream { +pub fn version_handling(version_flags: &Flags) -> TokenStream { if version_flags.is_empty() { return quote!(); } diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 8c3d4cc..7383602 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -24,7 +24,7 @@ pub fn initial(input: TokenStream) -> TokenStream { initial::initial(input) } -#[proc_macro_derive(Arguments, attributes(flag, option, positional, free, arguments))] +#[proc_macro_derive(Arguments, attributes(arg, arguments))] pub fn arguments(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); diff --git a/examples/deprecated.rs b/examples/deprecated.rs index 0e5cdde..ad92a42 100644 --- a/examples/deprecated.rs +++ b/examples/deprecated.rs @@ -20,10 +20,10 @@ fn parse_plus(s: &str) -> Option<&str> { #[derive(Arguments)] enum Arg { - #[free(parse_minus)] + #[arg(parse_minus)] Min(usize), - #[free(parse_plus)] + #[arg(parse_plus)] Plus(isize), } diff --git a/examples/hello_world.rs b/examples/hello_world.rs index d37425c..5d95993 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -8,15 +8,15 @@ enum Arg { /// Just to show off, I can do multiple paragraphs and wrap text! /// /// # Also headings! - #[option("-n NAME", "--name=NAME", "name=NAME")] + #[arg("-n NAME", "--name=NAME", "name=NAME")] Name(String), /// The **number of times** to `greet` - #[option("-c N", "--count=N")] + #[arg("-c N", "--count=N")] Count(u8), /// This argument is hidden - #[option("--hidden", hidden)] + #[arg("--hidden", hidden)] Hidden, } diff --git a/tests/coreutils/b2sum.rs b/tests/coreutils/b2sum.rs index 52c8036..d32a183 100644 --- a/tests/coreutils/b2sum.rs +++ b/tests/coreutils/b2sum.rs @@ -3,31 +3,31 @@ use uutils_args::{Arguments, Initial, Options}; #[derive(Clone, Arguments)] enum Arg { - #[option("-b", "--binary")] + #[arg("-b", "--binary")] Binary, - #[option("-c", "--check")] + #[arg("-c", "--check")] Check, - #[option("--tag")] + #[arg("--tag")] Tag, - #[option("-t", "--text")] + #[arg("-t", "--text")] Text, - #[option("-q", "--quiet")] + #[arg("-q", "--quiet")] Quiet, - #[option("-s", "--status")] + #[arg("-s", "--status")] Status, - #[option("--strict")] + #[arg("--strict")] Strict, - #[option("-w", "--warn")] + #[arg("-w", "--warn")] Warn, - #[positional(..)] + #[arg("FILE", ..)] File(PathBuf), } diff --git a/tests/coreutils/base32.rs b/tests/coreutils/base32.rs index 240d9d0..6681daf 100644 --- a/tests/coreutils/base32.rs +++ b/tests/coreutils/base32.rs @@ -4,16 +4,16 @@ use uutils_args::{Arguments, Initial, Options}; #[derive(Clone, Arguments)] enum Arg { - #[option("-d", "--decode")] + #[arg("-d", "--decode")] Decode, - #[option("-i", "--ignore-garbage")] + #[arg("-i", "--ignore-garbage")] IgnoreGarbage, - #[option("-w COLS", "--wrap=COLS")] + #[arg("-w COLS", "--wrap=COLS")] Wrap(usize), - #[positional(..=1)] + #[arg("FILE", ..=1)] File(PathBuf), } diff --git a/tests/coreutils/basename.rs b/tests/coreutils/basename.rs index 231a9fc..404ad60 100644 --- a/tests/coreutils/basename.rs +++ b/tests/coreutils/basename.rs @@ -2,16 +2,16 @@ use uutils_args::{Arguments, Initial, Options}; #[derive(Clone, Arguments)] enum Arg { - #[option("-a", "--multiple")] + #[arg("-a", "--multiple")] Multiple, - #[option("-s SUFFIX", "--suffix=SUFFIX")] + #[arg("-s SUFFIX", "--suffix=SUFFIX")] Suffix(String), - #[option("-z", "--zero")] + #[arg("-z", "--zero")] Zero, - #[positional(last, ..)] + #[arg("NAMES", last, ..)] Names(Vec), } diff --git a/tests/coreutils/cat.rs b/tests/coreutils/cat.rs index d4c9928..5932f6c 100644 --- a/tests/coreutils/cat.rs +++ b/tests/coreutils/cat.rs @@ -12,34 +12,34 @@ enum NumberingMode { #[derive(Clone, Arguments)] enum Arg { - #[option("-A", "--show-all")] + #[arg("-A", "--show-all")] ShowAll, - #[option("-b", "--number-nonblank")] + #[arg("-b", "--number-nonblank")] NumberNonblank, - #[option("-e")] + #[arg("-e")] ShowNonPrintingEnds, - #[option("-E")] + #[arg("-E")] ShowEnds, - #[option("-n", "--number")] + #[arg("-n", "--number")] Number, - #[option("-s", "--squeeze-blank")] + #[arg("-s", "--squeeze-blank")] SqueezeBlank, - #[option("-t")] + #[arg("-t")] ShowNonPrintingTabs, - #[option("-T", "--show-tabs")] + #[arg("-T", "--show-tabs")] ShowTabs, - #[option("-v", "--show-nonprinting")] + #[arg("-v", "--show-nonprinting")] ShowNonPrinting, - #[positional(..)] + #[arg("FILES", ..)] File(PathBuf), } diff --git a/tests/coreutils/dd.rs b/tests/coreutils/dd.rs index 723af69..ebac8f0 100644 --- a/tests/coreutils/dd.rs +++ b/tests/coreutils/dd.rs @@ -16,43 +16,43 @@ enum StatusLevel { // TODO: The bytes arguments should parse sizes #[derive(Arguments)] enum Arg { - #[option("if=FILE")] + #[arg("if=FILE")] Infile(PathBuf), - #[option("of=FILE")] + #[arg("of=FILE")] Outfile(PathBuf), - #[option("ibs=BYTES")] + #[arg("ibs=BYTES")] Ibs(usize), - #[option("obs=BYTES")] + #[arg("obs=BYTES")] Obs(usize), - #[option("bs=BYTES")] + #[arg("bs=BYTES")] Bs(usize), - #[option("cbs=BYTES")] + #[arg("cbs=BYTES")] Cbs(usize), - #[option("skip=BYTES", "iseek=BYTES")] + #[arg("skip=BYTES", "iseek=BYTES")] Skip(u64), - #[option("seek=BYTES", "oseek=BYTES")] + #[arg("seek=BYTES", "oseek=BYTES")] Seek(u64), - #[option("count=N")] + #[arg("count=N")] Count(usize), - #[option("status=LEVEL")] + #[arg("status=LEVEL")] Status(StatusLevel), - #[option("conv=CONVERSIONS")] + #[arg("conv=CONVERSIONS")] Conv(String), - #[option("iflag=FLAGS")] + #[arg("iflag=FLAGS")] Iflag(String), - #[option("oflag=FLAGS")] + #[arg("oflag=FLAGS")] Oflag(String), } diff --git a/tests/coreutils/echo.rs b/tests/coreutils/echo.rs index d42fe69..2cc1753 100644 --- a/tests/coreutils/echo.rs +++ b/tests/coreutils/echo.rs @@ -5,18 +5,18 @@ use uutils_args::{Arguments, Initial, Options}; #[arguments(parse_echo_style)] enum Arg { /// Do not output trailing newline - #[option("-n")] + #[arg("-n")] NoNewline, /// Enable interpretation of backslash escapes - #[option("-e")] + #[arg("-e")] EnableEscape, /// Disable interpretation of backslash escapes - #[option("-E")] + #[arg("-E")] DisableEscape, - #[positional(last)] + #[arg("STRING", last)] String(Vec), } diff --git a/tests/coreutils/head.rs b/tests/coreutils/head.rs index 07e35df..abe8ad4 100644 --- a/tests/coreutils/head.rs +++ b/tests/coreutils/head.rs @@ -84,22 +84,22 @@ where #[derive(Arguments)] enum Arg { - #[option("-c NUM", "--bytes=NUM")] + #[arg("-c NUM", "--bytes=NUM")] Bytes(SigNum), - #[option("-n NUM", "--lines=NUM")] + #[arg("-n NUM", "--lines=NUM")] Lines(SigNum), - #[option("-q", "--quiet", "--silent")] + #[arg("-q", "--quiet", "--silent")] Quiet, - #[option("-v", "--verbose")] + #[arg("-v", "--verbose")] Verbose, - #[option("-z", "--zero-terminated")] + #[arg("-z", "--zero-terminated")] Zero, - #[positional(..)] + #[arg("FILES", ..)] File(PathBuf), } diff --git a/tests/coreutils/ls.rs b/tests/coreutils/ls.rs index 4a71000..75f3a9f 100644 --- a/tests/coreutils/ls.rs +++ b/tests/coreutils/ls.rs @@ -134,150 +134,150 @@ enum IndicatorStyle { enum Arg { // === Files === /// Do not ignore entries starting with . - #[option("-a")] + #[arg("-a")] All, /// Do not list implied . and .. - #[option("-A")] + #[arg("-A")] AlmostAll, /// Show file author (ignored) - #[option("--author")] + #[arg("--author")] Author, - #[option("--time=WORD")] - #[option("-c", default = Time::Change)] - #[option("-u", default = Time::Access)] + #[arg("--time=WORD")] + #[arg("-c", default = Time::Change)] + #[arg("-u", default = Time::Access)] Time(Time), // === Sorting == /// Sort by WORD - #[option("--sort=WORD")] - #[option("-t", default = Sort::Time, help = "Sort by time")] - #[option("-U", default = Sort::None, help = "Do not sort")] - #[option("-v", default = Sort::Version, help = "Sort by version")] - #[option("-X", default = Sort::Extension, help = "Sort by extension")] + #[arg("--sort=WORD")] + #[arg("-t", default = Sort::Time, help = "Sort by time")] + #[arg("-U", default = Sort::None, help = "Do not sort")] + #[arg("-v", default = Sort::Version, help = "Sort by version")] + #[arg("-X", default = Sort::Extension, help = "Sort by extension")] Sort(Sort), // === Miscellaneous === - #[option("-Z", "--context")] + #[arg("-Z", "--context")] SecurityContext, /// Do not list files starting with ~ - #[option("-B", "--ignore-backups")] + #[arg("-B", "--ignore-backups")] IgnoreBackups, - #[option("-d", "--directory")] + #[arg("-d", "--directory")] Directory, - #[option("-D", "--dired")] + #[arg("-D", "--dired")] Dired, - #[option("--hyperlink")] + #[arg("--hyperlink")] Hyperlink(When), - #[option("-i", "--inode")] + #[arg("-i", "--inode")] Inode, - #[option("-I PATTERN", "--ignore=PATTERN")] + #[arg("-I PATTERN", "--ignore=PATTERN")] Ignore(String), - #[option("-r", "--reverse")] + #[arg("-r", "--reverse")] Reverse, - #[option("-R", "--recursive")] + #[arg("-R", "--recursive")] Recursive, - #[option("-w COLS", "--width=COLS")] + #[arg("-w COLS", "--width=COLS")] Width(u16), - #[option("-s", "--size")] + #[arg("-s", "--size")] AllocationSize, - #[option("-G", "--no-group")] + #[arg("-G", "--no-group")] NoGroup, // === Format === /// Set format - #[option("--format=FORMAT")] - #[option("-l", "--long", default = Format::Long, help = "Use long format")] - #[option("-C", default = Format::Columns, help = "Use columns format")] - #[option("-x", default = Format::Across, help = "Use across format")] - #[option("-m", default = Format::Commas, help = "Use comma format")] + #[arg("--format=FORMAT")] + #[arg("-l", "--long", default = Format::Long, help = "Use long format")] + #[arg("-C", default = Format::Columns, help = "Use columns format")] + #[arg("-x", default = Format::Across, help = "Use across format")] + #[arg("-m", default = Format::Commas, help = "Use comma format")] Format(Format), /// Show single column - #[option("-1")] + #[arg("-1")] SingleColumn, - #[option("-o")] + #[arg("-o")] LongNoGroup, - #[option("-g")] + #[arg("-g")] LongNoOwner, - #[option("-n", "--numeric-uid-gid")] + #[arg("-n", "--numeric-uid-gid")] LongNumericUidGid, // === Indicator style === - #[option("--indicator-style=STYLE")] - #[option("-p", default = IndicatorStyle::Slash, help = "Append slash to directories")] - #[option("--file-type", default = IndicatorStyle::FileType, help = "Add indicators for file types")] + #[arg("--indicator-style=STYLE")] + #[arg("-p", default = IndicatorStyle::Slash, help = "Append slash to directories")] + #[arg("--file-type", default = IndicatorStyle::FileType, help = "Add indicators for file types")] IndicatorStyle(IndicatorStyle), /// Classify items - #[option("-F", "--classify[=WHEN]", default = When::Always)] + #[arg("-F", "--classify[=WHEN]", default = When::Always)] IndicatorStyleClassify(When), // === Dereference === - #[option("-L", "--dereference")] + #[arg("-L", "--dereference")] DerefAll, - #[option("--dereference-command-line-symlink-to-dir")] + #[arg("--dereference-command-line-symlink-to-dir")] DerefDirArgs, - #[option("--dereference-command-line")] + #[arg("--dereference-command-line")] DerefArgs, // === Size === - #[option("-h", "--human-readable")] + #[arg("-h", "--human-readable")] HumanReadable, - #[option("-k", "--kibibytes")] + #[arg("-k", "--kibibytes")] Kibibytes, - #[option("--si")] + #[arg("--si")] Si, - // #[option("--block-size=BLOCKSIZE")] + // #[arg("--block-size=BLOCKSIZE")] // BlockSize(Size), // === Quoting style === - #[option("--quoting-style=STYLE")] - #[option("-N", "--literal", default = QuotingStyle::Literal)] - #[option("-h", "--escape", default = QuotingStyle::Escape)] - #[option("-Q", "--quote-name", default = todo!())] + #[arg("--quoting-style=STYLE")] + #[arg("-N", "--literal", default = QuotingStyle::Literal)] + #[arg("-h", "--escape", default = QuotingStyle::Escape)] + #[arg("-Q", "--quote-name", default = todo!())] QuotingStyle(QuotingStyle), /// Set the color - #[option("--color[=WHEN]", default = When::Always)] + #[arg("--color[=WHEN]", default = When::Always)] Color(When), /// Print control characters as ? - #[option("-q", "--hide-control-chars")] + #[arg("-q", "--hide-control-chars")] HideControlChars, /// Show control characters as is - #[option("--show-control-chars")] + #[arg("--show-control-chars")] ShowControlChars, - #[option("--zero")] + #[arg("--zero")] Zero, - #[option("--group-directories-first")] + #[arg("--group-directories-first")] GroupDirectoriesFirst, - #[positional(..)] + #[arg("FILES", ..)] File(PathBuf), } diff --git a/tests/coreutils/mktemp.rs b/tests/coreutils/mktemp.rs index b80b352..ad18b74 100644 --- a/tests/coreutils/mktemp.rs +++ b/tests/coreutils/mktemp.rs @@ -4,25 +4,25 @@ use uutils_args::{Arguments, Initial, Options}; #[derive(Clone, Arguments)] enum Arg { - #[option("-d", "--directory")] + #[arg("-d", "--directory")] Directory, - #[option("-u", "--dry-run")] + #[arg("-u", "--dry-run")] DryRun, - #[option("-q", "--quiet")] + #[arg("-q", "--quiet")] Quiet, - #[option("--suffix=SUFFIX")] + #[arg("--suffix=SUFFIX")] Suffix(String), - #[option("-t")] + #[arg("-t")] TreatAsTemplate, - #[option("-p DIR", "--tmpdir[=DIR]", default = ".".into())] + #[arg("-p DIR", "--tmpdir[=DIR]", default = ".".into())] TmpDir(PathBuf), - #[positional(0..=1)] + #[arg("TEMPLATE", 0..=1)] Template(String), } diff --git a/tests/coreutils/tail.rs b/tests/coreutils/tail.rs index 244dfcb..c23ba7b 100644 --- a/tests/coreutils/tail.rs +++ b/tests/coreutils/tail.rs @@ -106,44 +106,44 @@ where #[derive(Arguments)] enum Arg { - #[option("-c NUM", "--bytes=NUM")] + #[arg("-c NUM", "--bytes=NUM")] Bytes(SigNum), - #[option("-f", "--follow[=HOW]", default=FollowMode::Descriptor)] + #[arg("-f", "--follow[=HOW]", default=FollowMode::Descriptor)] Follow(FollowMode), - #[option("-F")] + #[arg("-F")] FollowRetry, - #[option("--max-unchanged-stats=N")] + #[arg("--max-unchanged-stats=N")] MaxUnchangedStats(u32), - #[option("-n NUM", "--lines=NUM")] + #[arg("-n NUM", "--lines=NUM")] Lines(SigNum), - #[option("--pid=PID")] + #[arg("--pid=PID")] Pid(u64), - #[option("-q", "--quiet", "--silent")] + #[arg("-q", "--quiet", "--silent")] Quiet, - #[option("--retry")] + #[arg("--retry")] Retry, - #[option("-s NUMBER", "--sleep-interval=NUMBER")] + #[arg("-s NUMBER", "--sleep-interval=NUMBER")] SleepInterval(u64), - #[option("-v", "--verbose")] + #[arg("-v", "--verbose")] Verbose, - #[option("-z", "--zero-terminated")] + #[arg("-z", "--zero-terminated")] Zero, - #[positional(..)] - File(PathBuf), - - #[option("---presume-input-pipe", hidden)] + #[arg("---presume-input-pipe", hidden)] PresumeInputPipe, + + #[arg("FILES", ..)] + File(PathBuf), } // We need both negative and positive 0 diff --git a/tests/defaults.rs b/tests/defaults.rs index 21ddd05..76a6511 100644 --- a/tests/defaults.rs +++ b/tests/defaults.rs @@ -4,7 +4,7 @@ use uutils_args::{Arguments, Initial, Options}; fn true_default() { #[derive(Arguments)] enum Arg { - #[option("--foo")] + #[arg("--foo")] Foo, } @@ -28,7 +28,7 @@ fn true_default() { fn env_var_string() { #[derive(Arguments)] enum Arg { - #[option("--foo=MSG")] + #[arg("--foo=MSG")] Foo(String), } diff --git a/tests/exit_code.rs b/tests/exit_code.rs index 76e2a66..ace64c6 100644 --- a/tests/exit_code.rs +++ b/tests/exit_code.rs @@ -5,7 +5,7 @@ fn one_flag() { #[derive(Arguments, Clone, Debug, PartialEq, Eq)] #[arguments(exit_code = 4)] enum Arg { - #[option("-f", "--foo")] + #[arg("-f", "--foo")] Foo, } diff --git a/tests/flags.rs b/tests/flags.rs index 0d4b1fe..2a6b808 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -4,7 +4,7 @@ use uutils_args::{Arguments, Initial, Options}; fn one_flag() { #[derive(Arguments)] enum Arg { - #[option("-f", "--foo")] + #[arg("-f", "--foo")] Foo, } @@ -29,9 +29,9 @@ fn one_flag() { fn two_flags() { #[derive(Arguments, Clone)] enum Arg { - #[option("-a")] + #[arg("-a")] A, - #[option("-b")] + #[arg("-b")] B, } @@ -69,7 +69,7 @@ fn two_flags() { fn long_and_short_flag() { #[derive(Arguments)] enum Arg { - #[option("-f", "--foo")] + #[arg("-f", "--foo")] Foo, } @@ -93,7 +93,7 @@ fn long_and_short_flag() { fn short_alias() { #[derive(Arguments)] enum Arg { - #[option("-b")] + #[arg("-b")] Foo, } @@ -115,7 +115,7 @@ fn short_alias() { fn long_alias() { #[derive(Arguments)] enum Arg { - #[option("--bar")] + #[arg("--bar")] Foo, } @@ -137,9 +137,9 @@ fn long_alias() { fn short_and_long_alias() { #[derive(Arguments)] enum Arg { - #[option("-b", "--bar")] + #[arg("-b", "--bar")] Foo, - #[option("-f", "--foo")] + #[arg("-f", "--foo")] Bar, } @@ -178,11 +178,11 @@ fn short_and_long_alias() { fn xyz_map_to_abc() { #[derive(Arguments)] enum Arg { - #[option("-x")] + #[arg("-x")] X, - #[option("-y")] + #[arg("-y")] Y, - #[option("-z")] + #[arg("-z")] Z, } @@ -254,9 +254,9 @@ fn xyz_map_to_abc() { fn non_rust_ident() { #[derive(Arguments)] enum Arg { - #[option("--foo-bar")] + #[arg("--foo-bar")] FooBar, - #[option("--super")] + #[arg("--super")] Super, } @@ -285,7 +285,7 @@ fn non_rust_ident() { fn number_flag() { #[derive(Arguments, Clone)] enum Arg { - #[option("-1")] + #[arg("-1")] One, } #[derive(Initial, PartialEq, Eq, Debug)] @@ -306,9 +306,9 @@ fn number_flag() { fn false_bool() { #[derive(Arguments)] enum Arg { - #[option("-a")] + #[arg("-a")] A, - #[option("-b")] + #[arg("-b")] B, } @@ -338,7 +338,7 @@ fn false_bool() { fn verbosity() { #[derive(Arguments)] enum Arg { - #[option("-v")] + #[arg("-v")] Verbosity, } @@ -362,11 +362,11 @@ fn verbosity() { fn infer_long_args() { #[derive(Arguments)] enum Arg { - #[option("--all")] + #[arg("--all")] All, - #[option("--almost-all")] + #[arg("--almost-all")] AlmostAll, - #[option("--author")] + #[arg("--author")] Author, } @@ -405,11 +405,11 @@ fn enum_flag() { #[derive(Arguments)] enum Arg { - #[option("--foo")] + #[arg("--foo")] Foo, - #[option("--bar")] + #[arg("--bar")] Bar, - #[option("--baz")] + #[arg("--baz")] Baz, } diff --git a/tests/options.rs b/tests/options.rs index 451c43c..ba02512 100644 --- a/tests/options.rs +++ b/tests/options.rs @@ -6,7 +6,7 @@ use uutils_args::{Arguments, Initial, Options, Value, ValueResult}; fn string_option() { #[derive(Arguments)] enum Arg { - #[option("--message=MSG")] + #[arg("--message=MSG")] Message(String), } @@ -42,7 +42,7 @@ fn enum_option() { #[derive(Arguments)] enum Arg { - #[option("--format=FORMAT")] + #[arg("--format=FORMAT")] Format(Format), } @@ -81,7 +81,7 @@ fn enum_option_with_fields() { #[derive(Arguments)] enum Arg { - #[option("-i INDENT")] + #[arg("-i INDENT")] Indent(Indent), } @@ -130,7 +130,7 @@ fn enum_with_complex_from_value() { #[derive(Arguments)] enum Arg { - #[option("-i INDENT")] + #[arg("-i INDENT")] Indent(Indent), } @@ -164,7 +164,7 @@ fn color() { #[derive(Arguments)] enum Arg { - #[option("--color[=WHEN]")] + #[arg("--color[=WHEN]")] Color(Option), } @@ -201,11 +201,11 @@ fn color() { fn actions() { #[derive(Arguments)] enum Arg { - #[option("-m MESSAGE")] + #[arg("-m MESSAGE")] Message(String), - #[option("--send")] + #[arg("--send")] Send, - #[option("--receive")] + #[arg("--receive")] Receive, } @@ -239,7 +239,7 @@ fn actions() { fn width() { #[derive(Arguments)] enum Arg { - #[option("-w WIDTH")] + #[arg("-w WIDTH")] Width(u64), } @@ -265,25 +265,25 @@ fn width() { fn integers() { #[derive(Arguments)] enum Arg { - #[option("--u8=N")] + #[arg("--u8=N")] U8(u8), - #[option("--u16=N")] + #[arg("--u16=N")] U16(u16), - #[option("--u32=N")] + #[arg("--u32=N")] U32(u32), - #[option("--u64=N")] + #[arg("--u64=N")] U64(u64), - #[option("--u128=N")] + #[arg("--u128=N")] U128(u128), - #[option("--i8=N")] + #[arg("--i8=N")] I8(i8), - #[option("--i16=N")] + #[arg("--i16=N")] I16(i16), - #[option("--i32=N")] + #[arg("--i32=N")] I32(i32), - #[option("--i64=N")] + #[arg("--i64=N")] I64(i64), - #[option("--i128=N")] + #[arg("--i128=N")] I128(i128), } @@ -337,7 +337,7 @@ fn ls_classify() { #[derive(Arguments)] enum Arg { - #[option( + #[arg( "-F", "--classify[=WHEN]", default = When::Always, )] @@ -372,7 +372,7 @@ fn ls_classify() { fn mktemp_tmpdir() { #[derive(Clone, Arguments)] enum Arg { - #[option( + #[arg( "-p DIR", "--tmpdir[=DIR]", default = String::from("/tmp"), )] @@ -445,10 +445,10 @@ fn deprecated() { #[derive(Arguments)] enum Arg { - #[free(parse_minus)] + #[arg(parse_minus)] Min(usize), - #[free(parse_plus)] + #[arg(parse_plus)] Plus(isize), } diff --git a/tests/positionals.rs b/tests/positionals.rs index 5e0bd3b..04f187c 100644 --- a/tests/positionals.rs +++ b/tests/positionals.rs @@ -4,7 +4,7 @@ use uutils_args::{Arguments, Initial, Options}; fn one_positional() { #[derive(Arguments, Clone)] enum Arg { - #[positional(1)] + #[arg("FILE", 1)] File1(String), } @@ -29,9 +29,9 @@ fn one_positional() { fn two_positionals() { #[derive(Arguments)] enum Arg { - #[positional(1)] + #[arg("FOO", 1)] Foo(String), - #[positional(1)] + #[arg("BAR", 1)] Bar(String), } @@ -61,7 +61,7 @@ fn two_positionals() { fn optional_positional() { #[derive(Arguments)] enum Arg { - #[positional(0..=1)] + #[arg("FOO", 0..=1)] Foo(String), } @@ -86,7 +86,7 @@ fn optional_positional() { fn collect_positional() { #[derive(Arguments, Clone)] enum Arg { - #[positional(..)] + #[arg("FOO", ..)] Foo(String), } @@ -111,7 +111,7 @@ fn collect_positional() { fn last1() { #[derive(Arguments)] enum Arg { - #[positional(last, ..)] + #[arg("FOO", last, ..)] Foo(Vec), } @@ -134,10 +134,10 @@ fn last1() { fn last2() { #[derive(Arguments, Clone)] enum Arg { - #[option("-a")] + #[arg("-a")] A, - #[positional(last, ..)] + #[arg("FOO", last, ..)] Foo(Vec), }