From b59850a6ef86f8c7070a6de60cc4e3e6e626241e Mon Sep 17 00:00:00 2001 From: Kevin K Date: Wed, 4 Sep 2019 21:46:14 -0400 Subject: [PATCH] wip refactoring shorts and longs into an arg key --- src/build/arg/alias.rs | 15 +++++++++---- src/build/arg/key.rs | 48 ++++++++++++++++++++++++++---------------- src/build/arg/mod.rs | 10 ++++----- src/mkeymap.rs | 19 +++++++++-------- src/parse/parser.rs | 29 +++++++++++++------------ 5 files changed, 71 insertions(+), 50 deletions(-) diff --git a/src/build/arg/alias.rs b/src/build/arg/alias.rs index 65b74579..7227f2a3 100644 --- a/src/build/arg/alias.rs +++ b/src/build/arg/alias.rs @@ -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>(n: T) -> Self { + Alias { + name: B(n), + vis: true, + } + } + pub fn hidden(n: &'help str) -> Self { Alias { name: n, vis: false, diff --git a/src/build/arg/key.rs b/src/build/arg/key.rs index 70948a7e..f519ceb5 100644 --- a/src/build/arg/key.rs +++ b/src/build/arg/key.rs @@ -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>, - short: Option, + l: Vec>, + s: Option, +} + +impl<'help> SwitchData<'help> { + pub fn short(&self) -> Option { self.s } + pub fn all_longs(&self) -> impl Iterator { 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, diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index c6f847b9..d58057d5 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -78,10 +78,6 @@ pub struct Arg<'help> { #[doc(hidden)] pub groups: Option>, - // position - #[doc(hidden)] - pub index: Option, - // validation #[doc(hidden)] pub r_ifs: Option>, @@ -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 diff --git a/src/mkeymap.rs b/src/mkeymap.rs index a24ec445..9bd3e281 100644 --- a/src/mkeymap.rs +++ b/src/mkeymap.rs @@ -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 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>(&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> { - 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 { 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; } diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 217afbde..ce243a2d 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -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 { 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;