diff --git a/complete/src/fish.rs b/complete/src/fish.rs index d6f0f66..e2a49f2 100644 --- a/complete/src/fish.rs +++ b/complete/src/fish.rs @@ -108,6 +108,7 @@ mod test { value: Value::No, }], long: vec![], + dd_style: vec![], help: "some flag", value: Some(hint), }], diff --git a/complete/src/lib.rs b/complete/src/lib.rs index 5d8649c..ab2a4eb 100644 --- a/complete/src/lib.rs +++ b/complete/src/lib.rs @@ -41,6 +41,7 @@ pub struct Command<'a> { pub struct Arg<'a> { pub short: Vec>, pub long: Vec>, + pub dd_style: Vec<(&'a str, &'a str)>, pub help: &'a str, pub value: Option, } diff --git a/complete/src/man.rs b/complete/src/man.rs index 046cf08..d381c59 100644 --- a/complete/src/man.rs +++ b/complete/src/man.rs @@ -54,6 +54,14 @@ pub fn render(c: &Command) -> String { Value::No => {} } } + for (flag, value) in &arg.dd_style { + if !flags.is_empty() { + flags.push(roman(", ")); + } + flags.push(bold(*flag)); + flags.push(roman("=")); + flags.push(italic(*value)); + } page.text(flags); page.text([roman(arg.help)]); } diff --git a/complete/src/md.rs b/complete/src/md.rs index 1c2fa1b..fcc80a3 100644 --- a/complete/src/md.rs +++ b/complete/src/md.rs @@ -58,6 +58,10 @@ fn options(c: &Command) -> String { flags.push(format!("-{flag}{value_str}")); } + for (flag, value) in &arg.dd_style { + flags.push(format!("{flag}={value}")); + } + out.push_str(&flags.join(", ")); out.push_str("\n"); out.push_str(&format!("
\n\n{}\n\n
\n", arg.help)); diff --git a/derive/src/complete.rs b/derive/src/complete.rs index 10b9691..6d00b9e 100644 --- a/derive/src/complete.rs +++ b/derive/src/complete.rs @@ -33,16 +33,21 @@ pub fn complete(args: &[Argument], file: &Option) -> TokenStream { continue; }; - let Flags { short, long, .. } = flags; - if short.is_empty() && long.is_empty() { + let Flags { + short, + long, + dd_style, + } = flags; + if short.is_empty() && long.is_empty() && dd_style.is_empty() { continue; } // If none of the flags take an argument, we won't need ValueHint // based on that type. So we should not attempt to call `value_hint` // on it. - let any_flag_takes_argument = - short.iter().any(|f| f.value != Value::No) && long.iter().any(|f| f.value != Value::No); + let any_flag_takes_argument = !dd_style.is_empty() + && short.iter().any(|f| f.value != Value::No) + && long.iter().any(|f| f.value != Value::No); let short: Vec<_> = short .iter() @@ -75,6 +80,11 @@ pub fn complete(args: &[Argument], file: &Option) -> TokenStream { }) .collect(); + let dd_style: Vec<_> = dd_style + .iter() + .map(|(flag, value)| quote!((#flag, #value))) + .collect(); + let hint = match (field, any_flag_takes_argument) { (Some(ty), true) => quote!(Some(<#ty>::value_hint())), _ => quote!(None), @@ -84,6 +94,7 @@ pub fn complete(args: &[Argument], file: &Option) -> TokenStream { ::uutils_args_complete::Arg { short: vec![#(#short),*], long: vec![#(#long),*], + dd_style: vec![#(#dd_style),*], help: #help, value: #hint, } diff --git a/examples/completion.rs b/examples/completion.rs index 112cc60..bf8f2e0 100644 --- a/examples/completion.rs +++ b/examples/completion.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use uutils_args::{Arguments, Options, Value}; -#[derive(Value)] +#[derive(Value, Debug)] enum Number { #[value] One, @@ -27,13 +27,22 @@ enum Arg { /// Give it a path! #[arg("-p P", "--path=P")] Path(PathBuf), + + /// A dd_style argument! + #[arg("if=file")] + File(PathBuf), } struct Settings; impl Options for Settings { - fn apply(&mut self, _arg: Arg) { - panic!("Compile with the 'parse-is-complete' feature!") + fn apply(&mut self, arg: Arg) { + match arg { + Arg::Flag => println!("Got flag"), + Arg::Number(n) => println!("Got number {n:?}"), + Arg::Path(p) => println!("Got path {}", p.display()), + Arg::File(f) => println!("Got file {}", f.display()), + } } } diff --git a/tests/coreutils/dd.rs b/tests/coreutils/dd.rs index fe5ef69..7538cfe 100644 --- a/tests/coreutils/dd.rs +++ b/tests/coreutils/dd.rs @@ -62,13 +62,14 @@ struct Settings { outfile: Option, ibs: usize, obs: usize, + cbs: usize, skip: u64, seek: u64, count: usize, - _iconv: Vec, - _iflags: Vec, - _oconv: Vec, - _oflags: Vec, + iconv: Vec, + iflags: Vec, + oconv: Vec, + oflags: Vec, status: Option, } @@ -77,15 +78,16 @@ impl Default for Settings { Self { ibs: 512, obs: 512, + cbs: 512, infile: Default::default(), outfile: Default::default(), skip: Default::default(), seek: Default::default(), count: Default::default(), - _iconv: Default::default(), - _iflags: Default::default(), - _oconv: Default::default(), - _oflags: Default::default(), + iconv: Default::default(), + iflags: Default::default(), + oconv: Default::default(), + oflags: Default::default(), status: Default::default(), } } @@ -102,14 +104,21 @@ impl Options for Settings { self.ibs = b; self.obs = b; } - Arg::Cbs(_) => todo!(), + Arg::Cbs(b) => self.cbs = b, Arg::Skip(b) => self.skip = b, Arg::Seek(b) => self.seek = b, Arg::Count(n) => self.count = n, Arg::Status(level) => self.status = Some(level), - Arg::Conv(_) => todo!(), - Arg::Iflag(_) => todo!(), - Arg::Oflag(_) => todo!(), + Arg::Conv(c) => { + self.iconv.push(c.clone()); + self.oconv.push(c); + } + Arg::Iflag(f) => { + self.iflags.push(f); + } + Arg::Oflag(f) => { + self.oflags.push(f); + } } } }