mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 22:32:33 +00:00
Merge pull request #70 from kbknapp/from-usage
Adds the ability to create args from a usage string
This commit is contained in:
commit
24dcc13b03
8 changed files with 876 additions and 48 deletions
|
@ -18,14 +18,14 @@ FLAGS:
|
|||
-v, --version Prints version information
|
||||
|
||||
OPTIONS:
|
||||
-o, --option=option... tests options
|
||||
--long-option-2=option2 tests long options with exclusions and requirements
|
||||
-O option3 test options with specific value sets [values: fast slow]
|
||||
-o, --option=opt... tests options
|
||||
--long-option-2=option2 tests long options with exclusions
|
||||
-O option3 tests options with specific value sets [values: fast slow]
|
||||
|
||||
POSITIONAL ARGUMENTS:
|
||||
positional tests positionals
|
||||
positional2 tests positionals with exclusions and multiple
|
||||
positional3... tests positionals with specific value sets [values: emacs vi]
|
||||
positional2 tests positionals with exclusions
|
||||
positional3... tests positionals with specific values [values: emacs vi]
|
||||
|
||||
SUBCOMMANDS:
|
||||
help Prints this message
|
||||
|
|
|
@ -3,6 +3,10 @@ extern crate clap;
|
|||
use clap::{App, Arg, SubCommand};
|
||||
|
||||
fn main() {
|
||||
let args =
|
||||
"-f --flag... 'tests flags'
|
||||
-o --option=[opt]... 'tests options'
|
||||
[positional] 'tests positionals'";
|
||||
// Test version from Cargo.toml
|
||||
let version = format!("{}.{}.{}{}",
|
||||
env!("CARGO_PKG_VERSION_MAJOR"),
|
||||
|
@ -13,45 +17,21 @@ fn main() {
|
|||
.version(&version[..])
|
||||
.about("tests clap library")
|
||||
.author("Kevin K. <kbknapp@gmail.com>")
|
||||
.arg(Arg::new("flag")
|
||||
.short("f")
|
||||
.long("flag")
|
||||
.help("tests flags")
|
||||
.multiple(true))
|
||||
.arg(Arg::new("option")
|
||||
.short("o")
|
||||
.long("option")
|
||||
.help("tests options")
|
||||
.takes_value(true)
|
||||
.multiple(true))
|
||||
.arg(Arg::new("positional")
|
||||
.index(1)
|
||||
.help("tests positionals"))
|
||||
.args_from_usage(args)
|
||||
.args(vec![
|
||||
Arg::new("flag2").short("F").mutually_excludes("flag").help("tests flags with exclusions").requires("option2"),
|
||||
Arg::new("option2").takes_value(true).long("long-option-2").mutually_excludes("option").help("tests long options with exclusions and requirements").requires("positional2"),
|
||||
Arg::new("positional2").index(2).help("tests positionals with exclusions and multiple"),
|
||||
Arg::new("option3").takes_value(true).short("O").possible_values(vec!["fast", "slow"]).help("test options with specific value sets"),
|
||||
Arg::new("positional3").index(3).multiple(true).possible_values(vec!["vi", "emacs"]).help("tests positionals with specific value sets")
|
||||
Arg::from_usage("[flag2] -F 'tests flags with exclusions'").mutually_excludes("flag").requires("option2"),
|
||||
Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").mutually_excludes("option").requires("positional2"),
|
||||
Arg::from_usage("[positional2] 'tests positionals with exclusions'"),
|
||||
Arg::from_usage("-O [option3] 'tests options with specific value sets'").possible_values(vec!["fast", "slow"]),
|
||||
Arg::from_usage("[positional3]... 'tests positionals with specific values'").possible_values(vec!["vi", "emacs"])
|
||||
])
|
||||
.subcommand(SubCommand::new("subcmd")
|
||||
.about("tests subcommands")
|
||||
.version("0.1")
|
||||
.author("Kevin K. <kbknapp@gmail.com>")
|
||||
.arg(Arg::new("scflag")
|
||||
.short("f")
|
||||
.long("flag")
|
||||
.help("tests flags")
|
||||
.multiple(true))
|
||||
.arg(Arg::new("scoption")
|
||||
.short("o")
|
||||
.long("option")
|
||||
.help("tests options")
|
||||
.takes_value(true)
|
||||
.multiple(true))
|
||||
.arg(Arg::new("scpositional")
|
||||
.index(1)
|
||||
.help("tests positionals")))
|
||||
.arg_from_usage("[scflag] -f --flag... 'tests flags'")
|
||||
.arg_from_usage("-o --option [scoption]... 'tests options'")
|
||||
.arg_from_usage("[scpositional] 'tests positionals'"))
|
||||
.get_matches();
|
||||
|
||||
if matches.is_present("flag") {
|
||||
|
@ -60,11 +40,11 @@ fn main() {
|
|||
println!("flag NOT present");
|
||||
}
|
||||
|
||||
if matches.is_present("option") {
|
||||
if let Some(v) = matches.value_of("option") {
|
||||
println!("option present {} times with value: {}",matches.occurrences_of("option"), v);
|
||||
if matches.is_present("opt") {
|
||||
if let Some(v) = matches.value_of("opt") {
|
||||
println!("option present {} times with value: {}",matches.occurrences_of("opt"), v);
|
||||
}
|
||||
if let Some(ref ov) = matches.values_of("option") {
|
||||
if let Some(ref ov) = matches.values_of("opt") {
|
||||
for o in ov {
|
||||
println!("An option: {}", o);
|
||||
}
|
||||
|
@ -101,11 +81,11 @@ fn main() {
|
|||
_ => println!("positional3 NOT present")
|
||||
}
|
||||
|
||||
if matches.is_present("option") {
|
||||
if let Some(v) = matches.value_of("option") {
|
||||
println!("option present {} times with value: {}",matches.occurrences_of("option"), v);
|
||||
if matches.is_present("opt") {
|
||||
if let Some(v) = matches.value_of("opt") {
|
||||
println!("option present {} times with value: {}",matches.occurrences_of("opt"), v);
|
||||
}
|
||||
if let Some(ref ov) = matches.values_of("option") {
|
||||
if let Some(ref ov) = matches.values_of("opt") {
|
||||
for o in ov {
|
||||
println!("An option: {}", o);
|
||||
}
|
||||
|
|
12
gede.ini
Normal file
12
gede.ini
Normal 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"
|
46
src/app.rs
46
src/app.rs
|
@ -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);
|
||||
|
@ -360,6 +365,43 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
|
|||
self
|
||||
}
|
||||
|
||||
/// Adds an argument from a usage string. See Arg::from_usage() for details
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap::{App, Arg};
|
||||
/// # let app = App::new("myprog")
|
||||
/// .arg_from_usage("-c --conf=<config> 'Sets a configuration file to use'")
|
||||
/// # .get_matches();
|
||||
/// ```
|
||||
pub fn arg_from_usage(mut self, usage: &'ar str) -> App<'a, 'v, 'ab, 'u, 'ar> {
|
||||
self = self.arg(Arg::from_usage(usage));
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds multiple arguments from a usage string, one per line. See Arg::from_usage() for
|
||||
/// details
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap::{App, Arg};
|
||||
/// # let app = App::new("myprog")
|
||||
/// .args_from_usage(
|
||||
/// "-c --conf=[config] 'Sets a configuration file to use'
|
||||
/// [debug]... -d 'Sets the debugging level'
|
||||
/// <input> 'The input file to use'")
|
||||
/// # .get_matches();
|
||||
/// ```
|
||||
pub fn args_from_usage(mut self, usage: &'ar str) -> App<'a, 'v, 'ab, 'u, 'ar> {
|
||||
for l in usage.lines() {
|
||||
self = self.arg(Arg::from_usage(l));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
/// Adds a subcommand to the list of valid possibilties. Subcommands are effectively sub apps,
|
||||
/// because they can contain their own arguments, subcommands, version, usage, etc. They also
|
||||
/// function just like apps, in that they get their own auto generated help and version
|
||||
|
|
149
src/args/arg.rs
149
src/args/arg.rs
|
@ -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,148 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new instace of `Arg` using a usage string. Allows creation of basic settings
|
||||
/// for Arg (i.e. everything except relational rules). The syntax is flexible, but there are
|
||||
/// some rules to follow.
|
||||
///
|
||||
/// The syntax should be as follows (only properties which you wish to set must be present):
|
||||
///
|
||||
/// 1. Name (arguments with a `long` or that take a value can ommit this if desired),
|
||||
/// use `[]` for non-required arguments, or `<>` for required arguments.
|
||||
/// 2. Short preceded by a `-`
|
||||
/// 3. Long preceded by a `--` (this may be used as the name, if the name is omitted. If the
|
||||
/// name is *not* omittied, the name takes precedence)
|
||||
/// 4. Value (this can be used as the name, if the name is not manually specified. If the name
|
||||
/// is manually specified, it takes precence. If this value is used as the name, it uses the
|
||||
/// same `[]` and `<>` requirement rules. If it is *not* used as the name, it still needs to
|
||||
/// be surrounded by either `[]` or `<>` but the effect is the same, as the requirement rule
|
||||
/// is determined by the name. The value may follow the `short` or `long`. If it
|
||||
/// follows the `long`, it may follow either a `=` or ` ` with the same effect, personal
|
||||
/// preference only, but may only follow a ` ` after a `short`)
|
||||
/// 5. Multiple specifier `...` (for flags or positional arguments the `...` may follow the
|
||||
/// name or `short` or `long`)
|
||||
/// 6. The help info surrounded by `'`
|
||||
/// 7. The index of a positional argument will be the next available index (you don't need to
|
||||
/// specify one)
|
||||
///
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap::{App, Arg};
|
||||
/// # let matches = App::new("myprog")
|
||||
/// .args(vec![
|
||||
/// // A option argument with a long, named "conf" (note: because the name was specified
|
||||
/// // the portion after the long can be called anything, only the first name will be displayed
|
||||
/// // to the user. Also, requirement is set with the *name*, so the portion after the long could
|
||||
/// // be either <> or [] and it wouldn't matter, so long as it's one of them. Had the name been
|
||||
/// // omitted, the name would have been derived from the portion after the long and those rules
|
||||
/// // would have mattered)
|
||||
/// Arg::from_usage("[conf] --config=[c] 'a required file for the configuration'"),
|
||||
/// // A flag with a short, a long, named "debug", and accepts multiple values
|
||||
/// Arg::from_usage("-d --debug... 'turns on debugging information"),
|
||||
/// // A required positional argument named "input"
|
||||
/// Arg::from_usage("<input> 'the input file to use'")
|
||||
/// ])
|
||||
/// #
|
||||
/// # .get_matches();
|
||||
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 `-`.
|
||||
///
|
||||
///
|
||||
|
|
506
src/lib.rs
506
src/lib.rs
|
@ -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")
|
||||
|
|
|
@ -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
126
src/usageparser.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue