You've already forked uutils-args
mirror of
https://github.com/uutils/uutils-args.git
synced 2026-06-10 16:13:08 -07:00
unify the option/positional/free attributes into arg
This commit is contained in:
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
+15
-19
@@ -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<Argument> {
|
||||
pub fn parse_argument(v: Variant) -> Vec<Argument> {
|
||||
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<Vec<ArgAttr>> {
|
||||
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<char>) {
|
||||
pub fn short_handling(args: &[Argument]) -> (TokenStream, Vec<char>) {
|
||||
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<char>) {
|
||||
(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.
|
||||
|
||||
+152
-133
@@ -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<ArgAttr> {
|
||||
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<String>,
|
||||
pub(crate) exit_code: i32,
|
||||
pub(crate) parse_echo_style: bool,
|
||||
}
|
||||
|
||||
fn get_ident(meta: &ParseNestedMeta) -> syn::Result<String> {
|
||||
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<Vec<String>> {
|
||||
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::<Token![,]>()?;
|
||||
if s.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
})
|
||||
pub struct ArgumentsAttr {
|
||||
pub help_flags: Flags,
|
||||
pub version_flags: Flags,
|
||||
pub file: Option<String>,
|
||||
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<Self> {
|
||||
pub fn parse(attr: &Attribute) -> syn::Result<Self> {
|
||||
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<Self> {
|
||||
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::<LitStr>() {
|
||||
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::<syn::Ident>() {
|
||||
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<Expr>,
|
||||
pub(crate) default: Option<Expr>,
|
||||
pub(crate) hidden: bool,
|
||||
pub(crate) help: Option<String>,
|
||||
pub struct OptionAttr {
|
||||
pub flags: Flags,
|
||||
pub parser: Option<Expr>,
|
||||
pub default: Option<Expr>,
|
||||
pub hidden: bool,
|
||||
pub help: Option<String>,
|
||||
}
|
||||
|
||||
impl OptionAttr {
|
||||
pub(crate) fn parse(attr: &Attribute) -> syn::Result<Self> {
|
||||
fn from_args(first_flag: String, s: ParseStream) -> syn::Result<OptionAttr> {
|
||||
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::<LitStr>() {
|
||||
option_attr.flags.add(&litstr.value());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let ident = s.parse::<Ident>()?;
|
||||
match ident.to_string().as_str() {
|
||||
match ident.to_string().as_ref() {
|
||||
"parser" => {
|
||||
s.parse::<Token![=]>()?;
|
||||
let p = s.parse::<Expr>()?;
|
||||
@@ -192,15 +151,16 @@ impl OptionAttr {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct FreeAttr {
|
||||
pub(crate) filters: Vec<syn::Ident>,
|
||||
pub struct FreeAttr {
|
||||
pub filters: Vec<syn::Ident>,
|
||||
}
|
||||
|
||||
impl FreeAttr {
|
||||
pub(crate) fn parse(attr: &Attribute) -> syn::Result<Self> {
|
||||
pub fn from_args(first_value: syn::Ident, s: ParseStream) -> syn::Result<Self> {
|
||||
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::<Ident>()?;
|
||||
free_attr.filters.push(ident);
|
||||
Ok(())
|
||||
@@ -210,46 +170,9 @@ impl FreeAttr {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct ValueAttr {
|
||||
pub(crate) keys: Vec<String>,
|
||||
pub(crate) value: Option<Expr>,
|
||||
}
|
||||
|
||||
impl ValueAttr {
|
||||
pub(crate) fn parse(attr: &Attribute) -> syn::Result<Self> {
|
||||
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::<LitStr>() {
|
||||
value_attr.keys.push(litstr.value());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let ident = s.parse::<Ident>()?;
|
||||
match ident.to_string().as_str() {
|
||||
"value" => {
|
||||
s.parse::<Token![=]>()?;
|
||||
let p = s.parse::<Expr>()?;
|
||||
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<usize>,
|
||||
pub(crate) last: bool,
|
||||
pub struct PositionalAttr {
|
||||
pub num_args: RangeInclusive<usize>,
|
||||
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<Self> {
|
||||
pub fn from_args(_first_value: String, s: ParseStream) -> syn::Result<Self> {
|
||||
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::<ExprRange>()?;
|
||||
// We're dealing with a range
|
||||
@@ -322,3 +245,99 @@ impl PositionalAttr {
|
||||
Ok(positional_attr)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ValueAttr {
|
||||
pub keys: Vec<String>,
|
||||
pub value: Option<Expr>,
|
||||
}
|
||||
|
||||
impl ValueAttr {
|
||||
pub fn parse(attr: &Attribute) -> syn::Result<Self> {
|
||||
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::<LitStr>() {
|
||||
value_attr.keys.push(litstr.value());
|
||||
} else {
|
||||
let ident = s.parse::<Ident>()?;
|
||||
match ident.to_string().as_str() {
|
||||
"value" => {
|
||||
s.parse::<Token![=]>()?;
|
||||
let p = s.parse::<Expr>()?;
|
||||
value_attr.value = Some(p);
|
||||
}
|
||||
_ => return Err(s.error("unrecognized keyword in value attribute")),
|
||||
}
|
||||
}
|
||||
|
||||
if s.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
s.parse::<Token![,]>()?;
|
||||
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::<Token![,]>()?;
|
||||
if s.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
logic(s)?;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ident(meta: &ParseNestedMeta) -> syn::Result<String> {
|
||||
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<Vec<String>> {
|
||||
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)
|
||||
}
|
||||
|
||||
+10
-10
@@ -5,27 +5,27 @@ use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Flags {
|
||||
pub struct Flags {
|
||||
pub short: Vec<Flag<char>>,
|
||||
pub long: Vec<Flag<String>>,
|
||||
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<T> {
|
||||
pub(crate) flag: T,
|
||||
pub(crate) value: Value,
|
||||
pub struct Flag<T> {
|
||||
pub flag: T,
|
||||
pub value: Value,
|
||||
}
|
||||
|
||||
impl Flags {
|
||||
pub(crate) fn new<T: AsRef<str>>(flags: impl IntoIterator<Item = T>) -> Self {
|
||||
pub fn new<T: AsRef<str>>(flags: impl IntoIterator<Item = T>) -> 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()
|
||||
|
||||
+3
-3
@@ -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!();
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String>),
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
+13
-13
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
@@ -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<OsString>),
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
+53
-53
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
+15
-15
@@ -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
|
||||
|
||||
+2
-2
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user