wip refactoring shorts and longs into an arg key

This commit is contained in:
Kevin K 2019-09-04 21:46:14 -04:00
parent 4f48b3db63
commit b59850a6ef
No known key found for this signature in database
GPG key ID: 17218E4B3692F01A
5 changed files with 71 additions and 50 deletions

View file

@ -1,11 +1,18 @@
use bstr::{BStr, B};
pub struct Alias<'help> {
name: &'help str,
vis: bool,
pub(crate) name: &'help BStr,
pub(crate) vis: bool,
}
impl<'help> Alias<'help> {
fn visible(n: &'help str) -> Self { Alias { name: n, vis: true } }
fn hidden(n: &'help str) -> Self {
pub fn visible<T: ?Sized + AsRef<[u8]>>(n: T) -> Self {
Alias {
name: B(n),
vis: true,
}
}
pub fn hidden(n: &'help str) -> Self {
Alias {
name: n,
vis: false,

View file

@ -1,3 +1,7 @@
// Third party
use bstr::{ByteSlice, B};
// Internal
use crate::build::Alias;
#[derive(Default)]
@ -7,8 +11,14 @@ pub struct Key<'help> {
#[derive(Default)]
pub struct SwitchData<'help> {
longs: Vec<Alias<'help>>,
short: Option<char>,
l: Vec<Alias<'help>>,
s: Option<char>,
}
impl<'help> SwitchData<'help> {
pub fn short(&self) -> Option<char> { self.s }
pub fn all_longs(&self) -> impl Iterator<Item = &str> { self.l.iter().map(|a| a.name) }
pub fn has_longs(&self) -> bool { !self.l.is_empty() }
}
pub(crate) enum KeyKind<'help> {
@ -22,38 +32,40 @@ impl<'help> Default for KeyKind<'help> {
}
impl<'help> Key<'help> {
fn set_short(&mut self, c: char) { self.switch_mut().short = Some(c); }
fn add_long(&mut self, l: &'help str) {
pub fn has_long(&self) -> bool { self.has_switch() && self.switch().has_longs() }
pub fn has_short(&self) -> bool { self.has_switch() && self.switch().short().is_some() }
pub fn set_short(&mut self, c: char) { self.switch_mut().s = Some(c); }
pub fn add_long(&mut self, l: &'help str) {
self.switch_mut()
.longs
.push(Alias::visible(l.trim_left_matches(|c| c == '-')));
.l
.push(Alias::visible(B(l).trim_start_with(|c| c == '-')));
}
fn add_longs(&mut self, longs: &[&'help str]) {
pub fn add_longs(&mut self, longs: &[&'help str]) {
for l in longs {
self.long(l);
}
}
fn add_hidden_long(&mut self, l: &'help str) {
pub fn add_hidden_long(&mut self, l: &'help str) {
self.switch_mut()
.longs
.l
.push(Alias::hidden(l.trim_left_matches(|c| c == '-')));
}
fn add_hidden_longs(&mut self, longs: &[&'help str]) {
pub fn add_hidden_longs(&mut self, longs: &[&'help str]) {
for l in longs {
self.switch_mut()
.longs
.l
.push(Alias::hidden(l.trim_left_matches(|c| c == '-')));
}
}
fn set_index(&mut self, i: usize) {
pub fn set_index(&mut self, i: usize) {
assert!(i > 0, "Argument index cannot be zero (0)");
self.kind = KeyKind::Index(i);
}
fn has_index(&self) -> bool { self.index().is_some() }
pub fn has_index(&self) -> bool { self.index().is_some() }
/// # Panics
///
/// Panics if `*self != KeyKind::Index`
fn index(&self) -> usize {
pub fn index(&self) -> usize {
use KeyKind::*;
match self.kind {
Index(i) => i,
@ -63,14 +75,14 @@ impl<'help> Key<'help> {
/// # Panics
///
/// Panics if `*self != KeyKind::Index`
fn index_mut(&mut self) -> usize {
pub fn index_mut(&mut self) -> usize {
use KeyKind::*;
match *self {
Index(i) => i,
_ => panic!("Argument is not positional"),
}
}
fn has_switch(&self) -> bool {
pub fn has_switch(&self) -> bool {
use KeyKind::*;
match *self {
Switch(_) => true,
@ -80,7 +92,7 @@ impl<'help> Key<'help> {
/// # Panics
///
/// Panics if `*self != KeyKind::Switch`
fn switch(&self) -> &SwitchData<'help> {
pub fn switch(&self) -> &SwitchData<'help> {
use KeyKind::*;
match *self {
Switch(s) => s,
@ -90,7 +102,7 @@ impl<'help> Key<'help> {
/// # Panics
///
/// Panics if `*self != KeyKind::Switch`
fn switch_mut(&mut self) -> &mut SwitchData<'help> {
pub fn switch_mut(&mut self) -> &mut SwitchData<'help> {
use KeyKind::*;
match *self {
Switch(s) => s,

View file

@ -78,10 +78,6 @@ pub struct Arg<'help> {
#[doc(hidden)]
pub groups: Option<Vec<Id>>,
// position
#[doc(hidden)]
pub index: Option<u64>,
// validation
#[doc(hidden)]
pub r_ifs: Option<Vec<(Id, &'help str)>>,
@ -4005,11 +4001,15 @@ impl<'help> Arg<'help> {
#[doc(hidden)]
pub fn has_switch(&self) -> bool { self.key.has_switch() }
#[doc(hidden)]
pub fn switch(&self) -> &SwitchData { self.key.switch() }
#[doc(hidden)]
pub fn key(&self) -> &Key { &self.key }
#[doc(hidden)]
pub fn longest_filter(&self) -> bool {
self.kind() == ArgKind::Opt || self.long.is_some() || self.short.is_none()
self.kind() == ArgKind::Opt || self.key.has_long() || !self.key.has_short()
}
// Used for positionals when printing

View file

@ -4,6 +4,7 @@ use bstr::{BStr, BString};
// Internal
use crate::build::arg::{Arg, Key};
use crate::util::FnvHash;
use crate::INTERNAL_ERROR_MSG;
type Id = u64;
@ -58,7 +59,7 @@ impl PartialEq<str> for MapKeyKind {
fn eq(&self, rhs: &str) -> bool {
match self {
MapKeyKind::Long(ref l) => l == rhs,
MapKeyKind::Id(i) => i == rhs.fnv_hash(),
MapKeyKind::Id(i) => *i == rhs.fnv_hash(),
_ => false,
}
}
@ -107,14 +108,14 @@ impl<'b> MKeyMap<'b> {
self.keys
.iter()
.find(|x| x.key == key)
.map(|mk| self.args.get(mk.index))
.map(|mk| self.args.get(mk.index).expect(INTERNAL_ERROR_MSG))
}
pub fn remove_key<K: Into<MapKeyKind>>(&mut self, k: K) {
let key = k.into();
let mut idx = None;
for k in self.keys.iter() {
if &k.key == key {
if k.key == key {
idx = Some(k.index);
break;
}
@ -128,7 +129,7 @@ impl<'b> MKeyMap<'b> {
let key = k.into();
let mut idx = None;
for k in self.keys.iter() {
if &k.key == key {
if k.key == key {
idx = Some(k.index);
break;
}
@ -136,7 +137,7 @@ impl<'b> MKeyMap<'b> {
if let Some(idx) = idx {
let arg = self.args.swap_remove(idx);
for key in get_keys(&arg) {
self.remove_key(&key);
self.remove_key(key);
}
return Some(arg);
}
@ -149,7 +150,7 @@ impl<'b> MKeyMap<'b> {
for k in get_keys(arg) {
self.keys.push(MapKey { key: k, index: i });
}
if arg.key() == Key::Unset {
if arg.key().kind == Key::Unset {
arg.index(counter);
counter += 1;
}
@ -157,7 +158,7 @@ impl<'b> MKeyMap<'b> {
}
pub fn find_by_name(&self, name: &str) -> Option<&Arg<'b>> {
let key: MapKeyKind = name.key().into();
let key: MapKeyKind = name.fnv_hash().into();
self.keys
.iter()
.find(|x| x.key == key)
@ -165,7 +166,7 @@ impl<'b> MKeyMap<'b> {
}
pub fn remove_by_name(&mut self, name: &str) -> Option<Arg<'b>> {
let key: MapKeyKind = name.key().into();
let key: MapKeyKind = name.fnv_hash().into();
let mut index = None;
for k in self.keys.iter() {
if k.key == key {
@ -186,7 +187,7 @@ impl<'b> MKeyMap<'b> {
fn get_keys(arg: &Arg) -> Vec<MapKeyKind> {
let mut keys = vec![arg.id.into()];
if let Some(index) = arg.index {
if let Some(index) = arg.get_index() {
keys.push(index.into());
return keys;
}

View file

@ -5,7 +5,7 @@ use std::iter::Peekable;
use std::mem;
// Third Party
use bstr::{BStr, BString};
use bstr::{BStr, BString, ByteSlice, B};
// Internal
use crate::build::app::Propagation;
@ -126,7 +126,7 @@ where
.count();
assert!(
highest_idx == num_p as u64,
highest_idx == num_p,
"Found positional argument whose index is {} but there \
are only {} positional arguments defined",
highest_idx,
@ -707,7 +707,7 @@ where
debugln!("Parser::possible_subcommand: arg={:?}", arg_os);
fn starts(h: &str, n: &BStr) -> bool {
let n_bytes = n.as_bytes();
let h_bytes = BStr::from(h).as_bytes();
let h_bytes = B(h);
h_bytes.starts_with(n_bytes)
}
@ -995,16 +995,17 @@ where
let mut val = None;
debug!("Parser::parse_long_arg: Does it contain '='...");
let arg = if full_arg.contains_byte(b'=') {
let (p0, p1) = full_arg.trim_left_matches(b'-').split_at_byte(b'=');
sdebugln!("Yes '{:?}'", p1);
val = Some(p1);
p0
let arg = if full_arg.contains_str(b"=") {
let p = full_arg.trim_start_with(|c| c == '-').split_str(b"=");
sdebugln!("Yes '{:?}'", p);
let arg = p.next().expect(INTERNAL_ERROR_MSG);
val = p.next();
arg
} else {
sdebugln!("No");
full_arg.trim_left_matches(b'-')
full_arg.trim_start_with(|c| c == '-')
};
if let Some(opt) = self.app.args.get(&MapKeyKind::Long(arg.into())) {
if let Some(opt) = self.app.args.find(arg) {
debugln!(
"Parser::parse_long_arg: Found valid opt or flag '{}'",
opt.to_string()
@ -1038,7 +1039,7 @@ where
full_arg: &BStr,
) -> ClapResult<ParseResult> {
debugln!("Parser::parse_short_arg: full_arg={:?}", full_arg);
let arg_os = full_arg.trim_left_matches(b'-');
let arg_os = full_arg.trim_start_with(|c| c == '-');
let arg = arg_os.to_string_lossy();
// If AllowLeadingHyphen is set, we want to ensure `-val` gets parsed as `-val` and not
@ -1138,7 +1139,7 @@ where
debug!("Parser::parse_opt; Checking for val...");
if let Some(fv) = val {
has_eq = fv.starts_with(&[b'=']) || had_eq;
let v = fv.trim_left_matches(b'=');
let v = fv.trim_start_with(|c| c == '=');
if !empty_vals && (v.is_empty() || (needs_eq && !has_eq)) {
sdebugln!("Found Empty - Error");
return Err(ClapError::empty_value(
@ -1203,11 +1204,11 @@ where
Ok(self.add_single_val_to_arg(arg, val, matcher)?)
} else {
let mut iret = ParseResult::ValuesDone;
for v in val.split(delim as u32 as u8) {
for v in val.split_str(B(delim)) {
iret = self.add_single_val_to_arg(arg, v, matcher)?;
}
// If there was a delimiter used, we're not looking for more values
if val.contains_byte(delim as u32 as u8)
if val.contains_str([delim as u32 as u8])
|| arg.is_set(ArgSettings::RequireDelimiter)
{
iret = ParseResult::ValuesDone;