Skip to content

Commit

Permalink
feat(ArgGroups): add ability to create arg groups
Browse files Browse the repository at this point in the history
  • Loading branch information
kbknapp committed Apr 27, 2015
1 parent cfffb45 commit 09eb4d9
Show file tree
Hide file tree
Showing 9 changed files with 535 additions and 66 deletions.
236 changes: 193 additions & 43 deletions src/app.rs

Large diffs are not rendered by default.

65 changes: 44 additions & 21 deletions src/args/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use usageparser::{UsageParser, UsageToken};
/// // Using a usage string (setting a similar argument to the one above)
/// Arg::from_usage("-i --input=[input] 'Provides an input file to the program'")
/// # ).get_matches();
pub struct Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub struct Arg<'n, 'l, 'h, 'g, 'p, 'r> {
/// The unique name of the argument, required
#[doc(hidden)]
pub name: &'n str,
Expand Down Expand Up @@ -65,17 +65,20 @@ pub struct Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub multiple: bool,
/// A list of names for other arguments that *may not* be used with this flag
#[doc(hidden)]
pub blacklist: Option<Vec<&'b str>>,
pub blacklist: Option<Vec<&'r str>>,
/// A list of possible values for an option or positional argument
#[doc(hidden)]
pub possible_vals: Option<Vec<&'p str>>,
/// A list of names of other arguments that are *required* to be used when
/// this flag is used
#[doc(hidden)]
pub requires: Option<Vec<&'r str>>
pub requires: Option<Vec<&'r str>>,
/// A name of the group the argument belongs to
#[doc(hidden)]
pub group: Option<&'g str>
}

impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
impl<'n, 'l, 'h, 'g, 'p, 'r> Arg<'n, 'l, 'h, 'g, '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.
Expand All @@ -97,7 +100,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// Arg::new("conifg")
/// # .short("c")
/// # ).get_matches();
pub fn new(n: &'n str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn new(n: &'n str) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
Arg {
name: n,
short: None,
Expand All @@ -110,6 +113,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
possible_vals: None,
blacklist: None,
requires: None,
group: None,
}
}

Expand All @@ -131,7 +135,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// Arg::with_name("conifg")
/// # .short("c")
/// # ).get_matches();
pub fn with_name(n: &'n str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn with_name(n: &'n str) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
Arg {
name: n,
short: None,
Expand All @@ -144,6 +148,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
possible_vals: None,
blacklist: None,
requires: None,
group: None,
}
}

Expand Down Expand Up @@ -195,7 +200,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// 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> {
pub fn from_usage(u: &'n str) -> Arg<'n, 'n, 'n, 'g, 'p, 'r> {
assert!(u.len() > 0, "Arg::from_usage() requires a non-zero-length usage string but none was provided");

let mut name = None;
Expand Down Expand Up @@ -258,6 +263,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
possible_vals: None,
blacklist: None,
requires: None,
group: None,
}
}

Expand All @@ -281,7 +287,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// # Arg::new("conifg")
/// .short("c")
/// # ).get_matches();
pub fn short(mut self, s: &str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn short(mut self, s: &str) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
self.short = s.trim_left_matches(|c| c == '-').chars().nth(0);
self
}
Expand All @@ -305,7 +311,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// # Arg::new("conifg")
/// .long("config")
/// # ).get_matches();
pub fn long(mut self, l: &'l str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn long(mut self, l: &'l str) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
self.long = Some(l.trim_left_matches(|c| c == '-'));
self
}
Expand All @@ -323,7 +329,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// # Arg::new("conifg")
/// .help("The config file used by the myprog")
/// # ).get_matches();
pub fn help(mut self, h: &'h str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn help(mut self, h: &'h str) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
self.help = Some(h);
self
}
Expand All @@ -347,7 +353,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// # Arg::with_name("conifg")
/// .required(true)
/// # ).get_matches();
pub fn required(mut self, r: bool) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn required(mut self, r: bool) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
self.required = r;
self
}
Expand All @@ -369,7 +375,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// # let myprog = App::new("myprog").arg(Arg::with_name("conifg")
/// .mutually_excludes("debug")
/// # ).get_matches();
pub fn mutually_excludes(mut self, name: &'b str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn mutually_excludes(mut self, name: &'r str) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
if let Some(ref mut vec) = self.blacklist {
vec.push(name);
} else {
Expand All @@ -396,7 +402,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// .mutually_excludes_all(
/// vec!["debug", "input"])
/// # ).get_matches();
pub fn mutually_excludes_all(mut self, names: Vec<&'b str>) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn mutually_excludes_all(mut self, names: Vec<&'r str>) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
if let Some(ref mut vec) = self.blacklist {
for n in names {
vec.push(n);
Expand All @@ -422,7 +428,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// # let myprog = App::new("myprog").arg(Arg::with_name("conifg")
/// .conflicts_with("debug")
/// # ).get_matches();
pub fn conflicts_with(mut self, name: &'b str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn conflicts_with(mut self, name: &'r str) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
if let Some(ref mut vec) = self.blacklist {
vec.push(name);
} else {
Expand All @@ -447,7 +453,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// .conflicts_with_all(
/// vec!["debug", "input"])
/// # ).get_matches();
pub fn conflicts_with_all(mut self, names: Vec<&'b str>) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn conflicts_with_all(mut self, names: Vec<&'r str>) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
if let Some(ref mut vec) = self.blacklist {
for n in names {
vec.push(n);
Expand All @@ -471,7 +477,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// # let myprog = App::new("myprog").arg(Arg::with_name("conifg")
/// .requires("debug")
/// # ).get_matches();
pub fn requires(mut self, name: &'r str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn requires(mut self, name: &'r str) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
if let Some(ref mut vec) = self.requires {
vec.push(name);
} else {
Expand All @@ -495,7 +501,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// .requires_all(
/// vec!["debug", "input"])
/// # ).get_matches();
pub fn requires_all(mut self, names: Vec<&'r str>) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn requires_all(mut self, names: Vec<&'r str>) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
if let Some(ref mut vec) = self.requires {
for n in names {
vec.push(n);
Expand All @@ -521,7 +527,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// # Arg::with_name("conifg")
/// .takes_value(true)
/// # ).get_matches();
pub fn takes_value(mut self, tv: bool) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn takes_value(mut self, tv: bool) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
self.takes_value = tv;
self
}
Expand All @@ -543,7 +549,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// # Arg::with_name("conifg")
/// .index(1)
/// # ).get_matches();
pub fn index(mut self, idx: u8) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn index(mut self, idx: u8) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
self.index = Some(idx);
self
}
Expand All @@ -566,7 +572,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// # Arg::with_name("debug")
/// .multiple(true)
/// # ).get_matches();
pub fn multiple(mut self, multi: bool) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn multiple(mut self, multi: bool) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
self.multiple = multi;
self
}
Expand All @@ -586,7 +592,7 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// # Arg::with_name("debug").index(1)
/// .possible_values(vec!["fast", "slow"])
/// # ).get_matches();
pub fn possible_values(mut self, names: Vec<&'p str>) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
pub fn possible_values(mut self, names: Vec<&'p str>) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
if let Some(ref mut vec) = self.possible_vals {
for n in names {
vec.push(n);
Expand All @@ -596,4 +602,21 @@ impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
}
self
}

/// Specifies the name of the group the argument belongs to.
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// # Arg::with_name("debug").index(1)
/// .group("mode")
/// # ).get_matches();
pub fn group(mut self, name: &'g str) -> Arg<'n, 'l, 'h, 'g, 'p, 'r> {
self.group = Some(name);
self
}
}
7 changes: 7 additions & 0 deletions src/args/argbuilder/flag.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::HashSet;
use std::fmt::{ Display, Formatter, Result };

pub struct FlagBuilder<'n> {
pub name: &'n str,
Expand All @@ -23,4 +24,10 @@ pub struct FlagBuilder<'n> {
/// The short version (i.e. single character)
/// of the argument, no preceding `-`
pub short: Option<char>,
}

impl<'n> Display for FlagBuilder<'n> {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{}", if self.long.is_some() { format!("--{}", self.long.unwrap())} else {format!("-{}", self.short.unwrap())})
}
}
7 changes: 7 additions & 0 deletions src/args/argbuilder/option.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashSet;
use std::collections::BTreeSet;
use std::fmt::{ Display, Formatter, Result };

pub struct OptBuilder<'n> {
pub name: &'n str,
Expand All @@ -25,3 +26,9 @@ pub struct OptBuilder<'n> {
/// this flag is used
pub requires: Option<HashSet<&'n str>>,
}

impl<'n> Display for OptBuilder<'n> {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{} <{}>{}", if self.long.is_some() { format!("--{}", self.long.unwrap())} else {format!("-{}", self.short.unwrap())}, self.name, if self.multiple{"..."}else{""})
}
}
7 changes: 7 additions & 0 deletions src/args/argbuilder/positional.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashSet;
use std::collections::BTreeSet;
use std::fmt::{ Display, Formatter, Result };

pub struct PosBuilder<'n> {
pub name: &'n str,
Expand All @@ -22,4 +23,10 @@ pub struct PosBuilder<'n> {
pub possible_vals: Option<BTreeSet<&'n str>>,
/// The index of the argument
pub index: u8
}

impl<'n> Display for PosBuilder<'n> {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{}{}{}{}", if self.required { "<" } else {"["}, self.name,if self.required { ">" } else {"]"}, if self.multiple {"..."}else{""})
}
}
Loading

0 comments on commit 09eb4d9

Please sign in to comment.