From dd441f8f1cf578abbb1d6b61e9e3b113c6b0ab0e Mon Sep 17 00:00:00 2001 From: Kevin K Date: Tue, 3 Sep 2019 21:55:59 -0400 Subject: [PATCH] wip refactoring shorts and longs into an arg key --- Cargo.toml | 1 + src/build/arg/key.rs | 71 ++++++++-- src/build/arg/mod.rs | 128 ++++++------------ src/build/mod.rs | 2 +- src/lib.rs | 1 + src/mkeymap.rs | 315 +++++++++++++++++++------------------------ src/output/help.rs | 7 +- src/parse/parser.rs | 78 +++++------ v3_changes.md | 2 + 9 files changed, 280 insertions(+), 325 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 04dcde2d..e3862857 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ is-it-maintained-open-issues = { repository = "clap-rs/clap" } maintenance = {status = "actively-developed"} [dependencies] +bstr = "0.2.8" bitflags = "1.0" unicode-width = "0.1.4" textwrap = "0.11" diff --git a/src/build/arg/key.rs b/src/build/arg/key.rs index 02f7ad50..d46589d1 100644 --- a/src/build/arg/key.rs +++ b/src/build/arg/key.rs @@ -1,37 +1,88 @@ -struct SwitchData { +use crate::INTERNAL_ERR_MSG; + +#[derive(Default)] +struct SwitchData<'help> { longs: Vec>, short: Option, } -pub(crate) enum Key<'help> { +pub(crate) enum ArgKey<'help> { + Unset, Index(usize), Switch(SwitchData), } -impl<'help> Key { +impl Default for ArgKey<'help> { + fn default() -> Self { + ArgKey::Unset + } +} + +impl<'help> ArgKey { fn long(&mut self, l: &'help str) { + match *self { + ArgKey::Unset => *self = ArgKey::Switch(SwitchData::default()), + ArgKey::Index => panic!("You cannot add both an index and switch (short or long) to an Arg"), + _ => (), + } self.switch_mut() + .expect(INTERNAL_ERR_MSG) .longs .push(Alias::visible(l.trim_left_matches(|c| c == '-'))); } + fn longs(&mut self, longs: &[&'help str]) { + for l in longs { + self.long(l); + } + } fn hidden_long(&mut self, l: &'help str) { self.switch_mut() .longs .push(Alias::hidden(l.trim_left_matches(|c| c == '-'))); } - - fn switch_mut(&mut self) -> &mut SwitchData<'help> { - match *self { - Switch(s) => s, - _ => unreachable!(), + fn hidden_longs(&mut self, longs: &[&'help str]) { + for l in longs { + self.switch_mut() + .longs + .push(Alias::hidden(l.trim_left_matches(|c| c == '-'))); + } + } + fn has_index(&self) -> bool { + use ArgKey::*; + match *self { + Index(_) => true, + Switch(_) => false, + } + } + fn index(&self) -> Option<&usize>> { + match *self { + Index(i) => Some(i), + _ => None, + } + } + fn index_mut(&mut self) -> Option<&mut usize> { + match *self { + Index(i) => Some(i), + _ => None, } } - fn has_switch(&self) -> bool { - use Key::*; + use ArgKey::*; match *self { Index(_) => false, Switch(_) => true, } } + fn switch(&self) -> Option<&SwitchData<'help>> { + match *self { + Switch(s) => Some(s), + _ => None, + } + } + fn switch_mut(&mut self) -> Option<&mut SwitchData<'help>> { + match *self { + Switch(s) => Some(s), + _ => None, + } + } } diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index 5cdb04e4..8eafcb4a 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -18,6 +18,7 @@ use crate::util::VecMap; use yaml_rust; // Internal +use crate::build::arg::{ArgKey, SwitchData}; use crate::build::UsageParser; use crate::util::Key; #[cfg(any(target_os = "windows", target_arch = "wasm32"))] @@ -120,15 +121,13 @@ pub struct Arg<'help> { #[doc(hidden)] pub disp_ord: usize, #[doc(hidden)] - pub help_heading: Option<&'help str>, - #[doc(hidden)] pub global: bool, pub unified_ord: usize, #[doc(hidden)] pub val_names: Option>, // switch - pub key: Key<'help>, + pub key: ArgKey<'help>, } impl<'help> Arg<'help> { @@ -281,7 +280,7 @@ impl<'help> Arg<'help> { /// ``` /// [`short`]: ./struct.Arg.html#method.short pub fn short(mut self, s: char) -> Self { - self.short = Some(s); + self.key.short(s); self } @@ -325,10 +324,35 @@ impl<'help> Arg<'help> { self } - /// Allows adding a [`Arg`] alias, which function as "hidden" arguments that + /// Allows adding multiple [`Arg`] longs at once. In the help message each long will be + /// displayed normally, with all of it's "aliases" listed in parenthesis. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("test") + /// .longs(&["test", "something", "awesome", "cool"])) + /// .get_matches_from(vec![ + /// "prog", "--awesome" + /// ]); + /// assert!(m.is_present("test")); + /// ``` + /// [`Arg`]: ./struct.Arg.html + /// [`App::aliases`]: ./struct.Arg.html#method.aliases + pub fn longs(mut self, names: &[&'help str]) -> Self { + self.key.longs(names); + self + } + + /// Allows adding an [`Arg`] hidden [long], which function as "hidden" arguments that /// automatically dispatch as if this argument was used. This is more efficient, and easier /// than creating multiple hidden arguments as one only needs to check for the existence of - /// this command, and not all variants. + /// this command, and not all dummy variants. + /// + /// These hidden longs will not be displayed or mentioned in the help message as the name + /// implies. /// /// # Examples /// @@ -337,7 +361,7 @@ impl<'help> Arg<'help> { /// let m = App::new("prog") /// .arg(Arg::with_name("test") /// .long("test") - /// .alias("alias") + /// .hidden_long("alias") /// .takes_value(true)) /// .get_matches_from(vec![ /// "prog", "--alias", "cool" @@ -346,19 +370,13 @@ impl<'help> Arg<'help> { /// assert_eq!(m.value_of("test"), Some("cool")); /// ``` /// [`Arg`]: ./struct.Arg.html - pub fn alias>(mut self, name: S) -> Self { - if let Some(ref mut als) = self.aliases { - als.push((name.into(), false)); - } else { - self.aliases = Some(vec![(name.into(), false)]); - } + /// [long]: ./struct.Arg.html#method.long + pub fn hidden_long>(mut self, name: S) -> Self { + self.key.hidden_long(name); self } - /// Allows adding [`Arg`] aliases, which function as "hidden" arguments that - /// automatically dispatch as if this argument was used. This is more efficient, and easier - /// than creating multiple hidden subcommands as one only needs to check for the existence of - /// this command, and not all variants. + /// Allows adding [`Arg`] multiple [hidden longs] at once. /// /// # Examples /// @@ -367,7 +385,7 @@ impl<'help> Arg<'help> { /// let m = App::new("prog") /// .arg(Arg::with_name("test") /// .long("test") - /// .aliases(&["do-stuff", "do-tests", "tests"]) + /// .hidden_longs(&["do-stuff", "do-tests", "tests"]) /// .help("the file to add") /// .required(false)) /// .get_matches_from(vec![ @@ -376,73 +394,9 @@ impl<'help> Arg<'help> { /// assert!(m.is_present("test")); /// ``` /// [`Arg`]: ./struct.Arg.html - pub fn aliases(mut self, names: &[&'help str]) -> Self { - if let Some(ref mut als) = self.aliases { - for n in names { - als.push((n, false)); - } - } else { - self.aliases = Some(names.iter().map(|&x| (x, false)).collect()); - } - self - } - - /// Allows adding a [`Arg`] alias that functions exactly like those defined with - /// [`Arg::alias`], except that they are visible inside the help message. - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let m = App::new("prog") - /// .arg(Arg::with_name("test") - /// .visible_alias("something-awesome") - /// .long("test") - /// .takes_value(true)) - /// .get_matches_from(vec![ - /// "prog", "--something-awesome", "coffee" - /// ]); - /// assert!(m.is_present("test")); - /// assert_eq!(m.value_of("test"), Some("coffee")); - /// ``` - /// [`Arg`]: ./struct.Arg.html - /// [`App::alias`]: ./struct.Arg.html#method.alias - pub fn visible_alias>(mut self, name: S) -> Self { - if let Some(ref mut als) = self.aliases { - als.push((name.into(), true)); - } else { - self.aliases = Some(vec![(name.into(), true)]); - } - self - } - - /// Allows adding multiple [`Arg`] aliases that functions exactly like those defined - /// with [`Arg::aliases`], except that they are visible inside the help message. - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let m = App::new("prog") - /// .arg(Arg::with_name("test") - /// .long("test") - /// .visible_aliases(&["something", "awesome", "cool"])) - /// .get_matches_from(vec![ - /// "prog", "--awesome" - /// ]); - /// assert!(m.is_present("test")); - /// ``` - /// [`Arg`]: ./struct.Arg.html - /// [`App::aliases`]: ./struct.Arg.html#method.aliases - pub fn visible_aliases(mut self, names: &[&'help str]) -> Self { - if let Some(ref mut als) = self.aliases { - for n in names { - als.push((n, true)); - } - } else { - self.aliases = Some(names.iter().map(|n| (*n, true)).collect::>()); - } - self + /// [hidden longs]: ./struct.Arg.html#method.hidden_long + pub fn hidden_longs(mut self, names: &[&'help str]) -> Self { + self.key.hidden_longs(names): self } /// Sets the short help text of the argument that will be displayed to the user when they print @@ -1529,7 +1483,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 = ArgKey::Index(idx); self } @@ -4045,6 +3999,8 @@ impl<'help> Arg<'help> { #[doc(hidden)] pub fn has_switch(&self) -> bool { self.key.has_switch() } + pub fn switch(&self) -> &SwitchData { self.key.switch() } + #[doc(hidden)] pub fn longest_filter(&self) -> bool { self.kind() == ArgKind::Opt || self.long.is_some() || self.short.is_none() diff --git a/src/build/mod.rs b/src/build/mod.rs index 3d67ba6b..80cffa44 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -8,6 +8,6 @@ mod arg_group; mod usage_parser; pub use self::app::{App, AppFlags, AppSettings, Propagation}; -pub use self::arg::{Arg, ArgFlags, ArgSettings}; +pub use self::arg::{Arg, ArgFlags, ArgKey, ArgSettings}; pub use self::arg_group::ArgGroup; pub use self::usage_parser::UsageParser; diff --git a/src/lib.rs b/src/lib.rs index 92e23e61..90974e36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -540,6 +540,7 @@ extern crate ansi_term; extern crate atty; #[macro_use] extern crate bitflags; +extern crate bstr; #[cfg(feature = "derive")] #[cfg_attr(feature = "derive", allow(unused_imports))] #[cfg_attr(feature = "derive", macro_use)] diff --git a/src/mkeymap.rs b/src/mkeymap.rs index 2e7455c0..bebdc473 100644 --- a/src/mkeymap.rs +++ b/src/mkeymap.rs @@ -1,119 +1,121 @@ +// Third Party +use bstr::{BStr, BString}; + +// Internal use crate::build::Arg; -use std::ffi::{OsStr, OsString}; +use crate::util::Key; type Id = u64; +#[derive(Default, PartialEq, Debug, Clone)] +pub struct MKeyMap<'b> { + pub keys: Vec, + pub args: Vec>, +} + #[derive(PartialEq, Debug, Clone)] -pub struct Key { - pub key: KeyType, +pub struct MapKey { + pub key: MapKeyType, pub index: usize, } -#[derive(Default, PartialEq, Debug, Clone)] -pub struct MKeyMap<'b> { - pub keys: Vec, - pub args: Vec>, - built: bool, // mutation isn't possible after being built -} - #[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum KeyType { +pub enum MapKeyType { + Id(Id), Short(char), - Long(OsString), - Position(u64), + Long(BString), + Position(usize), } -impl KeyType { +impl MapKeyType { pub(crate) fn is_position(&self) -> bool { match *self { - KeyType::Position(_) => true, + MapKeyType::Position(_) => true, _ => false, } } } -impl PartialEq<&str> for KeyType { - fn eq(&self, rhs: &&str) -> bool { +impl PartialEq for MapKeyType { + fn eq(&self, rhs: &usize) -> bool { match self { - KeyType::Long(ref l) => l == OsStr::new(rhs), + MapKeyType::Position(i) => i == rhs, _ => false, } } } -impl PartialEq for KeyType { +impl PartialEq for MapKeyType { + fn eq(&self, rhs: &Id) -> bool { + match self { + MapKeyType::Id(i) => i == rhs, + _ => false, + } + } +} + +impl PartialEq for MapKeyType { + fn eq(&self, rhs: &str) -> bool { + match self { + MapKeyType::Long(ref l) => l == rhs, + MapKeyType::Id(i) => i == rhs.key(), + _ => false, + } + } +} + +impl PartialEq for MapKeyType { fn eq(&self, rhs: &char) -> bool { match self { - KeyType::Short(c) => c == rhs, + MapKeyType::Short(c) => c == rhs, _ => false, } } } +impl From for MapKeyType { + fn from(us: usize) -> Self { MapKeyType::Position(us) } +} + +impl From for MapKeyType { + fn from(c: char) -> Self { MapKeyType::Short(c) } +} + +impl From for MapKeyType { + fn from(i: Id) -> Self { MapKeyType::Id(i) } +} + impl<'b> MKeyMap<'b> { pub fn new() -> Self { MKeyMap::default() } - //TODO ::from(x), ::with_capacity(n) etc - //? set theory ops? - pub fn contains_long(&self, l: &str) -> bool { self.keys.iter().any(|x| x.key == l) } - - pub fn contains_short(&self, c: char) -> bool { self.keys.iter().any(|x| x.key == c) } - - pub fn insert(&mut self, key: KeyType, value: Arg<'b>) -> usize { - let index = self.push(value); - self.keys.push(Key { key, index }); - index - } + pub fn is_empty(&self) -> bool { self.args.is_empty() } pub fn push(&mut self, value: Arg<'b>) -> usize { - if self.built { - panic!("Cannot add Args to the map after the map is built"); - } - let index = self.args.len(); self.args.push(value); index } - //TODO ::push_many([x, y]) - pub fn insert_key(&mut self, key: KeyType, index: usize) { - if index >= self.args.len() { - panic!("Index out of bounds"); - } - - self.keys.push(Key { key, index }); - } - //TODO ::insert_keyset([Long, Key2]) - - // ! Arg mutation functionality - - pub fn get(&self, key: &KeyType) -> Option<&Arg<'b>> { - for k in &self.keys { - if &k.key == key { - return Some(&self.args[k.index]); - } - } - None - } - //TODO ::get_first([KeyA, KeyB]) - - pub fn get_mut(&mut self, key: &KeyType) -> Option<&mut Arg<'b>> { - for k in &self.keys { - if &k.key == key { - return self.args.get_mut(k.index); - } - } - None + pub fn contains>(&self, k: K) -> bool { + let key = k.into(); + self.keys.iter().any(|x| x.key == key) } - pub fn is_empty(&self) -> bool { self.keys.is_empty() && self.args.is_empty() } + pub fn find>(&self, k: K) -> Option<&Arg<'b>> { + let key = k.into(); + self.keys + .iter() + .find(|x| x.key == key) + .map(|mk| self.args.get(mk.index)) + } - pub fn remove_key(&mut self, key: &KeyType) { + pub fn remove_key>(&mut self, k: K) { + let key = k.into(); let mut idx = None; - for (i, k) in self.keys.iter().enumerate() { + for k in self.keys.iter() { if &k.key == key { - idx = Some(i); + idx = Some(k.index); break; } } @@ -121,65 +123,9 @@ impl<'b> MKeyMap<'b> { self.keys.swap_remove(idx); } } - //TODO ::remove_keys([KeyA, KeyB]) - pub fn insert_key_by_name(&mut self, key: KeyType, name: &str) { - let index = self.find_by_name(name); - - self.keys.push(Key { key, index }); - } - - pub fn _build(&mut self) { - self.built = true; - - for (i, arg) in self.args.iter_mut().enumerate() { - for k in _get_keys(arg) { - self.keys.push(Key { key: k, index: i }); - } - } - } - - pub fn make_entries_by_index(&mut self, index: usize) { - let short; - let positional; - let mut longs: Vec<_>; - - { - let arg = &self.args[index]; - short = arg.short.map(KeyType::Short); - positional = arg.index.map(KeyType::Position); - - longs = arg - .aliases - .clone() - .map(|v| { - v.iter() - .map(|(n, _)| KeyType::Long(OsString::from(n))) - .collect() - }) - .unwrap_or_default(); - longs.extend(arg.long.map(|l| KeyType::Long(OsString::from(l)))); - } - - if let Some(s) = short { - self.insert_key(s, index) - } - if let Some(p) = positional { - self.insert_key(p, index) - } - } - - pub fn find_by_name(&mut self, name: &str) -> usize { - self.args - .iter() - .position(|x| x.name == name) - .expect("No such name found") - } - - pub fn remove(&mut self, key: &KeyType) -> Option> { - if self.built { - panic!("Cannot remove args after being built"); - } + pub fn remove>(&mut self, k: K) -> Option> { + let key = k.into(); let mut idx = None; for k in self.keys.iter() { if &k.key == key { @@ -189,7 +135,7 @@ impl<'b> MKeyMap<'b> { } if let Some(idx) = idx { let arg = self.args.swap_remove(idx); - for key in _get_keys(&arg) { + for key in get_keys(&arg) { self.remove_key(&key); } return Some(arg); @@ -197,22 +143,40 @@ impl<'b> MKeyMap<'b> { None } - //TODO ::remove_many([KeyA, KeyB]) - //? probably shouldn't add a possibility for removal? - //? or remove by replacement by some dummy object, so the order is preserved - - pub fn remove_by_name(&mut self, _name: Id) -> Option> { - if self.built { - panic!("Cannot remove args after being built"); + pub fn _build(&mut self) { + let mut counter = 0; + for (i, arg) in self.args.iter_mut().enumerate() { + for k in get_keys(arg) { + self.keys.push(MapKey { key: k, index: i }); + } + if arg.arg_key() == ArgKey::Unset { + a.index(counter); + counter += 1; + } } + } + + pub fn find_by_name(&self, name: &str) -> Option<&Arg<'b>> { + let key: MapKeyType = name.key().into(); + self.keys + .iter() + .find(|x| x.key == key) + .map(|mk| self.args.get(mk.index)) + } + + pub fn remove_by_name(&mut self, name: &str) -> Option> { + let key: MapKeyType = name.key().into(); let mut index = None; - for (i, arg) in self.args.iter().enumerate() { - if arg.id == _name { - index = Some(i); + for k in self.keys.iter() { + if k.key == key { + index = Some(k.index); break; } } if let Some(i) = index { + for key in get_keys(&arg) { + self.remove_key(&key); + } Some(self.args.swap_remove(i)) } else { None @@ -220,43 +184,36 @@ impl<'b> MKeyMap<'b> { } } -fn _get_keys(arg: &Arg) -> Vec { +fn get_keys(arg: &Arg) -> Vec { + let mut keys = vec![arg.id.into()]; if let Some(index) = arg.index { - return vec![KeyType::Position(index)]; + keys.push(index.into()); + return keys; } - let mut keys = vec![]; - if let Some(c) = arg.short { - keys.push(KeyType::Short(c)); + let sd = arg.switch(); + if let Some(s) = sd.short() { + keys.push(s.into()); } - if let Some(ref aliases) = arg.aliases { - for long in aliases - .iter() - .map(|(a, _)| KeyType::Long(OsString::from(a))) - { - keys.push(long); - } + for l in sd.all_longs() { + keys.push(l.into()); } - if let Some(long) = arg.long { - keys.push(KeyType::Long(OsString::from(long))); - } - keys } #[cfg(test)] mod tests { - use self::KeyType::*; + use self::MapKeyType::*; use super::*; #[test] fn get_some_value() { let mut map: MKeyMap = MKeyMap::new(); - map.insert(Long(OsString::from("One")), Arg::with_name("Value1")); + map.insert(Long(BString::from("One")), Arg::with_name("Value1")); assert_eq!( - map.get(&Long(OsString::from("One"))), + map.get(&Long(BString::from("One"))), Some(&Arg::with_name("Value1")) ); } @@ -265,10 +222,10 @@ mod tests { fn get_none_value() { let mut map: MKeyMap = MKeyMap::new(); - map.insert(Long(OsString::from("One")), Arg::with_name("Value1")); - map.get(&Long(OsString::from("Two"))); + map.insert(Long(BString::from("One")), Arg::with_name("Value1")); + map.get(&Long(BString::from("Two"))); - assert_eq!(map.get(&Long(OsString::from("Two"))), None); + assert_eq!(map.get(&Long(BString::from("Two"))), None); } // #[test] @@ -283,10 +240,10 @@ mod tests { fn insert_duplicate_key() { let mut map: MKeyMap = MKeyMap::new(); - map.insert(Long(OsString::from("One")), Arg::with_name("Value1")); + map.insert(Long(BString::from("One")), Arg::with_name("Value1")); assert_eq!( - map.insert(Long(OsString::from("One")), Arg::with_name("Value2")), + map.insert(Long(BString::from("One")), Arg::with_name("Value2")), 1 ); } @@ -296,16 +253,16 @@ mod tests { fn insert_duplicate_value() { let mut map: MKeyMap = MKeyMap::new(); - map.insert(Long(OsString::from("One")), Arg::with_name("Value1")); + map.insert(Long(BString::from("One")), Arg::with_name("Value1")); let orig_len = map.args.len(); - map.insert(Long(OsString::from("Two")), Arg::with_name("Value1")); + map.insert(Long(BString::from("Two")), Arg::with_name("Value1")); - assert_eq!(map.args.len(), orig_len + 1/* , "Len changed" */); + assert_eq!(map.args.len(), orig_len + 1 /* , "Len changed" */); // assert_eq!( - // map.get(&Long(OsString::from("One"))), - // map.get(&Long(OsString::from("Two"))) + // map.get(&Long(BString::from("One"))), + // map.get(&Long(BString::from("Two"))) // ); } @@ -321,13 +278,13 @@ mod tests { #[test] fn insert_multiple_keys() { let mut map: MKeyMap = MKeyMap::new(); - let index = map.insert(Long(OsString::from("One")), Arg::with_name("Value1")); + let index = map.insert(Long(BString::from("One")), Arg::with_name("Value1")); - map.insert_key(Long(OsString::from("Two")), index); + map.insert_key(Long(BString::from("Two")), index); assert_eq!( - map.get(&Long(OsString::from("One"))), - map.get(&Long(OsString::from("Two"))) + map.get(&Long(BString::from("One"))), + map.get(&Long(BString::from("Two"))) ); assert_eq!(map.args.len(), 1); } @@ -335,13 +292,13 @@ mod tests { // #[test] // fn insert_by_name() { // let mut map: MKeyMap = MKeyMap::new(); - // let index = map.insert(Long(OsString::from("One")), Arg::with_name("Value1")); + // let index = map.insert(Long(BString::from("One")), Arg::with_name("Value1")); - // map.insert_key_by_name(Long(OsString::from("Two")), "Value1"); + // map.insert_key_by_name(Long(BString::from("Two")), "Value1"); // assert_eq!( - // map.get(Long(OsString::from("One"))), - // map.get(Long(OsString::from("Two"))) + // map.get(Long(BString::from("One"))), + // map.get(Long(BString::from("Two"))) // ); // assert_eq!(map.values.len(), 1); // } @@ -350,10 +307,10 @@ mod tests { fn get_mutable() { let mut map: MKeyMap = MKeyMap::new(); - map.insert(Long(OsString::from("One")), Arg::with_name("Value1")); + map.insert(Long(BString::from("One")), Arg::with_name("Value1")); assert_eq!( - map.get_mut(&Long(OsString::from("One"))), + map.get_mut(&Long(BString::from("One"))), Some(&mut Arg::with_name("Value1")) ); } @@ -361,10 +318,10 @@ mod tests { #[test] fn remove_key() { let mut map: MKeyMap = MKeyMap::new(); - let index = map.insert(Long(OsString::from("One")), Arg::with_name("Value1")); + let index = map.insert(Long(BString::from("One")), Arg::with_name("Value1")); - map.insert_key(Long(OsString::from("Two")), index); - map.remove_key(&Long(OsString::from("One"))); + map.insert_key(Long(BString::from("Two")), index); + map.remove_key(&Long(BString::from("One"))); assert_eq!(map.keys.len(), 1); assert_eq!(map.args.len(), 1); diff --git a/src/output/help.rs b/src/output/help.rs index 29a655b6..4d4314a2 100644 --- a/src/output/help.rs +++ b/src/output/help.rs @@ -48,7 +48,12 @@ pub struct Help<'b, 'c, 'd, 'w> { // Public Functions impl<'b, 'c, 'd, 'w> Help<'b, 'c, 'd, 'w> { /// Create a new `Help` instance. - pub fn new(w: &'w mut dyn Write, parser: &'d Parser<'b, 'c>, use_long: bool, stderr: bool) -> Self { + pub fn new( + w: &'w mut dyn Write, + parser: &'d Parser<'b, 'c>, + use_long: bool, + stderr: bool, + ) -> Self { debugln!("Help::new;"); let term_w = match parser.app.term_w { Some(0) => usize::MAX, diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 64072b32..b5a83f02 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -1,14 +1,11 @@ // Std use std::cell::Cell; -use std::ffi::{OsStr, OsString}; use std::io::{self, BufWriter, Write}; use std::iter::Peekable; use std::mem; -#[cfg(all( - feature = "debug", - not(any(target_os = "windows", target_arch = "wasm32")) -))] -use std::os::unix::ffi::OsStrExt; + +// Third Party +use bstr::{BStr, BString}; // Internal use crate::build::app::Propagation; @@ -23,9 +20,7 @@ use crate::parse::errors::Result as ClapResult; use crate::parse::features::suggestions; use crate::parse::Validator; use crate::parse::{ArgMatcher, SubCommand}; -use crate::util::{self, ChildGraph, Key, OsStrExt2, EMPTY_HASH}; -#[cfg(all(feature = "debug", any(target_os = "windows", target_arch = "wasm32")))] -use crate::util::OsStrExt3; +use crate::util::{self, ChildGraph, Key, EMPTY_HASH}; use crate::INTERNAL_ERROR_MSG; use crate::INVALID_UTF8; @@ -151,16 +146,12 @@ where // We can't pass the closure (it.next()) to the macro directly because each call to // find() (iterator, not macro) gets called repeatedly. - let last = self - .app - .args - .get(&KeyType::Position(highest_idx)) - .expect(INTERNAL_ERROR_MSG); + let last = self.app.args.find(highest_idx).expect(INTERNAL_ERROR_MSG); let second_to_last = self .app .args - .get(&KeyType::Position(highest_idx - 1)) + .find(highest_idx - 1) .expect(INTERNAL_ERROR_MSG); // Either the final positional is required @@ -364,7 +355,7 @@ where 'b: 'c, { // The actual parsing function - #[allow(clippy::cyclomatic_complexity)] + #[allow(clippy::cognitive_complexity)] pub fn get_matches_with( &mut self, matcher: &mut ArgMatcher, @@ -372,7 +363,7 @@ where ) -> ClapResult<()> where I: Iterator, - T: Into + Clone, + T: Into + Clone, { debugln!("Parser::get_matches_with;"); // Verify all positional assertions pass @@ -437,9 +428,7 @@ where needs_val_of ); match needs_val_of { - ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => { - continue - } + ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => continue, _ => (), } } else if arg_os.starts_with(b"-") && arg_os.len() != 1 { @@ -465,9 +454,7 @@ where )); } } - ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => { - continue - } + ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => continue, _ => (), } } @@ -716,16 +703,11 @@ where } // Checks if the arg matches a subcommand name, or any of it's aliases (if defined) - fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) { + fn possible_subcommand(&self, arg_os: &BStr) -> (bool, Option<&str>) { debugln!("Parser::possible_subcommand: arg={:?}", arg_os); - fn starts(h: &str, n: &OsStr) -> bool { - #[cfg(target_os = "windows")] - use crate::util::OsStrExt3; - #[cfg(not(target_os = "windows"))] - use std::os::unix::ffi::OsStrExt; - + fn starts(h: &str, n: &BStr) -> bool { let n_bytes = n.as_bytes(); - let h_bytes = OsStr::new(h).as_bytes(); + let h_bytes = BStr::from(h).as_bytes(); h_bytes.starts_with(n_bytes) } @@ -752,10 +734,10 @@ where fn parse_help_subcommand(&self, it: &mut I) -> ClapResult where I: Iterator, - T: Into, + T: Into, { debugln!("Parser::parse_help_subcommand;"); - let cmds: Vec = it.map(Into::into).collect(); + let cmds: Vec = it.map(Into::into).collect(); let mut help_help = false; let mut bin_name = self.app.bin_name.as_ref().unwrap_or(&self.app.name).clone(); let mut sc = { @@ -813,7 +795,7 @@ where // allow wrong self convention due to self.valid_neg_num = true and it's a private method #[allow(clippy::wrong_self_convention)] - fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult) -> bool { + fn is_new_arg(&mut self, arg_os: &BStr, needs_val_of: ParseResult) -> bool { debugln!("Parser::is_new_arg:{:?}:{:?}", arg_os, needs_val_of); let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) { true @@ -874,7 +856,7 @@ where ) -> ClapResult<()> where I: Iterator, - T: Into + Clone, + T: Into + Clone, { use std::fmt::Write; debugln!("Parser::parse_subcommand;"); @@ -933,7 +915,7 @@ where // Retrieves the names of all args the user has supplied thus far, except required ones // because those will be listed in self.required - fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> { + fn check_for_help_and_version_str(&self, arg: &BStr) -> ClapResult<()> { debugln!("Parser::check_for_help_and_version_str;"); debug!( "Parser::check_for_help_and_version_str: Checking if --{} is help or version...", @@ -964,7 +946,7 @@ where // Needs to use app.settings.is_set instead of just is_set() because is_set() checks // both global and local settings, we only want to check local if let Some(help) = self.app.find(util::HELP_HASH) { - if let Some(h) = help.short { + if let Some(h) = help.switch().short() { if arg == h && !self.app.settings.is_set(AS::NoAutoHelp) { sdebugln!("Help"); return Err(self.help_err(false)); @@ -972,7 +954,7 @@ where } } if let Some(version) = self.app.find(util::VERSION_HASH) { - if let Some(v) = version.short { + if let Some(v) = version.switch().short() { if arg == v && !self.app.settings.is_set(AS::NoAutoVersion) { sdebugln!("Version"); return Err(self.version_err(false)); @@ -1003,7 +985,7 @@ where fn parse_long_arg( &mut self, matcher: &mut ArgMatcher, - full_arg: &OsStr, + full_arg: &BStr, ) -> ClapResult { // maybe here lifetime should be 'a debugln!("Parser::parse_long_arg;"); @@ -1053,7 +1035,7 @@ where fn parse_short_arg( &mut self, matcher: &mut ArgMatcher, - full_arg: &OsStr, + full_arg: &BStr, ) -> ClapResult { debugln!("Parser::parse_short_arg: full_arg={:?}", full_arg); let arg_os = full_arg.trim_left_matches(b'-'); @@ -1140,7 +1122,7 @@ where fn parse_opt( &self, - val: Option<&OsStr>, + val: Option<&BStr>, opt: &Arg<'b>, had_eq: bool, matcher: &mut ArgMatcher, @@ -1206,7 +1188,7 @@ where fn add_val_to_arg( &self, arg: &Arg<'b>, - val: &OsStr, + val: &BStr, matcher: &mut ArgMatcher, ) -> ClapResult { debugln!("Parser::add_val_to_arg; arg={}, val={:?}", arg.name, val); @@ -1243,7 +1225,7 @@ where fn add_single_val_to_arg( &self, arg: &Arg<'b>, - v: &OsStr, + v: &BStr, matcher: &mut ArgMatcher, ) -> ClapResult { debugln!("Parser::add_single_val_to_arg;"); @@ -1377,7 +1359,7 @@ where "Parser::add_defaults:iter:{}: has no user defined vals", $a.name ); - $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + $_self.add_val_to_arg($a, BStr::from(val), $m)?; } else if $m.get($a.id).is_some() { debugln!( "Parser::add_defaults:iter:{}: has user defined vals", @@ -1386,7 +1368,7 @@ where } else { debugln!("Parser::add_defaults:iter:{}: wasn't used", $a.name); - $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + $_self.add_val_to_arg($a, BStr::from(val), $m)?; } } else { debugln!( @@ -1411,7 +1393,7 @@ where false }; if add { - $_self.add_val_to_arg($a, OsStr::new(default), $m)?; + $_self.add_val_to_arg($a, BStr::from(default), $m)?; done = true; break; } @@ -1443,7 +1425,7 @@ where for a in self.app.args.args.iter() { if let Some(ref val) = a.env { if let Some(ref val) = val.1 { - self.add_val_to_arg(a, OsStr::new(val), matcher)?; + self.add_val_to_arg(a, BStr::from(val), matcher)?; } } } @@ -1480,7 +1462,7 @@ where // Add the arg to the matches to build a proper usage string if let Some(ref name) = suffix.1 { - if let Some(opt) = self.app.args.get(&KeyType::Long(OsString::from(name))) { + if let Some(opt) = self.app.args.get(&KeyType::Long(BString::from(name))) { for g in groups_for_arg!(self.app, opt.id) { matcher.inc_occurrence_of(g); } diff --git a/v3_changes.md b/v3_changes.md index cfb39e90..abedb87a 100644 --- a/v3_changes.md +++ b/v3_changes.md @@ -14,6 +14,8 @@ * Instead of adding arg with long `--help` or `--version` you can use `App::mut_arg` to override things * Caution, must fully override * No longer forces auto-handle of help/ver however if still desired `AppSettings::NoAuto{Help,Version}` +* `Arg::alias` -> `Arg::hidden_long` +* `Arg::visible_alias` -> `Arg::long` # How to Upgrade