mirror of
https://github.com/clap-rs/clap
synced 2024-11-10 06:44:16 +00:00
wip
This commit is contained in:
parent
1498910971
commit
de36cd18c0
22 changed files with 483 additions and 516 deletions
|
@ -1,5 +1,4 @@
|
|||
[package]
|
||||
|
||||
name = "clap"
|
||||
version = "3.0.0-beta.1"
|
||||
authors = ["Kevin K. <kbknapp@gmail.com>"]
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
type_punctuation_density = "Compressed"
|
||||
format_strings = false
|
||||
fn_single_line = true
|
||||
where_pred_indent = "Visual"
|
272
src/args_map.rs
272
src/args_map.rs
|
@ -1,272 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Keys;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::slice::{Iter, IterMut};
|
||||
|
||||
use build::{ArgSettings, Arg};
|
||||
use util::hash;
|
||||
|
||||
// LE
|
||||
fn short_to_bytes(s: char) -> [u8; 8] {
|
||||
let bytes = ['-', s];
|
||||
let h = '-' as u32;
|
||||
let c = s as u32;
|
||||
|
||||
let b1 : u8 = ((h >> 24) & 0xff) as u8;
|
||||
let b2 : u8 = ((h >> 16) & 0xff) as u8;
|
||||
let b3 : u8 = ((h >> 8) & 0xff) as u8;
|
||||
let b4 : u8 = (h & 0xff) as u8;
|
||||
let b5 : u8 = ((c >> 24) & 0xff) as u8;
|
||||
let b6 : u8 = ((c >> 16) & 0xff) as u8;
|
||||
let b7 : u8 = ((c >> 8) & 0xff) as u8;
|
||||
let b8 : u8 = (c & 0xff) as u8;
|
||||
|
||||
[b1, b1, b3, b4, b5, b6, b7, b8]
|
||||
}
|
||||
|
||||
// LE
|
||||
fn u64_to_bytes(u: u64) -> [u8; 8] {
|
||||
let b1 : u8 = ((u >> 56) & 0xff) as u8;
|
||||
let b2 : u8 = ((u >> 48) & 0xff) as u8;
|
||||
let b3 : u8 = ((u >> 40) & 0xff) as u8;
|
||||
let b4 : u8 = ((u >> 32) & 0xff) as u8;
|
||||
let b5 : u8 = ((u >> 24) & 0xff) as u8;
|
||||
let b6 : u8 = ((u >> 16) & 0xff) as u8;
|
||||
let b7 : u8 = ((u >> 8) & 0xff) as u8;
|
||||
let b8 : u8 = (u & 0xff) as u8;
|
||||
|
||||
[b1, b1, b3, b4, b5, b6, b7, b8]
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Debug, Clone)]
|
||||
pub struct ArgsMap<'help> {
|
||||
pub index_map: HashMap<u64, usize>,
|
||||
pub args: Vec<Arg<'help>>,
|
||||
built: bool, // mutation isn't possible after being built
|
||||
}
|
||||
|
||||
impl<'help> ArgsMap<'help> {
|
||||
pub fn new() -> Self { ArgsMap::default() }
|
||||
//TODO ::from(x), ::with_capacity(n) etc
|
||||
|
||||
pub fn contains_long(&self, l: &str) -> bool { self.index_map.get(&hash(l.as_bytes())).is_some() }
|
||||
|
||||
pub fn contains_short(&self, c: char) -> bool { self.index_map.get(&hash(short_to_bytes(c))).is_some() }
|
||||
|
||||
pub fn insert(&mut self, arg: Arg<'help>) -> usize {
|
||||
assert!(!self.built, "Cannot add Args to the map after the map is built");
|
||||
|
||||
let index = self.args.len();
|
||||
self.insert_keys(&arg, index);
|
||||
self.args.push(arg);
|
||||
index
|
||||
}
|
||||
|
||||
pub fn push(&mut self, arg: Arg<'help>) -> usize {
|
||||
assert!(!self.built, "Cannot add Args to the map after the map is built");
|
||||
|
||||
let index = self.args.len();
|
||||
self.args.push(arg);
|
||||
index
|
||||
}
|
||||
|
||||
//TODO ::push_many([x, y])
|
||||
|
||||
pub fn insert_short_key(&mut self, key: char, index: usize) {
|
||||
self.index_map.insert(hash(short_to_bytes(key)), index);
|
||||
}
|
||||
|
||||
pub fn insert_long_key(&mut self, key: &str, index: usize) {
|
||||
self.index_map.insert(hash(key.as_bytes()), index);
|
||||
}
|
||||
|
||||
pub fn insert_positional_key(&mut self, key: u64, index: usize) {
|
||||
self.index_map.insert(hash(u64_to_bytes(key)), index);
|
||||
}
|
||||
|
||||
pub fn get_by_id(&self, key: u64) -> Option<&Arg<'help>> {
|
||||
self.args.get(*self.index_map.get(&key)?)
|
||||
}
|
||||
pub fn get_by_index(&self, key: usize) -> Option<&Arg<'help>> {
|
||||
self.args.get(key)
|
||||
}
|
||||
pub fn get_by_short(&self, key: char) -> Option<&Arg<'help>> {
|
||||
self.args.get(*self.index_map.get(&hash(short_to_bytes(key)))?)
|
||||
}
|
||||
// &[u8] better?
|
||||
pub fn get_by_short_with_hyphen(&self, key: [u8; 8]) -> Option<&Arg<'help>> {
|
||||
self.args.get(*self.index_map.get(&hash(&key))?)
|
||||
}
|
||||
pub fn get_by_long(&self, key: &str) -> Option<&Arg<'help>> {
|
||||
self.args.get(*self.index_map.get(&hash(key.as_bytes()))?)
|
||||
}
|
||||
pub fn get_by_long_with_hyphen(&self, key: &[u8]) -> Option<&Arg<'help>> {
|
||||
self.args.get(*self.index_map.get(&hash(key))?)
|
||||
}
|
||||
pub fn get_by_positional(&self, key: u64) -> Option<&Arg<'help>> {
|
||||
self.args.get(*self.index_map.get(&hash(u64_to_bytes(key)))?)
|
||||
}
|
||||
|
||||
pub fn get_mut_by_id(&mut self, key: u64) -> Option<&mut Arg<'help>> {
|
||||
self.args.get_mut(*self.index_map.get(&key)?)
|
||||
}
|
||||
pub fn get_mut_by_index(&mut self, key: usize) -> Option<&mut Arg<'help>> {
|
||||
self.args.get_mut(key)
|
||||
}
|
||||
pub fn get_mut_by_short(&mut self, key: char) -> Option<&mut Arg<'help>> {
|
||||
self.args.get_mut(*self.index_map.get(&hash(short_to_bytes(key)))?)
|
||||
}
|
||||
// &[u8] better?
|
||||
pub fn get_mut_by_short_with_hyphen(&mut self, key: [u8; 8]) -> Option<&mut Arg<'help>> {
|
||||
self.args.get_mut(*self.index_map.get(&hash(&key))?)
|
||||
}
|
||||
pub fn get_mut_by_long(&mut self, key: &str) -> Option<&mut Arg<'help>> {
|
||||
self.args.get_mut(*self.index_map.get(&hash(key.as_bytes()))?)
|
||||
}
|
||||
pub fn get_mut_by_long_with_hyphen(&mut self, key: &[u8]) -> Option<&mut Arg<'help>> {
|
||||
self.args.get_mut(*self.index_map.get(&hash(key))?)
|
||||
}
|
||||
pub fn get_mut_by_positional(&mut self, key: u64) -> Option<&mut Arg<'help>> {
|
||||
self.args.get_mut(*self.index_map.get(&hash(u64_to_bytes(key)))?)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool { self.args.is_empty() }
|
||||
|
||||
// Remove Key
|
||||
pub fn remove_id_key(&mut self, key: u64) -> Option<usize> {
|
||||
self.index_map.remove(&key)
|
||||
}
|
||||
pub fn remove_short_key(&mut self, key: char) -> Option<usize> {
|
||||
self.index_map.remove(&hash(short_to_bytes(key)))
|
||||
}
|
||||
pub fn remove_short_key_with_hyphen(&mut self, key: [u8; 8]) -> Option<usize> {
|
||||
self.index_map.remove(&hash(&key))
|
||||
}
|
||||
pub fn remove_long_key(&mut self, key: &str) -> Option<usize> {
|
||||
self.index_map.remove(&hash(key.as_bytes()))
|
||||
}
|
||||
pub fn remove_long_key_with_hyphen(&mut self, key: &[u8]) -> Option<usize> {
|
||||
self.index_map.remove(&hash(key))
|
||||
}
|
||||
pub fn remove_positional_key(&mut self, key: u64) -> Option<usize> {
|
||||
self.index_map.remove(&hash(u64_to_bytes(key)))
|
||||
}
|
||||
|
||||
pub fn remove_by_id(&mut self, id: u64) -> Option<Arg> {
|
||||
assert!(!self.built, "Cannot remove args once built");
|
||||
let i = self.index_map.remove(&id)?;
|
||||
Some(self.args.swap_remove(i))
|
||||
}
|
||||
|
||||
//TODO ::remove_keys([KeyA, KeyB])
|
||||
|
||||
fn insert_keys(&mut self, arg: &Arg, index: usize) {
|
||||
self.index_map.insert(arg.id, index);
|
||||
if let Some(p) = arg.index {
|
||||
self.index_map.insert(hash(u64_to_bytes(p)), index);
|
||||
} else {
|
||||
if let Some(s) = arg.short {
|
||||
self.index_map.insert(hash(short_to_bytes(s)), index);
|
||||
}
|
||||
if let Some(l) = arg.long {
|
||||
self.index_map.insert(hash(l.as_bytes()), index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _build(&mut self) {
|
||||
self.built = true;
|
||||
|
||||
for (i, arg) in self.args.iter().enumerate() {
|
||||
self.insert_keys(arg, i);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_by_name(&mut self, name: u64) -> usize {
|
||||
self.args
|
||||
.iter()
|
||||
.position(|x| x.id == name)
|
||||
.expect("No such name found")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Iter getters
|
||||
impl<'help> ArgsMap<'help> {
|
||||
pub fn iter_args(&self) -> Iter<Arg<'help>> {
|
||||
self.args.iter()
|
||||
}
|
||||
|
||||
pub fn iter_args_mut(&mut self) -> IterMut<Arg<'help>> {
|
||||
self.args.iter_mut()
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> impl Iterator<Item=&Arg<'help>> {
|
||||
self.args.iter().filter(|x| !x.is_set(ArgSettings::TakesValue) && x.has_switch())
|
||||
}
|
||||
|
||||
pub fn opts(&self) -> impl Iterator<Item=&Arg<'help>> {
|
||||
self.args.iter().filter(|x| x.is_set(ArgSettings::TakesValue) && x.has_switch())
|
||||
}
|
||||
|
||||
pub fn positionals(&self) -> impl Iterator<Item=&Arg<'help>> {
|
||||
self.args.iter().filter(|x| x.index.is_some())
|
||||
}
|
||||
|
||||
pub fn global_args(&self) -> impl Iterator<Item=&Arg<'help>> {
|
||||
self.args.iter().filter(|a| a.is_set(ArgSettings::Global))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use util::hash;
|
||||
|
||||
#[test]
|
||||
fn get_some_value() {
|
||||
let mut map: ArgsMap = ArgsMap::new();
|
||||
|
||||
map.insert(Arg::new("Value1").long("value"));
|
||||
|
||||
assert_eq!(
|
||||
map.get_by_long_with_hyphen("--value".as_bytes()).unwrap().id,
|
||||
hash("Value1")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_none_value() {
|
||||
let mut map: ArgsMap = ArgsMap::new();
|
||||
|
||||
map.insert(Arg::new("Value1").long("value"));
|
||||
|
||||
assert_eq!(map.get_by_long("none"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_multiple_keys() {
|
||||
let mut map: ArgsMap = ArgsMap::new();
|
||||
let index = map.insert(Arg::new("Value1").long("value"));
|
||||
|
||||
map.insert_long_key("other", index);
|
||||
|
||||
assert_eq!(
|
||||
map.get_by_long("value"),
|
||||
map.get_by_long("other"),
|
||||
);
|
||||
assert_eq!(map.args.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_key() {
|
||||
let mut map: ArgsMap = ArgsMap::new();
|
||||
let index = map.insert(Arg::new("Value1").long("value"));
|
||||
map.insert_long_key("other", index);
|
||||
|
||||
map.remove_long_key("other");
|
||||
|
||||
assert_eq!(map.index_map.len(), 1);
|
||||
assert_eq!(map.args.len(), 1);
|
||||
}
|
||||
}
|
|
@ -17,13 +17,14 @@ use std::process;
|
|||
use yaml_rust::Yaml;
|
||||
|
||||
// Internal
|
||||
use build::{Arg, ArgGroup, ArgSettings, Terminal, HelpMsg, VersionMsg, Aliases};
|
||||
use args_map::ArgsMap;
|
||||
use output::fmt::ColorWhen;
|
||||
use output::{Help, Usage};
|
||||
use parse::errors::Result as ClapResult;
|
||||
use parse::{ArgMatcher, ArgMatches, Parser};
|
||||
use util::hash;
|
||||
use crate::build::{Arg, ArgGroup, ArgSettings, Terminal, HelpMsg, VersionMsg, Aliases};
|
||||
use crate::build::args::Args;
|
||||
use crate::output::fmt::ColorWhen;
|
||||
use crate::output::{Help, Usage};
|
||||
use crate::parse::errors::Result as ClapResult;
|
||||
use crate::parse::{ArgMatcher, ArgMatches, Parser};
|
||||
use crate::util::hash;
|
||||
use crate::build::args::Find;
|
||||
use INTERNAL_ERROR_MSG;
|
||||
|
||||
#[doc(hidden)]
|
||||
|
@ -91,7 +92,7 @@ pub struct App<'help> {
|
|||
pub g_settings: AppFlags,
|
||||
// The list of valid arguments
|
||||
#[doc(hidden)]
|
||||
pub args: ArgsMap<'help>,
|
||||
pub args: Args<'help>,
|
||||
// A list of valid subcommands
|
||||
#[doc(hidden)]
|
||||
pub subcommands: Vec<App<'help>>,
|
||||
|
@ -127,6 +128,40 @@ impl<'help> App<'help> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Preallocate `args` number of Arguments
|
||||
pub fn with_args<S: AsRef<str>>(n: S, args: usize) -> Self where S: 'help {
|
||||
let name = n.as_ref();
|
||||
App {
|
||||
id: hash(name),
|
||||
name,
|
||||
args: Args::with_capacity(args),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Preallocate `scs` number of SubCommands
|
||||
pub fn with_subcommands<S: AsRef<str>>(n: S, scs: usize) -> Self where S: 'help {
|
||||
let name = n.as_ref();
|
||||
App {
|
||||
id: hash(name),
|
||||
name,
|
||||
subcommands: Vec::with_capacity(scs),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Preallocate `args` number of Arguments and `scs` number of SubCommands (not recursive)
|
||||
pub fn with_args_and_subcommands<S: AsRef<str>>(n: S, args: usize, scs: usize) -> Self where S: 'help {
|
||||
let name = n.as_ref();
|
||||
App {
|
||||
id: hash(name),
|
||||
name,
|
||||
args: Args::with_capacity(args),
|
||||
subcommands: Vec::with_capacity(scs),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the name of the app
|
||||
pub fn get_name(&self) -> &str { &self.name }
|
||||
|
||||
|
@ -962,7 +997,7 @@ impl<'help> App<'help> {
|
|||
{
|
||||
let a = self
|
||||
.args
|
||||
.remove_by_id(hash(arg))
|
||||
.remove(hash(arg))
|
||||
.unwrap_or_else(|| Arg::new(arg));
|
||||
self.args.push(f(a));
|
||||
|
||||
|
@ -1365,8 +1400,7 @@ impl<'a, 'help> App<'help> {
|
|||
|
||||
let global_arg_vec: Vec<u64> = self
|
||||
.args
|
||||
.args
|
||||
.iter()
|
||||
.args()
|
||||
.filter(|a| a.is_set(ArgSettings::Global))
|
||||
.map(|ga| ga.id)
|
||||
.collect();
|
||||
|
@ -1401,8 +1435,7 @@ impl<'a, 'help> App<'help> {
|
|||
true
|
||||
});
|
||||
|
||||
let mut pos_counter = 1;
|
||||
for a in self.args.args.iter_mut() {
|
||||
for a in self.args.args_mut() {
|
||||
// Figure out implied settings
|
||||
if a.is_set(ArgSettings::Last) {
|
||||
// if an arg has `Last` set, we need to imply DontCollapseArgsInUsage so that args
|
||||
|
@ -1411,10 +1444,6 @@ impl<'a, 'help> App<'help> {
|
|||
self.set(AppSettings::ContainsLast);
|
||||
}
|
||||
a._build();
|
||||
if a.short.is_none() && a.long.is_none() && a.index.is_none() {
|
||||
a.index = Some(pos_counter);
|
||||
pos_counter += 1;
|
||||
}
|
||||
}
|
||||
|
||||
debug_assert!(self._app_debug_asserts());
|
||||
|
@ -1425,8 +1454,8 @@ impl<'a, 'help> App<'help> {
|
|||
// Perform some expensive assertions on the Parser itself
|
||||
fn _app_debug_asserts(&mut self) -> bool {
|
||||
debugln!("App::_app_debug_asserts;");
|
||||
for id in self.args.args.iter().map(|x| x.id) {
|
||||
if self.args.args.iter().filter(|x| x.id == id).count() > 1 {
|
||||
for id in self.args.args.args().map(|x| x.id) {
|
||||
if self.args.args.args().filter(|x| x.id == id).count() > 1 {
|
||||
panic!("Arg names must be unique");
|
||||
}
|
||||
}
|
||||
|
@ -1471,7 +1500,7 @@ impl<'a, 'help> App<'help> {
|
|||
pub(crate) fn _create_help_and_version(&mut self) {
|
||||
debugln!("App::_create_help_and_version;");
|
||||
// @TODO @perf hardcode common hashes?
|
||||
if !(self.args.get_by_long("help").is_some() || self.args.get_by_id(hash("help")).is_some())
|
||||
if !(self.args.find("help").is_some() || self.args.get_by_id(hash("help")).is_some())
|
||||
{
|
||||
debugln!("App::_create_help_and_version: Building --help");
|
||||
let mut help = Arg::new("help")
|
||||
|
@ -1541,31 +1570,27 @@ impl<'a, 'help> App<'help> {
|
|||
debugln!("App::_arg_debug_asserts:{}", a.name);
|
||||
|
||||
// Long conflicts
|
||||
if let Some(l) = a.long {
|
||||
for l in a.longs() {
|
||||
assert!(
|
||||
self.args.args.iter().filter(|x| x.long == Some(l)).count() < 2,
|
||||
self.args.args().filter(|x| x.uses_long(l)).count() < 2,
|
||||
"Argument long must be unique\n\n\t--{} is already in use",
|
||||
l
|
||||
);
|
||||
}
|
||||
|
||||
// Short conflicts
|
||||
if let Some(s) = a.short {
|
||||
if let Some(s) = a.get_short() {
|
||||
assert!(
|
||||
self.args.args.iter().filter(|x| x.short == Some(s)).count() < 2,
|
||||
self.args.args().filter(|x| x.uses_short(s)).count() < 2,
|
||||
"Argument short must be unique\n\n\t-{} is already in use",
|
||||
s
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(idx) = a.index {
|
||||
if let Some(idx) = a.get_position() {
|
||||
// No index conflicts
|
||||
assert!(
|
||||
self.args.positionals().fold(0, |acc, p| if p.index == Some(idx as u64) {
|
||||
acc + 1
|
||||
} else {
|
||||
acc
|
||||
}) < 2,
|
||||
self.args.positionals().filter(|x| x.uses_position(idx)).count() < 2,
|
||||
"Argument '{}' has the same index as another positional \
|
||||
argument\n\n\tUse Arg::setting(ArgSettings::MultipleValues) to allow one \
|
||||
positional argument to take multiple values",
|
||||
|
@ -1574,14 +1599,8 @@ impl<'a, 'help> App<'help> {
|
|||
}
|
||||
if a.is_set(ArgSettings::Last) {
|
||||
assert!(
|
||||
a.long.is_none(),
|
||||
"Flags or Options may not have last(true) set. {} has both a long and \
|
||||
last(true) set.",
|
||||
a.id
|
||||
);
|
||||
assert!(
|
||||
a.short.is_none(),
|
||||
"Flags or Options may not have last(true) set. {} has both a short and \
|
||||
a.has_switch(),
|
||||
"Flags or Options may not have last(true) set. {} has either a long or short and \
|
||||
last(true) set.",
|
||||
a.id
|
||||
);
|
||||
|
@ -1690,20 +1709,6 @@ impl<'help> App<'help> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn contains_long(&self, l: &str) -> bool {
|
||||
if !self.is_set(AppSettings::Propagated) {
|
||||
panic!("If App::_build hasn't been called, manually search through Arg longs");
|
||||
}
|
||||
self.args.contains_long(l)
|
||||
}
|
||||
|
||||
pub(crate) fn contains_short(&self, s: char) -> bool {
|
||||
if !self.is_set(AppSettings::Propagated) {
|
||||
panic!("If App::_build hasn't been called, manually search through Arg shorts");
|
||||
}
|
||||
self.args.contains_short(s)
|
||||
}
|
||||
|
||||
pub fn is_set(&self, s: AppSettings) -> bool {
|
||||
self.settings.is_set(s) || self.g_settings.is_set(s)
|
||||
}
|
||||
|
@ -1718,28 +1723,6 @@ impl<'help> App<'help> {
|
|||
|
||||
pub fn has_subcommands(&self) -> bool { !self.subcommands.is_empty() }
|
||||
|
||||
pub fn has_args(&self) -> bool { !self.args.is_empty() }
|
||||
|
||||
pub fn has_opts(&self) -> bool { self.args.has_opts() }
|
||||
|
||||
pub fn has_flags(&self) -> bool { self.args.has_flags() }
|
||||
|
||||
pub fn has_positionals(&self) -> bool { self.args.has_positionals() }
|
||||
|
||||
pub fn has_visible_opts(&self) -> bool { self.args.opts().any(|o| !o.is_set(ArgSettings::Hidden)) }
|
||||
|
||||
pub fn has_visible_flags(&self) -> bool { self.args.flags().any(|o| !o.is_set(ArgSettings::Hidden)) }
|
||||
|
||||
pub fn has_visible_positionals(&self) -> bool {
|
||||
self.args.positionals().any(|o| !o.is_set(ArgSettings::Hidden))
|
||||
}
|
||||
|
||||
pub fn has_visible_subcommands(&self) -> bool {
|
||||
self.subcommands.iter()
|
||||
.filter(|sc| sc.name != "help")
|
||||
.any(|sc| !sc.is_set(AppSettings::Hidden))
|
||||
}
|
||||
|
||||
pub(crate) fn unroll_args_in_group(&self, group: u64) -> Vec<u64> {
|
||||
let mut g_vec = vec![group];
|
||||
let mut args = vec![];
|
||||
|
@ -1754,7 +1737,7 @@ impl<'help> App<'help> {
|
|||
.iter()
|
||||
{
|
||||
if !args.contains(n) {
|
||||
if self.find(*n).is_some() {
|
||||
if self.args.find(*n).is_some() {
|
||||
args.push(*n)
|
||||
} else {
|
||||
g_vec.push(*n);
|
|
@ -1,37 +1,31 @@
|
|||
// @TODO @p2 @docs remove Arg::setting(foo) in examples, we are sticking with Arg::foo(true) isntead
|
||||
|
||||
// @TODO @p2 @docs remove Arg::setting(foo) in examples, we are sticking with Arg::foo(true) instead
|
||||
mod settings;
|
||||
mod key;
|
||||
mod short;
|
||||
mod long;
|
||||
pub use self::settings::{ArgFlags, ArgSettings};
|
||||
|
||||
// Std
|
||||
#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
|
||||
use osstringext::OsStrExt3;
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::hash::Hash;
|
||||
#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::rc::Rc;
|
||||
use std::str;
|
||||
use std::hash::Hash;
|
||||
|
||||
// Third Party
|
||||
use util::VecMap;
|
||||
#[cfg(feature = "yaml")]
|
||||
use yaml_rust;
|
||||
|
||||
// Internal
|
||||
use build::UsageParser;
|
||||
use INTERNAL_ERROR_MSG;
|
||||
#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
|
||||
use osstringext::OsStrExt3;
|
||||
use util::hash;
|
||||
use self::key::Key;
|
||||
use util::VecMap;
|
||||
|
||||
type Validator = Rc<Fn(String) -> Result<(), String>>;
|
||||
type ValidatorOs = Rc<Fn(&OsStr) -> Result<(), String>>;
|
||||
pub use self::key::{Key, Position, Short, Long};
|
||||
pub use self::settings::{ArgFlags, ArgSettings};
|
||||
|
||||
pub type ArgId = u64;
|
||||
|
||||
/// The abstract representation of a command line argument. Used to set all the options and
|
||||
/// relationships that define a valid argument for the program.
|
||||
|
@ -59,13 +53,16 @@ type ValidatorOs = Rc<Fn(&OsStr) -> Result<(), String>>;
|
|||
#[derive(Default, Clone)]
|
||||
pub struct Arg<'help> {
|
||||
#[doc(hidden)]
|
||||
pub id: u64,
|
||||
pub id: ArgId,
|
||||
#[doc(hidden)]
|
||||
key: Key<'help>,
|
||||
#[doc(hidden)]
|
||||
pub settings: ArgFlags,
|
||||
#[doc(hidden)]
|
||||
pub env: Option<(&'help OsStr, Option<OsString>)>,
|
||||
settings: ArgFlags,
|
||||
value: Option<Value>,
|
||||
help: HelpMessage,
|
||||
occurrence: Occurrence,
|
||||
validation: ValidationRules<'help>,
|
||||
|
||||
}
|
||||
|
||||
impl<'help> Arg<'help> {
|
||||
|
@ -86,35 +83,15 @@ impl<'help> Arg<'help> {
|
|||
/// ```
|
||||
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
|
||||
/// [`Arg`]: ./struct.Arg.html
|
||||
pub fn new<T>(id: T) -> Self where T: Hash {
|
||||
pub fn new<T>(id: T) -> Self where T: Hash{
|
||||
Arg {
|
||||
id: hash(id),
|
||||
disp_ord: 999,
|
||||
unified_ord: 999,
|
||||
help: None,
|
||||
long_help: None,
|
||||
blacklist: None,
|
||||
settings: ArgFlags::default(),
|
||||
r_unless: None,
|
||||
overrides: None,
|
||||
requires: None,
|
||||
key: Key::new(),
|
||||
possible_vals: None,
|
||||
val_names: None,
|
||||
num_vals: None,
|
||||
num_vals_per_occ: None,
|
||||
max_vals: None,
|
||||
min_vals: None,
|
||||
validator: None,
|
||||
validator_os: None,
|
||||
val_delim: None,
|
||||
default_val: None,
|
||||
default_vals_ifs: None,
|
||||
env: None,
|
||||
terminator: None,
|
||||
index: None,
|
||||
r_ifs: None,
|
||||
help_heading: None,
|
||||
value: None,
|
||||
help: HelpMessage::new(),
|
||||
occurrence: Occurrence::new(),
|
||||
validation: ValidationRules::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,7 +328,7 @@ impl<'help> Arg<'help> {
|
|||
/// ```
|
||||
/// [`Arg::long_help`]: ./struct.Arg.html#method.long_help
|
||||
pub fn help(mut self, h: &'help str) -> Self {
|
||||
self.help = Some(h);
|
||||
self.help.short_message(h);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -422,7 +399,7 @@ impl<'help> Arg<'help> {
|
|||
/// ```
|
||||
/// [`Arg::help`]: ./struct.Arg.html#method.help
|
||||
pub fn long_help(mut self, h: &'help str) -> Self {
|
||||
self.long_help = Some(h);
|
||||
self.help.long_message(h);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -484,11 +461,10 @@ impl<'help> Arg<'help> {
|
|||
/// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless
|
||||
pub fn required_unless<T>(mut self, other: T) -> Self where T: Hash {
|
||||
let id = hash(other);
|
||||
if let Some(ref mut vec) = self.r_unless {
|
||||
vec.push(id);
|
||||
} else {
|
||||
self.r_unless = Some(vec![id]);
|
||||
}
|
||||
self.validation.self_required_rule(
|
||||
Rule::new()
|
||||
.rule_modifier(RuleModifier::Unless)
|
||||
.condition(Condition::new(id)));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -556,14 +532,13 @@ impl<'help> Arg<'help> {
|
|||
/// [`Arg::required_unless_one`]: ./struct.Arg.html#method.required_unless_one
|
||||
/// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all
|
||||
pub fn required_unless_all<T>(mut self, others: &[T]) -> Self where T: Hash {
|
||||
if let Some(ref mut vec) = self.r_unless {
|
||||
for s in others {
|
||||
vec.push(hash(s));
|
||||
}
|
||||
} else {
|
||||
self.r_unless = Some(others.iter().map(hash).collect());
|
||||
}
|
||||
self.setting(ArgSettings::RequiredUnlessAll)
|
||||
self.validation.self_required_rule(
|
||||
Rule::new()
|
||||
.rule_modifier(RuleModifier::Unless)
|
||||
.conditions_modifier(ConditionsModifier::All)
|
||||
.conditions(
|
||||
others.iter().map(|x| Condition::new(hash(x)))));
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets args that override this arg's [required] setting. (i.e. this arg will be required
|
||||
|
@ -631,13 +606,11 @@ impl<'help> Arg<'help> {
|
|||
/// [`Arg::required_unless_one(names)`]: ./struct.Arg.html#method.required_unless_one
|
||||
/// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all
|
||||
pub fn required_unless_one<T>(mut self, others: &[T]) -> Self where T: Hash {
|
||||
if let Some(ref mut vec) = self.r_unless {
|
||||
for s in others {
|
||||
vec.push(hash(s));
|
||||
}
|
||||
} else {
|
||||
self.r_unless = Some(others.iter().map(hash).collect());
|
||||
}
|
||||
self.validation.self_required_rule(
|
||||
Rule::new()
|
||||
.rule_modifier(RuleModifier::Unless)
|
||||
.conditions(
|
||||
others.iter().map(|x| Condition::new(hash(x)))));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -680,11 +653,9 @@ impl<'help> Arg<'help> {
|
|||
/// ```
|
||||
pub fn conflicts_with<T>(mut self, other: T) -> Self where T: Hash {
|
||||
let id = hash(other);
|
||||
if let Some(ref mut vec) = self.blacklist {
|
||||
vec.push(id);
|
||||
} else {
|
||||
self.blacklist = Some(vec![id]);
|
||||
}
|
||||
self.validation.conflicts_rule(
|
||||
Rule::new()
|
||||
.condition(Condition::new(id)));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -730,13 +701,10 @@ impl<'help> Arg<'help> {
|
|||
/// ```
|
||||
/// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with
|
||||
pub fn conflicts_with_all<T>(mut self, others: &[T]) -> Self where T: Hash {
|
||||
if let Some(ref mut vec) = self.blacklist {
|
||||
for s in others {
|
||||
vec.push(hash(s));
|
||||
}
|
||||
} else {
|
||||
self.blacklist = Some(others.iter().map(hash).collect());
|
||||
}
|
||||
self.validation.conflicts_rule(
|
||||
Rule::new()
|
||||
.conditions_modifier(ConditionsModifier::All)
|
||||
.conditions(otheres.iter().map(|x| Condition::new(hash(x)))));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -842,12 +810,9 @@ impl<'help> Arg<'help> {
|
|||
/// [`Multiple*`]: ./enum.ArgSettings.html#variant.MultipleValues
|
||||
/// [`UseValueDelimiter`]: ./enum.ArgSettings.html#variant.UseValueDelimiter
|
||||
pub fn overrides_with<T>(mut self, other: T) -> Self where T: Hash {
|
||||
let id = hash(other);
|
||||
if let Some(ref mut vec) = self.overrides {
|
||||
vec.push(id);
|
||||
} else {
|
||||
self.overrides = Some(vec![id]);
|
||||
}
|
||||
self.validation.overrides_rule(
|
||||
Rule::new()
|
||||
.condition(Condition::new(hash(other))));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -878,14 +843,11 @@ impl<'help> Arg<'help> {
|
|||
/// assert!(!m.is_present("debug"));
|
||||
/// assert!(!m.is_present("flag"));
|
||||
/// ```
|
||||
pub fn overrides_with_all<T>(mut self, others: &[T]) -> Self where T: Hash{
|
||||
if let Some(ref mut vec) = self.overrides {
|
||||
for s in others {
|
||||
vec.push(hash(s));
|
||||
}
|
||||
} else {
|
||||
self.overrides = Some(others.iter().map(hash).collect());
|
||||
}
|
||||
pub fn overrides_with_all<T>(mut self, others: &[T]) -> Self where T: Hash {
|
||||
self.validation.overrides_rule(
|
||||
Rule::new()
|
||||
.conditions_modifier(ConditionsModifier::All)
|
||||
.conditions(others.iter().map(|x| Condition::new(hash(x)))));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -945,14 +907,9 @@ impl<'help> Arg<'help> {
|
|||
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
|
||||
/// [override]: ./struct.Arg.html#method.overrides_with
|
||||
pub fn requires<T>(mut self, other: T) -> Self where T: Hash {
|
||||
let id = hash(other);
|
||||
if let Some(ref mut vec) = self.requires {
|
||||
vec.push((None, id));
|
||||
} else {
|
||||
let mut vec = vec![];
|
||||
vec.push((None, id));
|
||||
self.requires = Some(vec);
|
||||
}
|
||||
self.validation.requirements_rule(
|
||||
Rule::new()
|
||||
.condition(Condition::new(hash(other))));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -1016,12 +973,10 @@ impl<'help> Arg<'help> {
|
|||
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
|
||||
/// [override]: ./struct.Arg.html#method.overrides_with
|
||||
pub fn requires_if<T>(mut self, val: &'help str, other: T) -> Self where T: Hash {
|
||||
let id = hash(other);
|
||||
if let Some(ref mut vec) = self.requires {
|
||||
vec.push((Some(val), id));
|
||||
} else {
|
||||
self.requires = Some(vec![(Some(val), id)]);
|
||||
}
|
||||
// need self val and other val...have to re-think
|
||||
self.validation.requirements_rule(
|
||||
Rule::new()
|
||||
.condition(Condition::new(hash(other))));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -1384,7 +1339,7 @@ impl<'help> Arg<'help> {
|
|||
/// [`App`]: ./struct.App.html
|
||||
/// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html
|
||||
pub fn index(mut self, idx: u64) -> Self {
|
||||
self.index = Some(idx);
|
||||
self.key.index(idx);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -1434,8 +1389,7 @@ impl<'help> Arg<'help> {
|
|||
/// [`number_of_values`]: ./struct.Arg.html#method.number_of_values
|
||||
/// [`max_values`]: ./struct.Arg.html#method.max_values
|
||||
pub fn value_terminator(mut self, term: &'help str) -> Self {
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
self.terminator = Some(term);
|
||||
self.value.terminator(term);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -1487,7 +1441,6 @@ impl<'help> Arg<'help> {
|
|||
/// [options]: ./struct.Arg.html#method.takes_value
|
||||
/// [positional arguments]: ./struct.Arg.html#method.index
|
||||
pub fn possible_values(mut self, values: &[&'help str]) -> Self {
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
if let Some(ref mut vec) = self.possible_vals {
|
||||
for s in values {
|
||||
vec.push(s);
|
||||
|
@ -1552,7 +1505,6 @@ impl<'help> Arg<'help> {
|
|||
/// [options]: ./struct.Arg.html#method.takes_value
|
||||
/// [positional arguments]: ./struct.Arg.html#method.index
|
||||
pub fn possible_value(mut self, value: &'help str) -> Self {
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
if let Some(ref mut vec) = self.possible_vals {
|
||||
vec.push(value);
|
||||
} else {
|
||||
|
@ -1598,7 +1550,6 @@ impl<'help> Arg<'help> {
|
|||
/// ```
|
||||
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
|
||||
pub fn number_of_values(mut self, qty: u64) -> Self {
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
self.num_vals = Some(qty);
|
||||
self
|
||||
}
|
||||
|
@ -1639,7 +1590,6 @@ impl<'help> Arg<'help> {
|
|||
/// ```
|
||||
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
|
||||
pub fn number_of_values_per_occurrence(mut self, qty: u64) -> Self {
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
self.num_vals_per_occ = Some(qty);
|
||||
self
|
||||
}
|
||||
|
@ -1786,8 +1736,6 @@ impl<'help> Arg<'help> {
|
|||
/// ```
|
||||
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
|
||||
pub fn max_values(mut self, qty: u64) -> Self {
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
self.setb(ArgSettings::MultipleValues);
|
||||
self.max_vals = Some(qty);
|
||||
self
|
||||
}
|
||||
|
@ -1851,7 +1799,7 @@ impl<'help> Arg<'help> {
|
|||
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
|
||||
pub fn min_values(mut self, qty: u64) -> Self {
|
||||
self.min_vals = Some(qty);
|
||||
self.setting(ArgSettings::TakesValue)
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies the separator to use when values are clumped together, defaults to `,` (comma).
|
||||
|
@ -1878,9 +1826,6 @@ impl<'help> Arg<'help> {
|
|||
/// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter
|
||||
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
|
||||
pub fn value_delimiter(mut self, d: &str) -> Self {
|
||||
self.unsetb(ArgSettings::ValueDelimiterNotSet);
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
self.setb(ArgSettings::UseValueDelimiter);
|
||||
self.val_delim = Some(
|
||||
d.chars()
|
||||
.nth(0)
|
||||
|
@ -1949,11 +1894,6 @@ impl<'help> Arg<'help> {
|
|||
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
|
||||
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
|
||||
pub fn value_names(mut self, names: &[&'help str]) -> Self {
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
if self.is_set(ArgSettings::ValueDelimiterNotSet) {
|
||||
self.unsetb(ArgSettings::ValueDelimiterNotSet);
|
||||
self.setb(ArgSettings::UseValueDelimiter);
|
||||
}
|
||||
if let Some(ref mut vals) = self.val_names {
|
||||
let mut l = vals.len();
|
||||
for s in names {
|
||||
|
@ -2017,7 +1957,6 @@ impl<'help> Arg<'help> {
|
|||
/// [positional]: ./struct.Arg.html#method.index
|
||||
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
|
||||
pub fn value_name(mut self, name: &'help str) -> Self {
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
if let Some(ref mut vals) = self.val_names {
|
||||
let l = vals.len();
|
||||
vals.insert(l, name);
|
||||
|
@ -2101,7 +2040,6 @@ impl<'help> Arg<'help> {
|
|||
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
|
||||
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
|
||||
pub fn default_value_os(mut self, val: &'help OsStr) -> Self {
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
self.default_val = Some(val);
|
||||
self
|
||||
}
|
||||
|
@ -2221,7 +2159,6 @@ impl<'help> Arg<'help> {
|
|||
default: &'help OsStr,
|
||||
) -> Self where T: Hash {
|
||||
let id = hash(arg);
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
if let Some(ref mut vm) = self.default_vals_ifs {
|
||||
let l = vm.len();
|
||||
vm.insert(l, (id, val, default));
|
||||
|
@ -2333,7 +2270,7 @@ impl<'help> Arg<'help> {
|
|||
/// [`Arg::default_value_ifs`]: ./struct.Arg.html#method.default_value_ifs
|
||||
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
|
||||
#[cfg_attr(feature = "lints", allow(explicit_counter_loop))]
|
||||
pub fn default_value_ifs_os<T>(mut self, ifs: &[(T, Option<&'help OsStr>, &'help OsStr)]) -> Self where T: Hash{
|
||||
pub fn default_value_ifs_os<T>(mut self, ifs: &[(T, Option<&'help OsStr>, &'help OsStr)]) -> Self where T: Hash {
|
||||
for &(arg, val, default) in ifs {
|
||||
self = self.default_value_if_os(arg, val, default);
|
||||
}
|
||||
|
@ -2445,8 +2382,6 @@ impl<'help> Arg<'help> {
|
|||
/// from the environment if available in the exact same manner as [`Arg::env`] only using
|
||||
/// [`OsStr`]s instead.
|
||||
pub fn env_os(mut self, name: &'help OsStr) -> Self {
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
|
||||
self.env = Some((name, env::var_os(name)));
|
||||
self
|
||||
}
|
||||
|
@ -3831,7 +3766,7 @@ impl<'help> Arg<'help> {
|
|||
#[doc(hidden)]
|
||||
pub fn _build(&mut self) {
|
||||
self.set_default_delimiter();
|
||||
if self.key.is_positional() {
|
||||
if self.is_positional() {
|
||||
if self.max_vals.is_some()
|
||||
|| self.min_vals.is_some()
|
||||
|| (self.num_vals.is_some() && self.num_vals.unwrap() > 1)
|
||||
|
@ -4137,16 +4072,16 @@ impl<'help> From<&'help yaml_rust::Yaml> for Arg<'help> {
|
|||
|
||||
a
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Flags
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Arg;
|
||||
use build::ArgSettings;
|
||||
use util::VecMap;
|
||||
|
||||
use super::Arg;
|
||||
|
||||
#[test]
|
||||
fn flag_display() {
|
||||
let mut f = Arg::new("flg");
|
|
@ -1,8 +1,25 @@
|
|||
#[derive(Default)]
|
||||
pub struct HelpMessage<'help> {
|
||||
short_message: &'help str,
|
||||
long_message: &'help str,
|
||||
short: Option<&'help str>,
|
||||
long: Option<&'help str>,
|
||||
value_names: VecMap<ValueName>,
|
||||
display_order: DisplayOrder,
|
||||
unified_order: DisplayOrder, // @TODO remove?
|
||||
heading: &'help str, // @TODO multiple?
|
||||
}
|
||||
|
||||
impl<'help> HelpMessage<'help> {
|
||||
pub fn new() -> Self {
|
||||
HelpMessage::default()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn short_message(&mut self, m: &'help str) {
|
||||
self.short = Some(m);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn long_message(&mut self, m: &'help str) {
|
||||
self.long = Some(m);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,10 @@
|
|||
use build::arg::{Short, Long, Position};
|
||||
mod long;
|
||||
mod short;
|
||||
mod position;
|
||||
|
||||
pub use self::long::Long;
|
||||
pub use self::short::Short;
|
||||
pub use self::position::Position;
|
||||
|
||||
pub struct Key<'help> {
|
||||
short: Option<Short>,
|
||||
|
@ -20,12 +26,16 @@ impl<'help> Key<'help> {
|
|||
}
|
||||
|
||||
pub fn short(&mut self, short: char) {
|
||||
self.short.replace(short);
|
||||
self.short.replace(Short(short));
|
||||
}
|
||||
|
||||
pub fn long(&mut self, l: &'help str) {
|
||||
self.long.add_long(l);
|
||||
}
|
||||
pub fn index(&mut self, i: u64) {
|
||||
self.index = Some(Position::at(i));
|
||||
}
|
||||
|
||||
pub fn hidden_long(&mut self, l: &'help str) {
|
||||
self.long.add_hidden_long(l);
|
||||
}
|
|
@ -7,7 +7,11 @@ impl Default for Position {
|
|||
}
|
||||
|
||||
impl Position {
|
||||
fn new() -> Self {
|
||||
pub fn new() -> Self {
|
||||
Position(1)
|
||||
}
|
||||
pub fn at(i: u64) -> Self {
|
||||
assert!(i>0, "Positional Index cannot be less than 1");
|
||||
Position(i)
|
||||
}
|
||||
}
|
|
@ -1,3 +1 @@
|
|||
pub struct Short {
|
||||
short: char
|
||||
}
|
||||
pub struct Short(char);
|
||||
|
|
|
@ -1,5 +1,34 @@
|
|||
#[derive(Default, Copy, Clone, PartialEq, Eq)]
|
||||
use std::u64;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Occurrence {
|
||||
min: u64,
|
||||
max: u64
|
||||
}
|
||||
|
||||
impl Default for Occurrence {
|
||||
fn default() -> Self {
|
||||
Occurrence {
|
||||
min: 1,
|
||||
max: u64::MAX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Occurrence {
|
||||
#[inline(always)]
|
||||
pub fn min(&mut self, num: u64) {
|
||||
self.min = num;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn max(&mut self, num: u64) {
|
||||
self.max = num;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn exact(&mut self, num: u64) {
|
||||
self.max = num;
|
||||
self.min = num;
|
||||
}
|
||||
}
|
|
@ -1,17 +1,49 @@
|
|||
pub struct Rule<'help> {
|
||||
other_arg: u64,
|
||||
self_value: Option<&'help str>,
|
||||
other_value: Option<&'help str>,
|
||||
}
|
||||
|
||||
pub struct Rules<'help> {
|
||||
rules: Vec<Rule<'help>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ValidationRules<'help> {
|
||||
occurrence: Occurrence,
|
||||
conflicts: Rules<'help>,
|
||||
requirements: Rules<'help>,
|
||||
overrides: Rules<'help>,
|
||||
requirements_unless: Rules<'help>,
|
||||
conflicts: Vec<Rule<'help>>,
|
||||
requirements: Vec<Rule<'help>>,
|
||||
self_required: Vec<Rule<'help>>,
|
||||
overrides: Vec<Rule<'help>>,
|
||||
}
|
||||
|
||||
impl<'help> ValidationRules<'help> {
|
||||
pub fn new() -> Self {
|
||||
ValidationRules::default()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn requirement_rule(&mut self, r: Rule) {
|
||||
self.requirements.push(r);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn self_required_rule(&mut self, r: Rule) {
|
||||
self.self_required.push(r);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn conflicts_rule(&mut self, r: Rule) {
|
||||
self.conflicts.push(r);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn overrides_rule(&mut self, r: Rule) {
|
||||
self.overrides.push(r);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn max_occurs(&mut self, num: usize) {
|
||||
self.occurrence.max(num);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn min_occurs(&mut self, num: usize) {
|
||||
self.occurrence.min(num);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn exact_occurs(&mut self, num: usize) {
|
||||
self.occurrence.exact(num);
|
||||
}
|
||||
}
|
||||
|
|
43
src/build/arg/validation_rules/conditions.rs
Normal file
43
src/build/arg/validation_rules/conditions.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
pub enum ConditionsModifier {
|
||||
All,
|
||||
Any,
|
||||
None,
|
||||
}
|
||||
|
||||
impl Default for ConditionsModifer {
|
||||
fn default() -> Self {
|
||||
ConditionsModifier::Any
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Condition<'help> {
|
||||
arg: u64,
|
||||
arg_value: Option<&'help str>,
|
||||
other_value: Option<&'help str>,
|
||||
}
|
||||
|
||||
impl<'help> Condition<'help> {
|
||||
pub fn new(id: ArgId) -> Self {
|
||||
Condition {
|
||||
arg: id,
|
||||
arg_value: None,
|
||||
other_value: None,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn arg(mut self, id: ArgId) -> Self {
|
||||
self.arg = id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn arg_value(mut self, val: &'help str) -> Self {
|
||||
self.arg_value = Some(val);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn other_value(mut self, val: &'help str) -> Self {
|
||||
self.other_value = Some(val);
|
||||
self
|
||||
}
|
||||
}
|
52
src/build/arg/validation_rules/rules.rs
Normal file
52
src/build/arg/validation_rules/rules.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use super::ConditionsModifier;
|
||||
|
||||
pub enum RuleModifer {
|
||||
Unless,
|
||||
With,
|
||||
}
|
||||
|
||||
impl Default for RuleModifer {
|
||||
fn default() -> Self {
|
||||
RuleModifer::With
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Rule<'help> {
|
||||
rule_mod: RuleModifer,
|
||||
conditions_mod: ConditionsModifier,
|
||||
conditions: Vec<Condition<'help>>,
|
||||
}
|
||||
|
||||
impl<'help> Rule<'help> {
|
||||
pub fn new() -> Self {
|
||||
Rule::default()
|
||||
}
|
||||
|
||||
pub fn rule_modifier(mut self, rm: RuleModifer) -> Self {
|
||||
self.rule_mod = rm;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn conditions_mod(mut self, cm: ConditionsModifier) -> Self {
|
||||
self.conditions_mod = cm;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn condition(mut self, c: Condition) -> Self {
|
||||
self.conditions.push(c);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn conditions(mut self, conds: &dyn Iterator<Item=Condition>) -> Self {
|
||||
for c in conds {
|
||||
self.conditions.push(cond);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn clear_conditions(&mut self) {
|
||||
self.conditions.clear()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,10 @@
|
|||
mod default_values;
|
||||
mod delimiter;
|
||||
mod filter;
|
||||
mod possible_values;
|
||||
mod terminator;
|
||||
mod value_name;
|
||||
|
||||
pub struct Value<'help> {
|
||||
defaults: Option<DefaultValues>,
|
||||
filter: Filter,
|
||||
|
@ -5,3 +12,9 @@ pub struct Value<'help> {
|
|||
requires_equals: bool,
|
||||
delimiter: Delimiter,
|
||||
}
|
||||
|
||||
impl<'help> Value<'help> {
|
||||
fn new() -> Self {
|
||||
|
||||
}
|
||||
}
|
4
src/build/arg/value/filter/validators.rs
Normal file
4
src/build/arg/value/filter/validators.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
pub type Validator = Rc<Fn(String) -> Result<(), String>>;
|
||||
pub type ValidatorOs = Rc<Fn(&OsStr) -> Result<(), String>>;
|
||||
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
// Maybe move to help message? Or keep here in case we integrate into Value at some point?
|
||||
|
||||
use std::io;
|
||||
|
||||
pub struct ValueName<'help>(&'help str);
|
||||
|
|
113
src/build/args.rs
Normal file
113
src/build/args.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use std::ops::Index;
|
||||
|
||||
use crate::Arg;
|
||||
use crate::build::arg::{ArgId, Position};
|
||||
|
||||
pub trait Find<By> {
|
||||
type Output;
|
||||
fn find(&self, by: By) -> Option<<Self as Find<By>>::Output>;
|
||||
}
|
||||
|
||||
pub trait FindMut<By> {
|
||||
type Output;
|
||||
fn find(&mut self, by: By) -> Option<<Self as FindMut<By>>::Output>;
|
||||
}
|
||||
|
||||
pub struct Args<'help> {
|
||||
inner: Vec<Arg<'help>>,
|
||||
}
|
||||
|
||||
impl<'help> Args<'help> {
|
||||
pub fn contains_short(&self, s: char) -> bool {
|
||||
self.args().any(|x| x.uses_short(c))
|
||||
}
|
||||
pub fn contains_long(&self, l: &str) -> bool {
|
||||
self.args().any(|x| x.uses_long(l))
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
pub fn has_flags(&self) -> bool {
|
||||
self.flags().any(|x| x.is_flag())
|
||||
}
|
||||
pub fn has_options(&self) -> bool {
|
||||
self.options().any(|x| x.is_option())
|
||||
}
|
||||
pub fn has_positionals(&self) -> bool {
|
||||
self.positionals().any(|x| x.is_positional())
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
pub fn push(&mut self, arg: Arg<'help>) {
|
||||
self.inner.push(arg)
|
||||
}
|
||||
pub fn remove(&mut self, id: ArgId) -> Option<Arg<'help>> {
|
||||
let opt_i = self.args().enumerate().find(|(x, i)| x.id == id).map(|x| x.0);
|
||||
if let Some(i) = opt_i {
|
||||
Some(self.inner.swap_remove(i))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn find(&self, id: ArgId) -> Option<&Arg<'help>> {
|
||||
self.args().find(|x| x.id == id)
|
||||
}
|
||||
pub fn find_short(&self, s: char) -> Option<&Arg<'help>> {
|
||||
self.args().find(|x| x.uses_short(s))
|
||||
}
|
||||
pub fn find_long(&self, l: &str) -> Option<&Arg<'help>> {
|
||||
self.args().find(|x| x.uses_long(l))
|
||||
}
|
||||
pub fn find_position(&self, p: Position) -> Option<&Arg<'help>> {
|
||||
self.positionals().find(|x| x.uses_position(p))
|
||||
}
|
||||
pub fn find_mut(&mut self, id: ArgId) -> Option<&mut Arg<'help>> {
|
||||
self.args_mut().find(|x| x.id == id)
|
||||
}
|
||||
pub fn find_short_mut(&mut self, s: char) -> Option<&mut Arg<'help>> {
|
||||
self.args_mut().find(|x| x.uses_short(s))
|
||||
}
|
||||
pub fn find_long_mut(&mut self, l: &str) -> Option<&mut Arg<'help>> {
|
||||
self.args_mut().find(|x| x.uses_long(l))
|
||||
}
|
||||
pub fn find_position_mut(&mut self, p: Position) -> Option<&mut Arg<'help>> {
|
||||
self.positionals_mut().find(|x| x.uses_position(p))
|
||||
}
|
||||
}
|
||||
|
||||
// Iterator Getters
|
||||
impl<'help> Args<'help> {
|
||||
pub fn args(&self) -> impl Iterator<Item=&Arg> {
|
||||
self.inner.iter()
|
||||
}
|
||||
pub fn flags(&self) -> impl Iterator<Item=&Arg> {
|
||||
self.args().filter(|x| x.is_flat())
|
||||
}
|
||||
pub fn options(&self) -> impl Iterator<Item=&Arg> {
|
||||
self.args().filter(|x| x.is_option())
|
||||
}
|
||||
pub fn positionals(&self) -> impl Iterator<Item=&Arg> {
|
||||
self.args().filter(|x| x.is_positional())
|
||||
}
|
||||
pub fn args_mut(&mut self) -> impl Iterator<Item=&mut Arg> {
|
||||
self.inner.iter_mut()
|
||||
}
|
||||
pub fn flags_mut(&mut self) -> impl Iterator<Item=&mut Arg> {
|
||||
self.args_mut().filter(|x| x.is_flat())
|
||||
}
|
||||
pub fn options_mut(&mut self) -> impl Iterator<Item=&mut Arg> {
|
||||
self.args_mut().filter(|x| x.is_option())
|
||||
}
|
||||
pub fn positionals_mut(&mut self) -> impl Iterator<Item=&mut Arg> {
|
||||
self.args_mut().filter(|x| x.is_positional())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'help> Index<usize> for Args<'help> {
|
||||
type Output = &'a Arg<'help>;
|
||||
|
||||
fn index(&'a self, index: usize) -> &'a Arg<'help> {
|
||||
self.inner[index]
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ mod aliases;
|
|||
|
||||
pub mod app;
|
||||
pub mod arg;
|
||||
pub mod args;
|
||||
|
||||
mod arg_group;
|
||||
mod usage_parser;
|
||||
|
|
|
@ -578,7 +578,6 @@ use std::result::Result as StdResult;
|
|||
mod macros;
|
||||
|
||||
mod build;
|
||||
mod args_map;
|
||||
mod output;
|
||||
mod parse;
|
||||
mod util;
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
use std::hash::{Hash, Hasher};
|
||||
|
||||
const MAGIC_INIT: u64 = 0x811C9DC5;
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn hash<T>(t: T) -> u64 where T: Hash {
|
||||
pub(crate) fn hash<T>(t: T) -> u64
|
||||
where
|
||||
T: Hash,
|
||||
{
|
||||
let mut hasher = FnvHasher::new();
|
||||
t.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
|
@ -10,9 +15,7 @@ pub(crate) fn hash<T>(t: T) -> u64 where T: Hash {
|
|||
pub(crate) struct FnvHasher(u64);
|
||||
|
||||
impl FnvHasher {
|
||||
pub(crate) fn new() -> Self {
|
||||
FnvHasher(0x811C9DC5)
|
||||
}
|
||||
pub(crate) fn new() -> Self { FnvHasher(MAGIC_INIT) }
|
||||
}
|
||||
|
||||
impl Hasher for FnvHasher {
|
||||
|
|
Loading…
Reference in a new issue