feat(args): add ability to create basic arguments from a usage string

This commit is contained in:
Kevin K 2015-04-13 00:37:59 -04:00
parent 5fc6050ddf
commit ab409a8f1d
6 changed files with 768 additions and 2 deletions

12
gede.ini Normal file
View file

@ -0,0 +1,12 @@
TcpPort="2000"
TcpHost="localhost"
Mode="0"
LastProgram="/home/kevin/Projects/clap-rs/target/debug/clap-fd2d4002ca38536a"
TcpProgram=""
InitCommands=""
GdpPath="gdb"
LastProgramArguments=""
Font="Monospace"
FontSize="8"
ReuseBreakpoints="0"
Breakpoints=":0;:0;:0;:0;:0;:0;:0;:0;/home/kevin/Projects/clap-rs/src/usageparser.rs:51;:0"

View file

@ -219,10 +219,13 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
if a.required {
self.required.insert(a.name);
}
if let Some(i) = a.index {
if a.index.is_some() || (a.short.is_none() && a.long.is_none()) {
let i = if a.index.is_none() {(self.positionals_idx.len() + 1) as u8 } else { a.index.unwrap() };
if a.short.is_some() || a.long.is_some() {
panic!("Argument \"{}\" has conflicting requirements, both index() and short(), or long(), were supplied", a.name);
}
if self.positionals_idx.contains_key(&i) {
panic!("Argument \"{}\" has the same index as another positional argument", a.name);
}
@ -230,6 +233,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
panic!("Argument \"{}\" has conflicting requirements, both index() and takes_value(true) were supplied", a.name);
}
// Create the Positional Arguemnt Builder with each HashSet = None to only allocate those that require it
let mut pb = PosBuilder {
name: a.name,
@ -304,7 +308,8 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
self.opts.insert(a.name, ob);
} else {
if a.short.is_none() && a.long.is_none() {
panic!("Argument \"{}\" must have either a short() and/or long() supplied since no index() or takes_value() were found", a.name);
// Could be a posistional constructed from usage string
}
if a.required {
panic!("Argument \"{}\" cannot be required(true) because it has no index() or takes_value(true)", a.name);

View file

@ -1,3 +1,5 @@
use usageparser::{UsageParser, UsageToken};
/// The abstract representation of a command line argument used by the consumer of the library.
/// Used to set all the options and relationships that define a valid argument for the program.
///
@ -74,6 +76,9 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// and positional arguments (i.e. those without a `-` or `--`) the name will also
/// be displayed when the user prints the usage/help information of the program.
///
/// **NOTE:** this function is deprecated in favor of Arg::with_name() to stay in line with
/// Rust APIs
///
/// Example:
///
/// ```no_run
@ -83,6 +88,8 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// Arg::new("conifg")
/// # .short("c")
/// # ).get_matches();
#[deprecated(since = "0.5.15",
reason = "use Arg::with_name() instead")]
pub fn new(n: &'n str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
Arg {
name: n,
@ -99,6 +106,103 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
}
}
/// Creates a new instace of `Arg` using a unique string name.
/// The name will be used by the library consumer to get information about
/// whether or not the argument was used at runtime.
///
/// **NOTE:** in the case of arguments that take values (i.e. `takes_value(true)`)
/// and positional arguments (i.e. those without a `-` or `--`) the name will also
/// be displayed when the user prints the usage/help information of the program.
///
/// Example:
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// Arg::with_name("conifg")
/// # .short("c")
/// # ).get_matches();
pub fn with_name(n: &'n str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
Arg {
name: n,
short: None,
long: None,
help: None,
required: false,
takes_value: false,
multiple: false,
index: None,
possible_vals: None,
blacklist: None,
requires: None,
}
}
pub fn from_usage(u: &'n str) -> Arg<'n, 'n, 'n, 'b, 'p, 'r> {
assert!(u.len() > 0, "Arg::from_usage() requires a non-zero-length usage string but none was provided");
let mut name = None;
let mut short = None;
let mut long = None;
let mut help = None;
let mut required = false;
let mut takes_value = false;
let mut multiple = false;
let parser = UsageParser::with_usage(u);
for_match!{ parser,
UsageToken::Name(n, req) => {
if name.is_none() {
name = Some(n);
if let Some(m) = req {
required = m;
}
}
if short.is_some() || long.is_some() {
takes_value = true;
}
if let Some(l) = long {
if n != name.unwrap() && name.unwrap() == l {
name = Some(n);
if let Some(m) = req {
required = m;
}
}
}
},
UsageToken::Short(s) => {
short = Some(s);
},
UsageToken::Long(l) => {
long = Some(l);
if name.is_none() {
name = Some(l);
}
},
UsageToken::Help(h) => {
help = Some(h);
},
UsageToken::Multiple => {
multiple = true;
}
}
Arg {
name: name.unwrap(),
short: short,
long: long,
help: help,
required: required,
takes_value: takes_value,
multiple: multiple,
index: None,
possible_vals: None,
blacklist: None,
requires: None,
}
}
/// Sets the short version of the argument without the preceding `-`.
///
///

View file

@ -9,6 +9,7 @@ pub use app::App;
mod macros;
mod app;
mod args;
mod usageparser;
#[cfg(test)]
mod tests {
@ -38,6 +39,58 @@ mod tests {
.get_matches();
}
#[test]
fn create_flag_usage() {
let a = Arg::from_usage("[flag] -f 'some help info'");
assert_eq!(a.name, "flag");
assert_eq!(a.short.unwrap(), 'f');
assert!(a.long.is_none());
assert_eq!(a.help.unwrap(), "some help info");
assert!(!a.multiple);
let b = Arg::from_usage("[flag] --flag 'some help info'");
assert_eq!(b.name, "flag");
assert_eq!(b.long.unwrap(), "flag");
assert!(b.short.is_none());
assert_eq!(b.help.unwrap(), "some help info");
assert!(!b.multiple);
let b = Arg::from_usage("--flag 'some help info'");
assert_eq!(b.name, "flag");
assert_eq!(b.long.unwrap(), "flag");
assert!(b.short.is_none());
assert_eq!(b.help.unwrap(), "some help info");
assert!(!b.multiple);
let c = Arg::from_usage("[flag] -f --flag 'some help info'");
assert_eq!(c.name, "flag");
assert_eq!(c.short.unwrap(), 'f');
assert_eq!(c.long.unwrap(), "flag");
assert_eq!(c.help.unwrap(), "some help info");
assert!(!c.multiple);
let d = Arg::from_usage("[flag] -f... 'some help info'");
assert_eq!(d.name, "flag");
assert_eq!(d.short.unwrap(), 'f');
assert!(d.long.is_none());
assert_eq!(d.help.unwrap(), "some help info");
assert!(d.multiple);
let e = Arg::from_usage("[flag] -f --flag... 'some help info'");
assert_eq!(e.name, "flag");
assert_eq!(e.long.unwrap(), "flag");
assert_eq!(e.short.unwrap(), 'f');
assert_eq!(e.help.unwrap(), "some help info");
assert!(e.multiple);
let e = Arg::from_usage("-f --flag... 'some help info'");
assert_eq!(e.name, "flag");
assert_eq!(e.long.unwrap(), "flag");
assert_eq!(e.short.unwrap(), 'f');
assert_eq!(e.help.unwrap(), "some help info");
assert!(e.multiple);
}
#[test]
fn create_positional() {
let _ = App::new("test")
@ -47,6 +100,33 @@ mod tests {
.get_matches();
}
#[test]
fn create_positional_usage() {
let a = Arg::from_usage("[pos] 'some help info'");
assert_eq!(a.name, "pos");
assert_eq!(a.help.unwrap(), "some help info");
assert!(!a.multiple);
assert!(!a.required);
let b = Arg::from_usage("<pos> 'some help info'");
assert_eq!(b.name, "pos");
assert_eq!(b.help.unwrap(), "some help info");
assert!(!b.multiple);
assert!(b.required);
let c = Arg::from_usage("[pos]... 'some help info'");
assert_eq!(c.name, "pos");
assert_eq!(c.help.unwrap(), "some help info");
assert!(c.multiple);
assert!(!c.required);
let d = Arg::from_usage("<pos>... 'some help info'");
assert_eq!(d.name, "pos");
assert_eq!(d.help.unwrap(), "some help info");
assert!(d.multiple);
assert!(d.required);
}
#[test]
fn create_option() {
let _ = App::new("test")
@ -58,6 +138,432 @@ mod tests {
.get_matches();
}
#[test]
fn create_option_usage() {
// Short only
let a = Arg::from_usage("[option] -o [opt] 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.short.unwrap(), 'o');
assert!(a.long.is_none());
assert_eq!(a.help.unwrap(), "some help info");
assert!(!a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let b = Arg::from_usage("-o [opt] 'some help info'");
assert_eq!(b.name, "opt");
assert_eq!(b.short.unwrap(), 'o');
assert!(b.long.is_none());
assert_eq!(b.help.unwrap(), "some help info");
assert!(!b.multiple);
assert!(b.takes_value);
assert!(!b.required);
let c = Arg::from_usage("<option> -o <opt> 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(c.short.unwrap(), 'o');
assert!(c.long.is_none());
assert_eq!(c.help.unwrap(), "some help info");
assert!(!c.multiple);
assert!(c.takes_value);
assert!(c.required);
let d = Arg::from_usage("-o <opt> 'some help info'");
assert_eq!(d.name, "opt");
assert_eq!(d.short.unwrap(), 'o');
assert!(d.long.is_none());
assert_eq!(d.help.unwrap(), "some help info");
assert!(!d.multiple);
assert!(d.takes_value);
assert!(d.required);
let a = Arg::from_usage("[option] -o [opt]... 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.short.unwrap(), 'o');
assert!(a.long.is_none());
assert_eq!(a.help.unwrap(), "some help info");
assert!(a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let a = Arg::from_usage("[option]... -o [opt] 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.short.unwrap(), 'o');
assert!(a.long.is_none());
assert_eq!(a.help.unwrap(), "some help info");
assert!(a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let b = Arg::from_usage("-o [opt]... 'some help info'");
assert_eq!(b.name, "opt");
assert_eq!(b.short.unwrap(), 'o');
assert!(b.long.is_none());
assert_eq!(b.help.unwrap(), "some help info");
assert!(b.multiple);
assert!(b.takes_value);
assert!(!b.required);
let c = Arg::from_usage("<option> -o <opt>... 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(c.short.unwrap(), 'o');
assert!(c.long.is_none());
assert_eq!(c.help.unwrap(), "some help info");
assert!(c.multiple);
assert!(c.takes_value);
assert!(c.required);
let c = Arg::from_usage("<option>... -o <opt> 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(c.short.unwrap(), 'o');
assert!(c.long.is_none());
assert_eq!(c.help.unwrap(), "some help info");
assert!(c.multiple);
assert!(c.takes_value);
assert!(c.required);
let d = Arg::from_usage("-o <opt>... 'some help info'");
assert_eq!(d.name, "opt");
assert_eq!(d.short.unwrap(), 'o');
assert!(d.long.is_none());
assert_eq!(d.help.unwrap(), "some help info");
assert!(d.multiple);
assert!(d.takes_value);
assert!(d.required);
// Long only
let a = Arg::from_usage("[option] --opt [opt] 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert!(a.short.is_none());
assert_eq!(a.help.unwrap(), "some help info");
assert!(!a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let b = Arg::from_usage("--opt [option] 'some help info'");
assert_eq!(b.name, "option");
assert_eq!(b.long.unwrap(), "opt");
assert!(b.short.is_none());
assert_eq!(b.help.unwrap(), "some help info");
assert!(!b.multiple);
assert!(b.takes_value);
assert!(!b.required);
let c = Arg::from_usage("<option> --opt <opt> 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(c.long.unwrap(), "opt");
assert!(c.short.is_none());
assert_eq!(c.help.unwrap(), "some help info");
assert!(!c.multiple);
assert!(c.takes_value);
assert!(c.required);
let d = Arg::from_usage("--opt <option> 'some help info'");
assert_eq!(d.name, "option");
assert_eq!(d.long.unwrap(), "opt");
assert!(d.short.is_none());
assert_eq!(d.help.unwrap(), "some help info");
assert!(!d.multiple);
assert!(d.takes_value);
assert!(d.required);
let a = Arg::from_usage("[option] --opt [opt]... 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert!(a.short.is_none());
assert_eq!(a.help.unwrap(), "some help info");
assert!(a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let a = Arg::from_usage("[option]... --opt [opt] 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert!(a.short.is_none());
assert_eq!(a.help.unwrap(), "some help info");
assert!(a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let b = Arg::from_usage("--opt [option]... 'some help info'");
assert_eq!(b.name, "option");
assert_eq!(b.long.unwrap(), "opt");
assert!(b.short.is_none());
assert_eq!(b.help.unwrap(), "some help info");
assert!(b.multiple);
assert!(b.takes_value);
assert!(!b.required);
let c = Arg::from_usage("<option> --opt <opt>... 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(c.long.unwrap(), "opt");
assert!(c.short.is_none());
assert_eq!(c.help.unwrap(), "some help info");
assert!(c.multiple);
assert!(c.takes_value);
assert!(c.required);
let c = Arg::from_usage("<option>... --opt <opt> 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(c.long.unwrap(), "opt");
assert!(c.short.is_none());
assert_eq!(c.help.unwrap(), "some help info");
assert!(c.multiple);
assert!(c.takes_value);
assert!(c.required);
let d = Arg::from_usage("--opt <option>... 'some help info'");
assert_eq!(d.name, "option");
assert_eq!(d.long.unwrap(), "opt");
assert!(d.short.is_none());
assert_eq!(d.help.unwrap(), "some help info");
assert!(d.multiple);
assert!(d.takes_value);
assert!(d.required);
// Long only with '='
let a = Arg::from_usage("[option] --opt=[opt] 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert!(a.short.is_none());
assert_eq!(a.help.unwrap(), "some help info");
assert!(!a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let b = Arg::from_usage("--opt=[option] 'some help info'");
assert_eq!(b.name, "option");
assert_eq!(b.long.unwrap(), "opt");
assert!(b.short.is_none());
assert_eq!(b.help.unwrap(), "some help info");
assert!(!b.multiple);
assert!(b.takes_value);
assert!(!b.required);
let c = Arg::from_usage("<option> --opt=<opt> 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(c.long.unwrap(), "opt");
assert!(c.short.is_none());
assert_eq!(c.help.unwrap(), "some help info");
assert!(!c.multiple);
assert!(c.takes_value);
assert!(c.required);
let d = Arg::from_usage("--opt=<option> 'some help info'");
assert_eq!(d.name, "option");
assert_eq!(d.long.unwrap(), "opt");
assert!(d.short.is_none());
assert_eq!(d.help.unwrap(), "some help info");
assert!(!d.multiple);
assert!(d.takes_value);
assert!(d.required);
let a = Arg::from_usage("[option] --opt=[opt]... 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert!(a.short.is_none());
assert_eq!(a.help.unwrap(), "some help info");
assert!(a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let a = Arg::from_usage("[option]... --opt=[opt] 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert!(a.short.is_none());
assert_eq!(a.help.unwrap(), "some help info");
assert!(a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let b = Arg::from_usage("--opt=[option]... 'some help info'");
assert_eq!(b.name, "option");
assert_eq!(b.long.unwrap(), "opt");
assert!(b.short.is_none());
assert_eq!(b.help.unwrap(), "some help info");
assert!(b.multiple);
assert!(b.takes_value);
assert!(!b.required);
let c = Arg::from_usage("<option> --opt=<opt>... 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(c.long.unwrap(), "opt");
assert!(c.short.is_none());
assert_eq!(c.help.unwrap(), "some help info");
assert!(c.multiple);
assert!(c.takes_value);
assert!(c.required);
let c = Arg::from_usage("<option>... --opt=<opt> 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(c.long.unwrap(), "opt");
assert!(c.short.is_none());
assert_eq!(c.help.unwrap(), "some help info");
assert!(c.multiple);
assert!(c.takes_value);
assert!(c.required);
let d = Arg::from_usage("--opt=<option>... 'some help info'");
assert_eq!(d.name, "option");
assert_eq!(d.long.unwrap(), "opt");
assert!(d.short.is_none());
assert_eq!(d.help.unwrap(), "some help info");
assert!(d.multiple);
assert!(d.takes_value);
assert!(d.required);
// Long and Short
let a = Arg::from_usage("[option] -o --opt [option] 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(a.help.unwrap(), "some help info");
assert!(!a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let b = Arg::from_usage("-o --opt [option] 'some help info'");
assert_eq!(b.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(b.short.unwrap(), 'o');
assert_eq!(b.help.unwrap(), "some help info");
assert!(!b.multiple);
assert!(b.takes_value);
assert!(!b.required);
let c = Arg::from_usage("<option> -o --opt <opt> 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(c.help.unwrap(), "some help info");
assert!(!c.multiple);
assert!(c.takes_value);
assert!(c.required);
let d = Arg::from_usage("-o --opt <option> 'some help info'");
assert_eq!(d.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(d.help.unwrap(), "some help info");
assert!(!d.multiple);
assert!(d.takes_value);
assert!(d.required);
let a = Arg::from_usage("[option]... -o --opt [option] 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(a.help.unwrap(), "some help info");
assert!(a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let b = Arg::from_usage("-o --opt [option]... 'some help info'");
assert_eq!(b.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(b.short.unwrap(), 'o');
assert_eq!(b.help.unwrap(), "some help info");
assert!(b.multiple);
assert!(b.takes_value);
assert!(!b.required);
let c = Arg::from_usage("<option>... -o --opt <opt> 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(c.help.unwrap(), "some help info");
assert!(c.multiple);
assert!(c.takes_value);
assert!(c.required);
let d = Arg::from_usage("-o --opt <option>... 'some help info'");
assert_eq!(d.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(d.help.unwrap(), "some help info");
assert!(d.multiple);
assert!(d.takes_value);
assert!(d.required);
// Long and Short with '='
let a = Arg::from_usage("[option] -o --opt=[option] 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(a.help.unwrap(), "some help info");
assert!(!a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let b = Arg::from_usage("-o --opt=[option] 'some help info'");
assert_eq!(b.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(b.short.unwrap(), 'o');
assert_eq!(b.help.unwrap(), "some help info");
assert!(!b.multiple);
assert!(b.takes_value);
assert!(!b.required);
let c = Arg::from_usage("<option> -o --opt=<opt> 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(c.help.unwrap(), "some help info");
assert!(!c.multiple);
assert!(c.takes_value);
assert!(c.required);
let d = Arg::from_usage("-o --opt=<option> 'some help info'");
assert_eq!(d.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(d.help.unwrap(), "some help info");
assert!(!d.multiple);
assert!(d.takes_value);
assert!(d.required);
let a = Arg::from_usage("[option]... -o --opt=[option] 'some help info'");
assert_eq!(a.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(a.help.unwrap(), "some help info");
assert!(a.multiple);
assert!(a.takes_value);
assert!(!a.required);
let b = Arg::from_usage("-o --opt=[option]... 'some help info'");
assert_eq!(b.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(b.short.unwrap(), 'o');
assert_eq!(b.help.unwrap(), "some help info");
assert!(b.multiple);
assert!(b.takes_value);
assert!(!b.required);
let c = Arg::from_usage("<option>... -o --opt=<opt> 'some help info'");
assert_eq!(c.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(c.help.unwrap(), "some help info");
assert!(c.multiple);
assert!(c.takes_value);
assert!(c.required);
let d = Arg::from_usage("-o --opt=<option>... 'some help info'");
assert_eq!(d.name, "option");
assert_eq!(a.long.unwrap(), "opt");
assert_eq!(a.short.unwrap(), 'o');
assert_eq!(d.help.unwrap(), "some help info");
assert!(d.multiple);
assert!(d.takes_value);
assert!(d.required);
}
#[test]
fn create_subcommand() {
let _ = App::new("test")

View file

@ -11,4 +11,17 @@ macro_rules! get_help {
" ".to_owned()
}
};
}
// Thanks to bluss and flan3002 in #rust IRC
macro_rules! for_match {
($it:ident, $($p:pat => $($e:expr);+),*) => {
for i in $it {
match i {
$(
$p => { $($e)+ }
)*
}
}
};
}

126
src/usageparser.rs Normal file
View file

@ -0,0 +1,126 @@
use std::str::Chars;
pub enum UsageToken<'u> {
Name(&'u str, Option<bool>),
Short(char),
Long(&'u str),
Help(&'u str),
Multiple,
}
pub struct UsageParser<'u> {
usage: &'u str,
chars: Chars<'u>,
s: usize,
e: usize,
}
impl<'u> UsageParser<'u> {
pub fn with_usage(u: &'u str) -> UsageParser<'u> {
UsageParser {
usage: u,
chars: u.chars(),
s: 0,
e: 0,
}
}
}
impl<'u> Iterator for UsageParser<'u> {
type Item = UsageToken<'u>;
fn next(&mut self) -> Option<UsageToken<'u>> {
loop {
match self.chars.next() {
Some(c) if c == '[' || c == '<' => {
// self.s = self.e + 1;
if self.e != 0 {
self.e += 1;
}
self.s = self.e + 1;
let closing = match c {
'[' => ']',
'<' => '>',
_ => unreachable!()
};
while let Some(c) = self.chars.next() {
self.e += 1;
if c == closing { break }
}
if self.e > self.usage.len() { return None }
// self.e += 1;
let name = &self.usage[self.s..self.e];
return Some(UsageToken::Name(name, if c == '<' { Some(true)} else {None}));
},
Some('\'') => {
self.s = self.e + 2;
self.e = self.usage.len() - 1;
while let Some(_) = self.chars.next() { continue }
return Some(UsageToken::Help(&self.usage[self.s..self.e]));
},
Some('-') => {
self.e += 1;
match self.chars.next() {
Some('-') => {
if self.e != 1 {
self.e += 1;
}
self.s = self.e + 1;
while let Some(c) = self.chars.next() {
self.e += 1;
if c == ' ' || c == '=' || c == '.' { break }
}
if self.e > self.usage.len() { return None }
return Some(UsageToken::Long(&self.usage[self.s..self.e]))
},
Some(c) => {
// When short is first don't increment e
if self.e != 1 {
self.e += 1;
}
// Short
if !c.is_alphanumeric() {
return None
}
return Some(UsageToken::Short(c))
},
_ => {
return None
}
}
},
Some('.') => {
self.e += 1;
let mut mult = false;
for _ in 0..2 {
self.e += 1;
match self.chars.next() {
// longs consume one '.' so they match '.. ' whereas shorts can match '...'
Some('.') | Some(' ') => { mult = true; },
_ => { mult = false; break; }
}
}
if mult { return Some(UsageToken::Multiple) }
},
Some(' ') | Some('=') | Some(']') | Some('>') => {
self.e += 1;
continue
},
_ => {
return None
}
}
}
}
}