mirror of
https://github.com/clap-rs/clap
synced 2024-11-10 14:54:15 +00:00
Replace ArgStr
with os_str_bytes::RawOsStr
This commit is contained in:
parent
ee67039c5e
commit
dc65513966
7 changed files with 70 additions and 341 deletions
|
@ -64,7 +64,7 @@ clap_derive = { path = "./clap_derive", version = "=3.0.0-beta.4", optional = tr
|
|||
bitflags = "1.2"
|
||||
textwrap = { version = "0.14.0", default-features = false, features = [] }
|
||||
indexmap = "1.0"
|
||||
os_str_bytes = { version = "3.0", features = ["raw"] }
|
||||
os_str_bytes = "4.1"
|
||||
vec_map = "0.8"
|
||||
strsim = { version = "0.10", optional = true }
|
||||
yaml-rust = { version = "0.4.1", optional = true }
|
||||
|
|
|
@ -18,6 +18,7 @@ use std::{
|
|||
};
|
||||
|
||||
// Third Party
|
||||
use os_str_bytes::RawOsStr;
|
||||
#[cfg(feature = "yaml")]
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
|
@ -27,7 +28,7 @@ use crate::{
|
|||
mkeymap::MKeyMap,
|
||||
output::{fmt::Colorizer, Help, HelpWriter, Usage},
|
||||
parse::{ArgMatcher, ArgMatches, Input, Parser},
|
||||
util::{safe_exit, termcolor::ColorChoice, ArgStr, Id, Key, USAGE_CODE},
|
||||
util::{safe_exit, termcolor::ColorChoice, Id, Key, USAGE_CODE},
|
||||
Result as ClapResult, INTERNAL_ERROR_MSG,
|
||||
};
|
||||
|
||||
|
@ -2791,7 +2792,7 @@ impl<'help> App<'help> {
|
|||
}
|
||||
|
||||
/// Find a flag subcommand name by long flag or an alias
|
||||
pub(crate) fn find_long_subcmd(&self, long: &ArgStr) -> Option<&str> {
|
||||
pub(crate) fn find_long_subcmd(&self, long: &RawOsStr) -> Option<&str> {
|
||||
self.get_subcommands()
|
||||
.find(|sc| sc.long_flag_aliases_to(long))
|
||||
.map(|sc| sc.get_name())
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{build::Arg, util::Id, INTERNAL_ERROR_MSG};
|
||||
|
||||
use std::{ffi::OsString, iter::Iterator, ops::Index};
|
||||
use std::{ffi::OsStr, ffi::OsString, iter::Iterator, ops::Index};
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub(crate) struct Key {
|
||||
|
@ -49,8 +49,8 @@ impl PartialEq<&str> for KeyType {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq<OsString> for KeyType {
|
||||
fn eq(&self, rhs: &OsString) -> bool {
|
||||
impl PartialEq<OsStr> for KeyType {
|
||||
fn eq(&self, rhs: &OsStr) -> bool {
|
||||
match self {
|
||||
KeyType::Long(l) => l == rhs,
|
||||
_ => false,
|
||||
|
@ -86,7 +86,7 @@ impl<'help> MKeyMap<'help> {
|
|||
/// Find the arg have corresponding key in this map, we can search the key
|
||||
/// with u64(for positional argument), char(for short flag), &str and
|
||||
/// OsString (for long flag)
|
||||
pub(crate) fn get<K>(&self, key: &K) -> Option<&Arg<'help>>
|
||||
pub(crate) fn get<K: ?Sized>(&self, key: &K) -> Option<&Arg<'help>>
|
||||
where
|
||||
KeyType: PartialEq<K>,
|
||||
{
|
||||
|
|
|
@ -4,6 +4,9 @@ use std::{
|
|||
ffi::{OsStr, OsString},
|
||||
};
|
||||
|
||||
// Third Party
|
||||
use os_str_bytes::RawOsStr;
|
||||
|
||||
// Internal
|
||||
use crate::{
|
||||
build::AppSettings as AS,
|
||||
|
@ -16,7 +19,7 @@ use crate::{
|
|||
parse::features::suggestions,
|
||||
parse::{ArgMatcher, SubCommand},
|
||||
parse::{Validator, ValueType},
|
||||
util::{termcolor::ColorChoice, ArgStr, ChildGraph, Id},
|
||||
util::{termcolor::ColorChoice, ChildGraph, Id},
|
||||
INTERNAL_ERROR_MSG, INVALID_UTF8,
|
||||
};
|
||||
|
||||
|
@ -374,7 +377,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let arg_os = ArgStr::new(arg_os);
|
||||
let arg_os = RawOsStr::new(arg_os);
|
||||
debug!(
|
||||
"Parser::get_matches_with: Begin parsing '{:?}' ({:?})",
|
||||
arg_os,
|
||||
|
@ -423,7 +426,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
// pos_counter(which means current value cannot be a
|
||||
// positional argument with a value next to it), assume
|
||||
// current value matches the next arg.
|
||||
let n = ArgStr::new(n);
|
||||
let n = RawOsStr::new(n);
|
||||
self.is_new_arg(&n, p)
|
||||
|| self.possible_subcommand(&n, valid_arg_found).is_some()
|
||||
} else {
|
||||
|
@ -468,10 +471,10 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
}
|
||||
}
|
||||
|
||||
if arg_os.starts_with("--") {
|
||||
if let Some(long_arg) = arg_os.strip_prefix("--") {
|
||||
let parse_result = self.parse_long_arg(
|
||||
matcher,
|
||||
&arg_os,
|
||||
long_arg,
|
||||
&parse_state,
|
||||
&mut valid_arg_found,
|
||||
trailing_values,
|
||||
|
@ -537,7 +540,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
unreachable!()
|
||||
}
|
||||
}
|
||||
} else if arg_os.starts_with("-") {
|
||||
} else if let Some(short_arg) = arg_os.strip_prefix("-") {
|
||||
// Arg looks like a short flag, and not a possible number
|
||||
|
||||
// Try to parse short args like normal, if AllowLeadingHyphen or
|
||||
|
@ -545,7 +548,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
// an error, and instead return Ok(None)
|
||||
let parse_result = self.parse_short_arg(
|
||||
matcher,
|
||||
&arg_os,
|
||||
short_arg,
|
||||
&parse_state,
|
||||
pos_counter,
|
||||
&mut valid_arg_found,
|
||||
|
@ -626,7 +629,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
// get the option so we can check the settings
|
||||
let parse_result = self.add_val_to_arg(
|
||||
&self.app[id],
|
||||
arg_os,
|
||||
&arg_os,
|
||||
matcher,
|
||||
ValueType::CommandLine,
|
||||
true,
|
||||
|
@ -645,7 +648,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
if let Some(p) = self.app.args.get(&pos_counter) {
|
||||
if p.is_set(ArgSettings::Last) && !trailing_values {
|
||||
return Err(ClapError::unknown_argument(
|
||||
arg_os.to_string_lossy().to_string(),
|
||||
arg_os.to_str_lossy().into_owned(),
|
||||
None,
|
||||
Usage::new(self).create_usage_with_title(&[]),
|
||||
self.app.color(),
|
||||
|
@ -663,7 +666,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
let append = self.arg_have_val(matcher, p);
|
||||
self.add_val_to_arg(
|
||||
p,
|
||||
arg_os,
|
||||
&arg_os,
|
||||
matcher,
|
||||
ValueType::CommandLine,
|
||||
append,
|
||||
|
@ -768,7 +771,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
|
||||
fn match_arg_error(
|
||||
&self,
|
||||
arg_os: &ArgStr,
|
||||
arg_os: &RawOsStr,
|
||||
valid_arg_found: bool,
|
||||
trailing_values: bool,
|
||||
) -> ClapError {
|
||||
|
@ -777,14 +780,14 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
// If the arg matches a subcommand name, or any of its aliases (if defined)
|
||||
if self.possible_subcommand(arg_os, valid_arg_found).is_some() {
|
||||
return ClapError::unnecessary_double_dash(
|
||||
arg_os.to_string_lossy().to_string(),
|
||||
arg_os.to_str_lossy().into_owned(),
|
||||
Usage::new(self).create_usage_with_title(&[]),
|
||||
self.app.color(),
|
||||
);
|
||||
}
|
||||
}
|
||||
let candidates =
|
||||
suggestions::did_you_mean(&arg_os.to_string_lossy(), self.app.all_subcommand_names());
|
||||
suggestions::did_you_mean(&arg_os.to_str_lossy(), self.app.all_subcommand_names());
|
||||
// If the argument looks like a subcommand.
|
||||
if !candidates.is_empty() {
|
||||
let candidates: Vec<_> = candidates
|
||||
|
@ -792,7 +795,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
.map(|candidate| format!("'{}'", candidate))
|
||||
.collect();
|
||||
return ClapError::invalid_subcommand(
|
||||
arg_os.to_string_lossy().to_string(),
|
||||
arg_os.to_str_lossy().into_owned(),
|
||||
candidates.join(" or "),
|
||||
self.app
|
||||
.bin_name
|
||||
|
@ -806,7 +809,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
// If the argument must be a subcommand.
|
||||
if !self.app.has_args() || self.is_set(AS::InferSubcommands) && self.app.has_subcommands() {
|
||||
return ClapError::unrecognized_subcommand(
|
||||
arg_os.to_string_lossy().to_string(),
|
||||
arg_os.to_str_lossy().into_owned(),
|
||||
self.app
|
||||
.bin_name
|
||||
.as_ref()
|
||||
|
@ -816,7 +819,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
);
|
||||
}
|
||||
ClapError::unknown_argument(
|
||||
arg_os.to_string_lossy().to_string(),
|
||||
arg_os.to_str_lossy().into_owned(),
|
||||
None,
|
||||
Usage::new(self).create_usage_with_title(&[]),
|
||||
self.app.color(),
|
||||
|
@ -835,7 +838,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
}
|
||||
|
||||
// Checks if the arg matches a subcommand name, or any of its aliases (if defined)
|
||||
fn possible_subcommand(&self, arg_os: &ArgStr, valid_arg_found: bool) -> Option<&str> {
|
||||
fn possible_subcommand(&self, arg_os: &RawOsStr, valid_arg_found: bool) -> Option<&str> {
|
||||
debug!("Parser::possible_subcommand: arg={:?}", arg_os);
|
||||
|
||||
if !(self.is_set(AS::ArgsNegateSubcommands) && valid_arg_found) {
|
||||
|
@ -845,7 +848,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
let v = self
|
||||
.app
|
||||
.all_subcommand_names()
|
||||
.filter(|s| arg_os.is_prefix_of(s))
|
||||
.filter(|s| RawOsStr::from_str(s).starts_with_os(arg_os))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if v.len() == 1 {
|
||||
|
@ -863,7 +866,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
}
|
||||
|
||||
// Checks if the arg matches a long flag subcommand name, or any of its aliases (if defined)
|
||||
fn possible_long_flag_subcommand(&self, arg_os: &ArgStr) -> Option<&str> {
|
||||
fn possible_long_flag_subcommand(&self, arg_os: &RawOsStr) -> Option<&str> {
|
||||
debug!("Parser::possible_long_flag_subcommand: arg={:?}", arg_os);
|
||||
if self.is_set(AS::InferSubcommands) {
|
||||
let options = self
|
||||
|
@ -871,12 +874,12 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
.get_subcommands()
|
||||
.fold(Vec::new(), |mut options, sc| {
|
||||
if let Some(long) = sc.long_flag {
|
||||
if arg_os.is_prefix_of(long) {
|
||||
if RawOsStr::from_str(long).starts_with_os(arg_os) {
|
||||
options.push(long);
|
||||
}
|
||||
options.extend(
|
||||
sc.get_all_aliases()
|
||||
.filter(|alias| arg_os.is_prefix_of(alias)),
|
||||
.filter(|alias| RawOsStr::from_str(alias).starts_with_os(arg_os)),
|
||||
)
|
||||
}
|
||||
options
|
||||
|
@ -885,7 +888,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
return Some(options[0]);
|
||||
}
|
||||
|
||||
for sc in &options {
|
||||
for sc in options {
|
||||
if sc == arg_os {
|
||||
return Some(sc);
|
||||
}
|
||||
|
@ -930,7 +933,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
}
|
||||
} else {
|
||||
return Err(ClapError::unrecognized_subcommand(
|
||||
cmd.to_string_lossy().to_string(),
|
||||
cmd.to_string_lossy().into_owned(),
|
||||
self.app
|
||||
.bin_name
|
||||
.as_ref()
|
||||
|
@ -968,7 +971,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
Err(parser.help_err(self.app.is_set(AS::UseLongFormatForHelpSubcommand)))
|
||||
}
|
||||
|
||||
fn is_new_arg(&self, next: &ArgStr, current_positional: &Arg) -> bool {
|
||||
fn is_new_arg(&self, next: &RawOsStr, current_positional: &Arg) -> bool {
|
||||
debug!(
|
||||
"Parser::is_new_arg: {:?}:{:?}",
|
||||
next, current_positional.name
|
||||
|
@ -977,7 +980,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
if self.is_set(AS::AllowLeadingHyphen)
|
||||
|| self.app[¤t_positional.id].is_set(ArgSettings::AllowHyphenValues)
|
||||
|| (self.is_set(AS::AllowNegativeNumbers)
|
||||
&& next.to_string_lossy().parse::<f64>().is_ok())
|
||||
&& next.to_str_lossy().parse::<f64>().is_ok())
|
||||
{
|
||||
// If allow hyphen, this isn't a new arg.
|
||||
debug!("Parser::is_new_arg: Allow hyphen");
|
||||
|
@ -990,7 +993,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
debug!("Parser::is_new_arg: - found");
|
||||
// If this is a short flag, this is a new arg. But a singe '-' by
|
||||
// itself is a value and typically means "stdin" on unix systems.
|
||||
next.len() != 1
|
||||
next.raw_len() != 1
|
||||
} else {
|
||||
debug!("Parser::is_new_arg: value");
|
||||
// Nothing special, this is a value.
|
||||
|
@ -1092,7 +1095,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
|
||||
// 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: &ArgStr) -> Option<ParseResult> {
|
||||
fn check_for_help_and_version_str(&self, arg: &RawOsStr) -> Option<ParseResult> {
|
||||
debug!("Parser::check_for_help_and_version_str");
|
||||
debug!(
|
||||
"Parser::check_for_help_and_version_str: Checking if --{:?} is help or version...",
|
||||
|
@ -1172,7 +1175,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
fn parse_long_arg(
|
||||
&mut self,
|
||||
matcher: &mut ArgMatcher,
|
||||
full_arg: &ArgStr,
|
||||
long_arg: &RawOsStr,
|
||||
parse_state: &ParseState,
|
||||
valid_arg_found: &mut bool,
|
||||
trailing_values: bool,
|
||||
|
@ -1191,12 +1194,11 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
debug!("Parser::parse_long_arg: cur_idx:={}", self.cur_idx.get());
|
||||
|
||||
debug!("Parser::parse_long_arg: Does it contain '='...");
|
||||
let long_arg = full_arg.trim_start_n_matches(2, b'-');
|
||||
if long_arg.is_empty() {
|
||||
return ParseResult::NoArg;
|
||||
}
|
||||
let (arg, val) = if full_arg.contains_byte(b'=') {
|
||||
let (p0, p1) = long_arg.split_at_byte(b'=');
|
||||
let (arg, val) = if let Some(index) = long_arg.find("=") {
|
||||
let (p0, p1) = long_arg.split_at(index);
|
||||
debug!("Yes '{:?}'", p1);
|
||||
(p0, Some(p1))
|
||||
} else {
|
||||
|
@ -1204,20 +1206,20 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
(long_arg, None)
|
||||
};
|
||||
|
||||
let opt = if let Some(opt) = self.app.args.get(&arg.to_os_string()) {
|
||||
let opt = if let Some(opt) = self.app.args.get(&*arg.to_os_str()) {
|
||||
debug!(
|
||||
"Parser::parse_long_arg: Found valid opt or flag '{}'",
|
||||
opt.to_string()
|
||||
);
|
||||
Some(opt)
|
||||
} else if self.is_set(AS::InferLongArgs) {
|
||||
let arg_str = arg.to_string_lossy();
|
||||
let arg_str = arg.to_str_lossy();
|
||||
self.app.args.args().find(|a| {
|
||||
a.long
|
||||
.map_or(false, |long| long.starts_with(arg_str.as_ref()))
|
||||
.map_or(false, |long| long.starts_with(&*arg_str))
|
||||
|| a.aliases
|
||||
.iter()
|
||||
.any(|(alias, _)| alias.starts_with(arg_str.as_ref()))
|
||||
.any(|(alias, _)| alias.starts_with(&*arg_str))
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
@ -1231,7 +1233,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
"Parser::parse_long_arg: Found an opt with value '{:?}'",
|
||||
&val
|
||||
);
|
||||
self.parse_opt(&val, opt, matcher, trailing_values)
|
||||
self.parse_opt(val, opt, matcher, trailing_values)
|
||||
} else if let Some(rest) = val {
|
||||
debug!(
|
||||
"Parser::parse_long_arg: Got invalid literal `{:?}`",
|
||||
|
@ -1248,7 +1250,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
.collect();
|
||||
|
||||
ParseResult::UnneededAttachedValue {
|
||||
rest: rest.to_string_lossy().to_string(),
|
||||
rest: rest.to_str_lossy().into_owned(),
|
||||
used,
|
||||
arg: opt.to_string(),
|
||||
}
|
||||
|
@ -1264,7 +1266,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
ParseResult::MaybeHyphenValue
|
||||
} else {
|
||||
ParseResult::NoMatchingArg {
|
||||
arg: arg.to_string_lossy().to_string(),
|
||||
arg: arg.to_str_lossy().into_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1272,16 +1274,15 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
fn parse_short_arg(
|
||||
&mut self,
|
||||
matcher: &mut ArgMatcher,
|
||||
full_arg: &ArgStr,
|
||||
short_arg: &RawOsStr,
|
||||
parse_state: &ParseState,
|
||||
// change this to possible pos_arg when removing the usage of &mut Parser.
|
||||
pos_counter: usize,
|
||||
valid_arg_found: &mut bool,
|
||||
trailing_values: bool,
|
||||
) -> ParseResult {
|
||||
debug!("Parser::parse_short_arg: full_arg={:?}", full_arg);
|
||||
let arg_os = full_arg.trim_start_matches(b'-');
|
||||
let arg = arg_os.to_string_lossy();
|
||||
debug!("Parser::parse_short_arg: short_arg={:?}", short_arg);
|
||||
let arg = short_arg.to_str_lossy();
|
||||
|
||||
if (self.is_set(AS::AllowNegativeNumbers) && arg.parse::<f64>().is_ok())
|
||||
|| (self.is_set(AS::AllowLeadingHyphen)
|
||||
|
@ -1332,24 +1333,12 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
}
|
||||
|
||||
// Check for trailing concatenated value
|
||||
let i = arg_os.split(c).next().expect(INTERNAL_ERROR_MSG).len() + c.len_utf8();
|
||||
let val = short_arg.split_once(c).expect(INTERNAL_ERROR_MSG).1;
|
||||
debug!(
|
||||
"Parser::parse_short_arg:iter:{}: i={}, arg_os={:?}",
|
||||
c, i, arg_os
|
||||
"Parser::parse_short_arg:iter:{}: val={:?} (bytes), val={:?} (ascii), rest={:?}, arg_os={:?}",
|
||||
c, val, val.as_raw_bytes(), arg_os
|
||||
);
|
||||
let val = if i != arg_os.len() {
|
||||
// This is always a valid place to split, because the separator is UTF-8.
|
||||
let val = arg_os.split_at_unchecked(i).1;
|
||||
debug!(
|
||||
"Parser::parse_short_arg:iter:{}: val={:?} (bytes), val={:?} (ascii)",
|
||||
c,
|
||||
val.as_raw_bytes(),
|
||||
val
|
||||
);
|
||||
Some(val)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let val = Some(val).filter(|v| !v.is_empty());
|
||||
|
||||
// Default to "we're expecting a value later".
|
||||
//
|
||||
|
@ -1358,7 +1347,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
//
|
||||
// e.g. `-xvf`, when RequireEquals && x.min_vals == 0, we don't
|
||||
// consume the `vf`, even if it's provided as value.
|
||||
match self.parse_opt(&val, opt, matcher, trailing_values) {
|
||||
match self.parse_opt(val, opt, matcher, trailing_values) {
|
||||
ParseResult::AttachedValueNotConsumed => continue,
|
||||
x => return x,
|
||||
}
|
||||
|
@ -1393,7 +1382,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
|
||||
fn parse_opt(
|
||||
&self,
|
||||
attached_value: &Option<ArgStr>,
|
||||
attached_value: Option<&RawOsStr>,
|
||||
opt: &Arg<'help>,
|
||||
matcher: &mut ArgMatcher,
|
||||
trailing_values: bool,
|
||||
|
@ -1435,8 +1424,8 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
}
|
||||
}
|
||||
} else if let Some(fv) = attached_value {
|
||||
let v = fv.trim_start_n_matches(1, b'=');
|
||||
debug!("Found - {:?}, len: {}", v, v.len());
|
||||
let v = fv.strip_prefix("=").unwrap_or(fv);
|
||||
debug!("Found - {:?}, len: {}", v, v.raw_len());
|
||||
debug!(
|
||||
"Parser::parse_opt: {:?} contains '='...{:?}",
|
||||
fv,
|
||||
|
@ -1466,7 +1455,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
fn add_val_to_arg(
|
||||
&self,
|
||||
arg: &Arg<'help>,
|
||||
val: ArgStr,
|
||||
val: &RawOsStr,
|
||||
matcher: &mut ArgMatcher,
|
||||
ty: ValueType,
|
||||
append: bool,
|
||||
|
@ -1495,7 +1484,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
};
|
||||
self.add_multiple_vals_to_arg(
|
||||
arg,
|
||||
vals.into_iter().map(|x| x.into_os_string()),
|
||||
vals.into_iter().map(|x| x.to_os_str().into_owned()),
|
||||
matcher,
|
||||
ty,
|
||||
append,
|
||||
|
@ -1503,7 +1492,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
// If there was a delimiter used or we must use the delimiter to
|
||||
// separate the values or no more vals is needed, we're not
|
||||
// looking for more values.
|
||||
return if val.contains_char(delim)
|
||||
return if val.contains(delim)
|
||||
|| arg.is_set(ArgSettings::RequireDelimiter)
|
||||
|| !matcher.needs_more_vals(arg)
|
||||
{
|
||||
|
@ -1518,7 +1507,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
return ParseResult::ValuesDone;
|
||||
}
|
||||
}
|
||||
self.add_single_val_to_arg(arg, val.to_os_string(), matcher, ty, append);
|
||||
self.add_single_val_to_arg(arg, val.to_os_str().into_owned(), matcher, ty, append);
|
||||
if matcher.needs_more_vals(arg) {
|
||||
ParseResult::Opt(arg.id.clone())
|
||||
} else {
|
||||
|
@ -1686,7 +1675,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
if let Some(default) = default {
|
||||
self.add_val_to_arg(
|
||||
arg,
|
||||
ArgStr::new(default),
|
||||
&RawOsStr::new(default),
|
||||
matcher,
|
||||
ty,
|
||||
false,
|
||||
|
@ -1782,7 +1771,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
|
||||
debug!("Parser::add_env: Checking arg `{}`", a);
|
||||
if let Some((_, Some(ref val))) = a.env {
|
||||
let val = ArgStr::new(val);
|
||||
let val = RawOsStr::new(val);
|
||||
|
||||
if a.is_set(ArgSettings::TakesValue) {
|
||||
debug!(
|
||||
|
@ -1791,7 +1780,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
);
|
||||
self.add_val_to_arg(
|
||||
a,
|
||||
val,
|
||||
&val,
|
||||
matcher,
|
||||
ValueType::EnvVariable,
|
||||
false,
|
||||
|
@ -1813,7 +1802,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
}
|
||||
|
||||
debug!("Parser::add_env: Found a flag with value `{:?}`", val);
|
||||
let predicate = str_to_bool(val.to_string_lossy());
|
||||
let predicate = str_to_bool(val.to_str_lossy());
|
||||
debug!("Parser::add_env: Found boolean literal `{}`", predicate);
|
||||
if predicate {
|
||||
matcher.add_index_to(&a.id, self.cur_idx.get(), ValueType::EnvVariable);
|
||||
|
|
|
@ -122,7 +122,7 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
|
|||
.cloned()
|
||||
.collect();
|
||||
return Err(Error::invalid_value(
|
||||
val_str.to_string(),
|
||||
val_str.into_owned(),
|
||||
&arg.possible_vals,
|
||||
arg,
|
||||
Usage::new(self.p).create_usage_with_title(&used),
|
||||
|
@ -149,7 +149,7 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
|
|||
debug!("error");
|
||||
return Err(Error::value_validation(
|
||||
arg.to_string(),
|
||||
val.to_string_lossy().to_string(),
|
||||
val.to_string_lossy().into_owned(),
|
||||
e,
|
||||
self.p.app.color(),
|
||||
));
|
||||
|
|
|
@ -1,260 +0,0 @@
|
|||
use std::{
|
||||
borrow::Cow,
|
||||
ffi::{OsStr, OsString},
|
||||
fmt::{self, Debug},
|
||||
str,
|
||||
};
|
||||
|
||||
use os_str_bytes::{raw, OsStrBytes};
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub(crate) struct ArgStr<'a>(Cow<'a, [u8]>);
|
||||
|
||||
impl<'a> ArgStr<'a> {
|
||||
pub(crate) fn new(s: &'a OsStr) -> Self {
|
||||
Self(s.to_raw_bytes())
|
||||
}
|
||||
|
||||
pub(crate) fn starts_with(&self, s: &str) -> bool {
|
||||
self.0.starts_with(s.as_bytes())
|
||||
}
|
||||
|
||||
pub(crate) fn is_prefix_of(&self, s: &str) -> bool {
|
||||
raw::starts_with(s, &self.0)
|
||||
}
|
||||
|
||||
fn to_borrowed(&'a self) -> Self {
|
||||
Self(Cow::Borrowed(&self.0))
|
||||
}
|
||||
|
||||
pub(crate) fn contains_byte(&self, byte: u8) -> bool {
|
||||
assert!(byte.is_ascii());
|
||||
|
||||
self.0.contains(&byte)
|
||||
}
|
||||
|
||||
pub(crate) fn contains_char(&self, ch: char) -> bool {
|
||||
let mut bytes = [0; 4];
|
||||
let bytes = ch.encode_utf8(&mut bytes).as_bytes();
|
||||
for i in 0..self.0.len().saturating_sub(bytes.len() - 1) {
|
||||
if self.0[i..].starts_with(bytes) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn split_at_byte(&self, byte: u8) -> (ArgStr, ArgStr) {
|
||||
assert!(byte.is_ascii());
|
||||
|
||||
if let Some(i) = self.0.iter().position(|&x| x == byte) {
|
||||
self.split_at_unchecked(i)
|
||||
} else {
|
||||
(self.to_borrowed(), Self(Cow::Borrowed(&[])))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn trim_start_matches(&'a self, byte: u8) -> ArgStr {
|
||||
assert!(byte.is_ascii());
|
||||
|
||||
if let Some(i) = self.0.iter().position(|x| x != &byte) {
|
||||
Self(Cow::Borrowed(&self.0[i..]))
|
||||
} else {
|
||||
Self(Cow::Borrowed(&[]))
|
||||
}
|
||||
}
|
||||
|
||||
// Like `trim_start_matches`, but trims no more than `n` matches
|
||||
pub(crate) fn trim_start_n_matches(&self, n: usize, ch: u8) -> ArgStr {
|
||||
assert!(ch.is_ascii());
|
||||
|
||||
let i = self.0.iter().take(n).take_while(|c| **c == ch).count();
|
||||
|
||||
self.split_at_unchecked(i).1
|
||||
}
|
||||
|
||||
pub(crate) fn split_at_unchecked(&'a self, i: usize) -> (ArgStr, ArgStr) {
|
||||
(
|
||||
Self(Cow::Borrowed(&self.0[..i])),
|
||||
Self(Cow::Borrowed(&self.0[i..])),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn split(&self, ch: char) -> ArgSplit<'_> {
|
||||
let mut sep = [0; 4];
|
||||
ArgSplit {
|
||||
sep_len: ch.encode_utf8(&mut sep).as_bytes().len(),
|
||||
sep,
|
||||
val: &self.0,
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn as_raw_bytes(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn to_str(&self) -> Option<&str> {
|
||||
str::from_utf8(&self.0).ok()
|
||||
}
|
||||
|
||||
pub(crate) fn to_string_lossy(&self) -> Cow<'_, str> {
|
||||
String::from_utf8_lossy(&self.0)
|
||||
}
|
||||
|
||||
pub(crate) fn to_os_string(&self) -> OsString {
|
||||
self.to_borrowed().into_os_string()
|
||||
}
|
||||
|
||||
pub(crate) fn into_os_string(self) -> OsString {
|
||||
OsStr::from_raw_bytes(self.0).unwrap().into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Debug for ArgStr<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self.to_string_lossy())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<str> for ArgStr<'a> {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
self.0 == other.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<&str> for ArgStr<'a> {
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
self.eq(*other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<ArgStr<'a>> for str {
|
||||
fn eq(&self, other: &ArgStr<'a>) -> bool {
|
||||
other.eq(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<ArgStr<'a>> for &str {
|
||||
fn eq(&self, other: &ArgStr<'a>) -> bool {
|
||||
other.eq(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct ArgSplit<'a> {
|
||||
sep: [u8; 4],
|
||||
sep_len: usize,
|
||||
val: &'a [u8],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ArgSplit<'a> {
|
||||
type Item = ArgStr<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<ArgStr<'a>> {
|
||||
debug!("ArgSplit::next: self={:?}", self);
|
||||
|
||||
if self.pos == self.val.len() {
|
||||
return None;
|
||||
}
|
||||
let start = self.pos;
|
||||
while self.pos < self.val.len() {
|
||||
if self.val[self.pos..].starts_with(&self.sep[..self.sep_len]) {
|
||||
let arg = ArgStr(Cow::Borrowed(&self.val[start..self.pos]));
|
||||
self.pos += self.sep_len;
|
||||
return Some(arg);
|
||||
}
|
||||
self.pos += 1;
|
||||
}
|
||||
Some(ArgStr(Cow::Borrowed(&self.val[start..])))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn test_trim_start_matches() {
|
||||
let raw = OsString::from("hello? world");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_matches(b'-');
|
||||
assert_eq!(trimmed, a);
|
||||
|
||||
let raw = OsString::from("------------hello? world");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_matches(b'-');
|
||||
assert_eq!(trimmed, ArgStr::new(&OsString::from("hello? world")));
|
||||
|
||||
let raw = OsString::from("------------hel-lo? -world");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_matches(b'-');
|
||||
assert_eq!(trimmed, ArgStr::new(&OsString::from("hel-lo? -world")));
|
||||
|
||||
let raw = OsString::from("hel-lo? -world");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_matches(b'-');
|
||||
assert_eq!(trimmed, ArgStr::new(&OsString::from("hel-lo? -world")));
|
||||
|
||||
let raw = OsString::from("");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_matches(b'-');
|
||||
assert_eq!(trimmed, ArgStr::new(&OsString::from("")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn test_trim_start_n_matches() {
|
||||
let raw = OsString::from("hello? world");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_n_matches(2, b'-');
|
||||
assert_eq!(trimmed, a);
|
||||
|
||||
let raw = OsString::from("------------hello? world");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_n_matches(2, b'-');
|
||||
assert_eq!(trimmed, ArgStr::new(&OsString::from("----------hello? world")));
|
||||
|
||||
let raw = OsString::from("------------hello? world");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_n_matches(1000, b'-');
|
||||
assert_eq!(trimmed, ArgStr::new(&OsString::from("hello? world")));
|
||||
|
||||
let raw = OsString::from("------------hel-lo? -world");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_n_matches(2, b'-');
|
||||
assert_eq!(trimmed, ArgStr::new(&OsString::from("----------hel-lo? -world")));
|
||||
|
||||
let raw = OsString::from("-hel-lo? -world");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_n_matches(5, b'-');
|
||||
assert_eq!(trimmed, ArgStr::new(&OsString::from("hel-lo? -world")));
|
||||
|
||||
let raw = OsString::from("hel-lo? -world");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_n_matches(10, b'-');
|
||||
assert_eq!(trimmed, ArgStr::new(&OsString::from("hel-lo? -world")));
|
||||
|
||||
let raw = OsString::from("");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_n_matches(10, b'-');
|
||||
assert_eq!(trimmed, ArgStr::new(&OsString::from("")));
|
||||
|
||||
let raw = OsString::from("");
|
||||
let a = ArgStr::new(&raw);
|
||||
let trimmed = a.trim_start_n_matches(0, b'-');
|
||||
assert_eq!(trimmed, ArgStr::new(&OsString::from("")));
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
#![allow(clippy::single_component_path_imports)]
|
||||
|
||||
mod argstr;
|
||||
mod fnv;
|
||||
mod graph;
|
||||
mod id;
|
||||
|
@ -11,7 +10,7 @@ pub use self::fnv::Key;
|
|||
|
||||
#[cfg(feature = "env")]
|
||||
pub(crate) use self::str_to_bool::str_to_bool;
|
||||
pub(crate) use self::{argstr::ArgStr, graph::ChildGraph, id::Id};
|
||||
pub(crate) use self::{graph::ChildGraph, id::Id};
|
||||
pub(crate) use vec_map::VecMap;
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
|
|
Loading…
Reference in a new issue