mirror of
https://github.com/clap-rs/clap
synced 2024-12-04 18:19:13 +00:00
wip refactoring shorts and longs into an arg key
This commit is contained in:
parent
4f48b3db63
commit
b59850a6ef
5 changed files with 71 additions and 50 deletions
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue