mirror of
https://github.com/clap-rs/clap
synced 2024-11-10 06:44:16 +00:00
Arg-specific API for MKeyMap
This commit is contained in:
parent
a75b67838e
commit
87c88d6054
6 changed files with 127 additions and 36 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -26,3 +26,6 @@ Cargo.lock
|
|||
.vscode/*
|
||||
.idea/*
|
||||
clap-rs.iml
|
||||
|
||||
# Auxiliary files
|
||||
test-results.test
|
||||
|
|
|
@ -679,7 +679,7 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
// @TODO @perf @p4 @v3-beta: maybe extend_from_slice would be possible and perform better?
|
||||
// But that may also not let us do `&["-a 'some'", "-b 'other']` because of not Into<Arg>
|
||||
for arg in args.into_iter() {
|
||||
self.args.push(arg.into());
|
||||
self.args.make_entries(arg.into());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -988,19 +988,8 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
where
|
||||
F: FnOnce(Arg<'a, 'b>) -> Arg<'a, 'b>,
|
||||
{
|
||||
// let i = self
|
||||
// .args
|
||||
// .values()
|
||||
// .enumerate()
|
||||
// .filter_map(|(i, a)| if a.name == arg { Some(i) } else { None })
|
||||
// .next();
|
||||
let a = if let Some(x) = self.args.remove_by_name(arg) {
|
||||
f(x)
|
||||
} else {
|
||||
let mut x = Arg::with_name(arg);
|
||||
f(x)
|
||||
};
|
||||
self.args.push(a);
|
||||
self.args.mut_arg(arg, f);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -1542,7 +1531,7 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
|
||||
// we have to set short manually because we're dealing with char's
|
||||
arg.short = self.help_short;
|
||||
self.args.push(arg);
|
||||
self.args.make_entries(arg);
|
||||
} else {
|
||||
self.settings.unset(AppSettings::NeedsLongHelp);
|
||||
}
|
||||
|
@ -1557,7 +1546,7 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
.help(self.version_message.unwrap_or("Prints version information"));
|
||||
// we have to set short manually because we're dealing with char's
|
||||
arg.short = self.version_short;
|
||||
self.args.push(arg);
|
||||
self.args.make_entries(arg);
|
||||
} else {
|
||||
self.settings.unset(AppSettings::NeedsLongVersion);
|
||||
}
|
||||
|
@ -2030,7 +2019,7 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
note = "Use `App::arg(Arg::from(&str)` instead. Will be removed in v3.0-beta"
|
||||
)]
|
||||
pub fn arg_from_usage(mut self, usage: &'a str) -> Self {
|
||||
self.args.push(Arg::from(usage));
|
||||
self.args.make_entries(Arg::from(usage));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -2045,7 +2034,7 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
if l.is_empty() {
|
||||
continue;
|
||||
}
|
||||
self.args.push(Arg::from(l));
|
||||
self.args.make_entries(Arg::from(l));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Std
|
||||
use std::io::Write;
|
||||
use std::ffi::OsStr;
|
||||
use std::io::Write;
|
||||
|
||||
// Internal
|
||||
use build::{App, Arg};
|
||||
|
@ -182,7 +182,9 @@ complete -F _{name} -o bashdefault -o default {name}
|
|||
shorts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s)),
|
||||
// Handles aliases too
|
||||
// error-handling?
|
||||
longs = longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l.to_str().unwrap())),
|
||||
longs = longs!(p).fold(String::new(), |acc, l| {
|
||||
format!("{} --{}", acc, l.to_str().unwrap())
|
||||
}),
|
||||
pos = positionals!(p).fold(String::new(), |acc, p| format!("{} {}", acc, p)),
|
||||
// Handles aliases too
|
||||
subcmds = sc_names!(p).fold(String::new(), |acc, s| format!("{} {}", acc, s))
|
||||
|
|
|
@ -466,7 +466,7 @@ macro_rules! crate_authors {
|
|||
struct CargoAuthors {
|
||||
__private_field: (),
|
||||
};
|
||||
|
||||
|
||||
impl Deref for CargoAuthors {
|
||||
type Target = str;
|
||||
|
||||
|
|
123
src/mkeymap.rs
123
src/mkeymap.rs
|
@ -4,6 +4,7 @@ use std::collections::hash_map::DefaultHasher;
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::OsString;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
use std::slice;
|
||||
// ! rustdoc
|
||||
|
||||
|
@ -18,7 +19,7 @@ pub struct MKeyMap<T> {
|
|||
pub enum KeyType {
|
||||
Short(char),
|
||||
Long(OsString),
|
||||
Position(usize),
|
||||
Position(u64),
|
||||
}
|
||||
|
||||
impl<T> MKeyMap<T>
|
||||
|
@ -77,16 +78,6 @@ where
|
|||
}
|
||||
//TODO ::insert_keyset([Long, Key2])
|
||||
|
||||
// pub fn insert_key_by_name(&mut self, key: KeyType, name: &str) {
|
||||
// let index = self
|
||||
// .value_index
|
||||
// .iter()
|
||||
// .position(|x| x.name == name)
|
||||
// .expect("No such name found");
|
||||
|
||||
// self.keys.insert(key, index);
|
||||
// }
|
||||
|
||||
// ! Arg mutation functionality
|
||||
|
||||
pub fn get(&self, key: KeyType) -> Option<&T> {
|
||||
|
@ -113,7 +104,7 @@ where
|
|||
//? probably shouldn't add a possibility for removal?
|
||||
//? or remove by replacement by some dummy object, so the order is preserved
|
||||
|
||||
pub fn remove_key(&mut self, key: KeyType) { unimplemented!() }
|
||||
pub fn remove_key(&mut self, key: KeyType) { self.keys.remove(&key); }
|
||||
//TODO ::remove_keys([KeyA, KeyB])
|
||||
|
||||
pub fn keys(&self) -> Keys<usize> {
|
||||
|
@ -142,6 +133,113 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> MKeyMap<Arg<'a, 'b>> {
|
||||
pub fn insert_key_by_name(&mut self, key: KeyType, name: &str) {
|
||||
let index = self.find_by_name(name);
|
||||
|
||||
self.keys.insert(key, index);
|
||||
}
|
||||
|
||||
pub fn make_entries(&mut self, arg: Arg<'a, 'b>) -> usize {
|
||||
let short = arg.short.map(|c| KeyType::Short(c));
|
||||
let positional = arg.index.map(|n| KeyType::Position(n));
|
||||
|
||||
let mut longs = arg
|
||||
.aliases
|
||||
.clone()
|
||||
.map(|v| {
|
||||
v.iter()
|
||||
.map(|(n, _)| KeyType::Long(OsString::from(n)))
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or(Vec::new());
|
||||
|
||||
longs.extend(arg.long.map(|l| KeyType::Long(OsString::from(l))));
|
||||
|
||||
let index = self.push(arg);
|
||||
short.map(|s| self.insert_key(s, index));
|
||||
positional.map(|p| self.insert_key(p, index));
|
||||
longs.into_iter().map(|l| self.insert_key(l, index)).count();
|
||||
|
||||
index
|
||||
}
|
||||
|
||||
pub fn make_entries_by_index(&mut self, index: usize) {
|
||||
let short;
|
||||
let positional;
|
||||
let mut longs;
|
||||
|
||||
{
|
||||
let arg = &self.value_index[index];
|
||||
short = arg.short.map(|c| KeyType::Short(c));
|
||||
positional = arg.index.map(|n| KeyType::Position(n));
|
||||
|
||||
longs = arg
|
||||
.aliases
|
||||
.clone()
|
||||
.map(|v| {
|
||||
v.iter()
|
||||
.map(|(n, _)| KeyType::Long(OsString::from(n)))
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or(Vec::new());
|
||||
longs.extend(arg.long.map(|l| KeyType::Long(OsString::from(l))));
|
||||
}
|
||||
|
||||
short.map(|s| self.insert_key(s, index));
|
||||
positional.map(|p| self.insert_key(p, index));
|
||||
longs.into_iter().map(|l| self.insert_key(l, index)).count();
|
||||
}
|
||||
|
||||
pub fn mut_arg<F>(&mut self, name: &str, f: F)
|
||||
where
|
||||
F: FnOnce(Arg<'a, 'b>) -> Arg<'a, 'b>,
|
||||
{
|
||||
let index = self.find_by_name(name);
|
||||
let new_arg = f(self.value_index[index].clone());
|
||||
|
||||
let value_key = self
|
||||
.values
|
||||
.iter()
|
||||
.filter(|(_, v)| v.contains(&index))
|
||||
.map(|(k, _)| k)
|
||||
.next()
|
||||
.map(|&x| x);
|
||||
value_key.map(|k| {
|
||||
self.values.entry(k).and_modify(|v| {
|
||||
v.remove(&index);
|
||||
})
|
||||
});
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
|
||||
new_arg.hash(&mut hasher);
|
||||
|
||||
let hash = hasher.finish();
|
||||
self.values
|
||||
.entry(hash)
|
||||
.and_modify(|x| {
|
||||
x.insert(index);
|
||||
})
|
||||
.or_insert({
|
||||
let mut set = HashSet::new();
|
||||
set.insert(index);
|
||||
set
|
||||
});
|
||||
|
||||
self.value_index.push(new_arg);
|
||||
self.value_index.swap_remove(index);
|
||||
self.make_entries_by_index(index);
|
||||
}
|
||||
|
||||
pub fn find_by_name(&mut self, name: &str) -> usize {
|
||||
self.value_index
|
||||
.iter()
|
||||
.position(|x| x.name == name)
|
||||
.expect("No such name found")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Keys<'a, V: 'a> {
|
||||
iter: hash_map::Keys<'a, KeyType, V>,
|
||||
|
@ -218,7 +316,6 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn get_none_value() {
|
||||
let mut map: MKeyMap<Arg> = MKeyMap::new();
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ where
|
|||
.count();
|
||||
|
||||
assert!(
|
||||
highest_idx == num_p,
|
||||
highest_idx == num_p as u64,
|
||||
"Found positional argument whose index is {} but there \
|
||||
are only {} positional arguments defined",
|
||||
highest_idx,
|
||||
|
@ -301,7 +301,7 @@ where
|
|||
let mut key: Vec<(KeyType, usize)> = Vec::new();
|
||||
for (i, a) in self.app.args.values().enumerate() {
|
||||
if let Some(ref index) = a.index {
|
||||
key.push((KeyType::Position((*index) as usize), i));
|
||||
key.push((KeyType::Position(*index), i));
|
||||
} else {
|
||||
if let Some(ref c) = a.short {
|
||||
key.push((KeyType::Short(*c), i));
|
||||
|
|
Loading…
Reference in a new issue