unify the option/positional/free attributes into arg

This commit is contained in:
Terts Diepraam
2023-11-30 12:40:16 +01:00
parent c965b3c3f8
commit e6a7f379bf
23 changed files with 372 additions and 357 deletions
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+2 -2
View File
@@ -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),
}
+3 -3
View File
@@ -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,
}
+9 -9
View File
@@ -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 -4
View File
@@ -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),
}
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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),
}
+4 -4
View File
@@ -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>),
}
+6 -6
View File
@@ -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
View File
@@ -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),
}
+7 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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