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"
|
bitflags = "1.2"
|
||||||
textwrap = { version = "0.14.0", default-features = false, features = [] }
|
textwrap = { version = "0.14.0", default-features = false, features = [] }
|
||||||
indexmap = "1.0"
|
indexmap = "1.0"
|
||||||
os_str_bytes = { version = "3.0", features = ["raw"] }
|
os_str_bytes = "4.1"
|
||||||
vec_map = "0.8"
|
vec_map = "0.8"
|
||||||
strsim = { version = "0.10", optional = true }
|
strsim = { version = "0.10", optional = true }
|
||||||
yaml-rust = { version = "0.4.1", optional = true }
|
yaml-rust = { version = "0.4.1", optional = true }
|
||||||
|
|
|
@ -18,6 +18,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
// Third Party
|
// Third Party
|
||||||
|
use os_str_bytes::RawOsStr;
|
||||||
#[cfg(feature = "yaml")]
|
#[cfg(feature = "yaml")]
|
||||||
use yaml_rust::Yaml;
|
use yaml_rust::Yaml;
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ use crate::{
|
||||||
mkeymap::MKeyMap,
|
mkeymap::MKeyMap,
|
||||||
output::{fmt::Colorizer, Help, HelpWriter, Usage},
|
output::{fmt::Colorizer, Help, HelpWriter, Usage},
|
||||||
parse::{ArgMatcher, ArgMatches, Input, Parser},
|
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,
|
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
|
/// 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()
|
self.get_subcommands()
|
||||||
.find(|sc| sc.long_flag_aliases_to(long))
|
.find(|sc| sc.long_flag_aliases_to(long))
|
||||||
.map(|sc| sc.get_name())
|
.map(|sc| sc.get_name())
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{build::Arg, util::Id, INTERNAL_ERROR_MSG};
|
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)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
pub(crate) struct Key {
|
pub(crate) struct Key {
|
||||||
|
@ -49,8 +49,8 @@ impl PartialEq<&str> for KeyType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<OsString> for KeyType {
|
impl PartialEq<OsStr> for KeyType {
|
||||||
fn eq(&self, rhs: &OsString) -> bool {
|
fn eq(&self, rhs: &OsStr) -> bool {
|
||||||
match self {
|
match self {
|
||||||
KeyType::Long(l) => l == rhs,
|
KeyType::Long(l) => l == rhs,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -86,7 +86,7 @@ impl<'help> MKeyMap<'help> {
|
||||||
/// Find the arg have corresponding key in this map, we can search the key
|
/// 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
|
/// with u64(for positional argument), char(for short flag), &str and
|
||||||
/// OsString (for long flag)
|
/// 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
|
where
|
||||||
KeyType: PartialEq<K>,
|
KeyType: PartialEq<K>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,9 @@ use std::{
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Third Party
|
||||||
|
use os_str_bytes::RawOsStr;
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
use crate::{
|
use crate::{
|
||||||
build::AppSettings as AS,
|
build::AppSettings as AS,
|
||||||
|
@ -16,7 +19,7 @@ use crate::{
|
||||||
parse::features::suggestions,
|
parse::features::suggestions,
|
||||||
parse::{ArgMatcher, SubCommand},
|
parse::{ArgMatcher, SubCommand},
|
||||||
parse::{Validator, ValueType},
|
parse::{Validator, ValueType},
|
||||||
util::{termcolor::ColorChoice, ArgStr, ChildGraph, Id},
|
util::{termcolor::ColorChoice, ChildGraph, Id},
|
||||||
INTERNAL_ERROR_MSG, INVALID_UTF8,
|
INTERNAL_ERROR_MSG, INVALID_UTF8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -374,7 +377,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg_os = ArgStr::new(arg_os);
|
let arg_os = RawOsStr::new(arg_os);
|
||||||
debug!(
|
debug!(
|
||||||
"Parser::get_matches_with: Begin parsing '{:?}' ({:?})",
|
"Parser::get_matches_with: Begin parsing '{:?}' ({:?})",
|
||||||
arg_os,
|
arg_os,
|
||||||
|
@ -423,7 +426,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
// pos_counter(which means current value cannot be a
|
// pos_counter(which means current value cannot be a
|
||||||
// positional argument with a value next to it), assume
|
// positional argument with a value next to it), assume
|
||||||
// current value matches the next arg.
|
// current value matches the next arg.
|
||||||
let n = ArgStr::new(n);
|
let n = RawOsStr::new(n);
|
||||||
self.is_new_arg(&n, p)
|
self.is_new_arg(&n, p)
|
||||||
|| self.possible_subcommand(&n, valid_arg_found).is_some()
|
|| self.possible_subcommand(&n, valid_arg_found).is_some()
|
||||||
} else {
|
} 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(
|
let parse_result = self.parse_long_arg(
|
||||||
matcher,
|
matcher,
|
||||||
&arg_os,
|
long_arg,
|
||||||
&parse_state,
|
&parse_state,
|
||||||
&mut valid_arg_found,
|
&mut valid_arg_found,
|
||||||
trailing_values,
|
trailing_values,
|
||||||
|
@ -537,7 +540,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
unreachable!()
|
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
|
// Arg looks like a short flag, and not a possible number
|
||||||
|
|
||||||
// Try to parse short args like normal, if AllowLeadingHyphen or
|
// 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)
|
// an error, and instead return Ok(None)
|
||||||
let parse_result = self.parse_short_arg(
|
let parse_result = self.parse_short_arg(
|
||||||
matcher,
|
matcher,
|
||||||
&arg_os,
|
short_arg,
|
||||||
&parse_state,
|
&parse_state,
|
||||||
pos_counter,
|
pos_counter,
|
||||||
&mut valid_arg_found,
|
&mut valid_arg_found,
|
||||||
|
@ -626,7 +629,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
// get the option so we can check the settings
|
// get the option so we can check the settings
|
||||||
let parse_result = self.add_val_to_arg(
|
let parse_result = self.add_val_to_arg(
|
||||||
&self.app[id],
|
&self.app[id],
|
||||||
arg_os,
|
&arg_os,
|
||||||
matcher,
|
matcher,
|
||||||
ValueType::CommandLine,
|
ValueType::CommandLine,
|
||||||
true,
|
true,
|
||||||
|
@ -645,7 +648,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
if let Some(p) = self.app.args.get(&pos_counter) {
|
if let Some(p) = self.app.args.get(&pos_counter) {
|
||||||
if p.is_set(ArgSettings::Last) && !trailing_values {
|
if p.is_set(ArgSettings::Last) && !trailing_values {
|
||||||
return Err(ClapError::unknown_argument(
|
return Err(ClapError::unknown_argument(
|
||||||
arg_os.to_string_lossy().to_string(),
|
arg_os.to_str_lossy().into_owned(),
|
||||||
None,
|
None,
|
||||||
Usage::new(self).create_usage_with_title(&[]),
|
Usage::new(self).create_usage_with_title(&[]),
|
||||||
self.app.color(),
|
self.app.color(),
|
||||||
|
@ -663,7 +666,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
let append = self.arg_have_val(matcher, p);
|
let append = self.arg_have_val(matcher, p);
|
||||||
self.add_val_to_arg(
|
self.add_val_to_arg(
|
||||||
p,
|
p,
|
||||||
arg_os,
|
&arg_os,
|
||||||
matcher,
|
matcher,
|
||||||
ValueType::CommandLine,
|
ValueType::CommandLine,
|
||||||
append,
|
append,
|
||||||
|
@ -768,7 +771,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
|
|
||||||
fn match_arg_error(
|
fn match_arg_error(
|
||||||
&self,
|
&self,
|
||||||
arg_os: &ArgStr,
|
arg_os: &RawOsStr,
|
||||||
valid_arg_found: bool,
|
valid_arg_found: bool,
|
||||||
trailing_values: bool,
|
trailing_values: bool,
|
||||||
) -> ClapError {
|
) -> 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 the arg matches a subcommand name, or any of its aliases (if defined)
|
||||||
if self.possible_subcommand(arg_os, valid_arg_found).is_some() {
|
if self.possible_subcommand(arg_os, valid_arg_found).is_some() {
|
||||||
return ClapError::unnecessary_double_dash(
|
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(&[]),
|
Usage::new(self).create_usage_with_title(&[]),
|
||||||
self.app.color(),
|
self.app.color(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let candidates =
|
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 the argument looks like a subcommand.
|
||||||
if !candidates.is_empty() {
|
if !candidates.is_empty() {
|
||||||
let candidates: Vec<_> = candidates
|
let candidates: Vec<_> = candidates
|
||||||
|
@ -792,7 +795,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
.map(|candidate| format!("'{}'", candidate))
|
.map(|candidate| format!("'{}'", candidate))
|
||||||
.collect();
|
.collect();
|
||||||
return ClapError::invalid_subcommand(
|
return ClapError::invalid_subcommand(
|
||||||
arg_os.to_string_lossy().to_string(),
|
arg_os.to_str_lossy().into_owned(),
|
||||||
candidates.join(" or "),
|
candidates.join(" or "),
|
||||||
self.app
|
self.app
|
||||||
.bin_name
|
.bin_name
|
||||||
|
@ -806,7 +809,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
// If the argument must be a subcommand.
|
// If the argument must be a subcommand.
|
||||||
if !self.app.has_args() || self.is_set(AS::InferSubcommands) && self.app.has_subcommands() {
|
if !self.app.has_args() || self.is_set(AS::InferSubcommands) && self.app.has_subcommands() {
|
||||||
return ClapError::unrecognized_subcommand(
|
return ClapError::unrecognized_subcommand(
|
||||||
arg_os.to_string_lossy().to_string(),
|
arg_os.to_str_lossy().into_owned(),
|
||||||
self.app
|
self.app
|
||||||
.bin_name
|
.bin_name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -816,7 +819,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ClapError::unknown_argument(
|
ClapError::unknown_argument(
|
||||||
arg_os.to_string_lossy().to_string(),
|
arg_os.to_str_lossy().into_owned(),
|
||||||
None,
|
None,
|
||||||
Usage::new(self).create_usage_with_title(&[]),
|
Usage::new(self).create_usage_with_title(&[]),
|
||||||
self.app.color(),
|
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)
|
// 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);
|
debug!("Parser::possible_subcommand: arg={:?}", arg_os);
|
||||||
|
|
||||||
if !(self.is_set(AS::ArgsNegateSubcommands) && valid_arg_found) {
|
if !(self.is_set(AS::ArgsNegateSubcommands) && valid_arg_found) {
|
||||||
|
@ -845,7 +848,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
let v = self
|
let v = self
|
||||||
.app
|
.app
|
||||||
.all_subcommand_names()
|
.all_subcommand_names()
|
||||||
.filter(|s| arg_os.is_prefix_of(s))
|
.filter(|s| RawOsStr::from_str(s).starts_with_os(arg_os))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if v.len() == 1 {
|
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)
|
// 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);
|
debug!("Parser::possible_long_flag_subcommand: arg={:?}", arg_os);
|
||||||
if self.is_set(AS::InferSubcommands) {
|
if self.is_set(AS::InferSubcommands) {
|
||||||
let options = self
|
let options = self
|
||||||
|
@ -871,12 +874,12 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
.get_subcommands()
|
.get_subcommands()
|
||||||
.fold(Vec::new(), |mut options, sc| {
|
.fold(Vec::new(), |mut options, sc| {
|
||||||
if let Some(long) = sc.long_flag {
|
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.push(long);
|
||||||
}
|
}
|
||||||
options.extend(
|
options.extend(
|
||||||
sc.get_all_aliases()
|
sc.get_all_aliases()
|
||||||
.filter(|alias| arg_os.is_prefix_of(alias)),
|
.filter(|alias| RawOsStr::from_str(alias).starts_with_os(arg_os)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
options
|
options
|
||||||
|
@ -885,7 +888,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
return Some(options[0]);
|
return Some(options[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for sc in &options {
|
for sc in options {
|
||||||
if sc == arg_os {
|
if sc == arg_os {
|
||||||
return Some(sc);
|
return Some(sc);
|
||||||
}
|
}
|
||||||
|
@ -930,7 +933,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(ClapError::unrecognized_subcommand(
|
return Err(ClapError::unrecognized_subcommand(
|
||||||
cmd.to_string_lossy().to_string(),
|
cmd.to_string_lossy().into_owned(),
|
||||||
self.app
|
self.app
|
||||||
.bin_name
|
.bin_name
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -968,7 +971,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
Err(parser.help_err(self.app.is_set(AS::UseLongFormatForHelpSubcommand)))
|
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!(
|
debug!(
|
||||||
"Parser::is_new_arg: {:?}:{:?}",
|
"Parser::is_new_arg: {:?}:{:?}",
|
||||||
next, current_positional.name
|
next, current_positional.name
|
||||||
|
@ -977,7 +980,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
if self.is_set(AS::AllowLeadingHyphen)
|
if self.is_set(AS::AllowLeadingHyphen)
|
||||||
|| self.app[¤t_positional.id].is_set(ArgSettings::AllowHyphenValues)
|
|| self.app[¤t_positional.id].is_set(ArgSettings::AllowHyphenValues)
|
||||||
|| (self.is_set(AS::AllowNegativeNumbers)
|
|| (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.
|
// If allow hyphen, this isn't a new arg.
|
||||||
debug!("Parser::is_new_arg: Allow hyphen");
|
debug!("Parser::is_new_arg: Allow hyphen");
|
||||||
|
@ -990,7 +993,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
debug!("Parser::is_new_arg: - found");
|
debug!("Parser::is_new_arg: - found");
|
||||||
// If this is a short flag, this is a new arg. But a singe '-' by
|
// 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.
|
// itself is a value and typically means "stdin" on unix systems.
|
||||||
next.len() != 1
|
next.raw_len() != 1
|
||||||
} else {
|
} else {
|
||||||
debug!("Parser::is_new_arg: value");
|
debug!("Parser::is_new_arg: value");
|
||||||
// Nothing special, this is a 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
|
// Retrieves the names of all args the user has supplied thus far, except required ones
|
||||||
// because those will be listed in self.required
|
// 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");
|
||||||
debug!(
|
debug!(
|
||||||
"Parser::check_for_help_and_version_str: Checking if --{:?} is help or version...",
|
"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(
|
fn parse_long_arg(
|
||||||
&mut self,
|
&mut self,
|
||||||
matcher: &mut ArgMatcher,
|
matcher: &mut ArgMatcher,
|
||||||
full_arg: &ArgStr,
|
long_arg: &RawOsStr,
|
||||||
parse_state: &ParseState,
|
parse_state: &ParseState,
|
||||||
valid_arg_found: &mut bool,
|
valid_arg_found: &mut bool,
|
||||||
trailing_values: 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: cur_idx:={}", self.cur_idx.get());
|
||||||
|
|
||||||
debug!("Parser::parse_long_arg: Does it contain '='...");
|
debug!("Parser::parse_long_arg: Does it contain '='...");
|
||||||
let long_arg = full_arg.trim_start_n_matches(2, b'-');
|
|
||||||
if long_arg.is_empty() {
|
if long_arg.is_empty() {
|
||||||
return ParseResult::NoArg;
|
return ParseResult::NoArg;
|
||||||
}
|
}
|
||||||
let (arg, val) = if full_arg.contains_byte(b'=') {
|
let (arg, val) = if let Some(index) = long_arg.find("=") {
|
||||||
let (p0, p1) = long_arg.split_at_byte(b'=');
|
let (p0, p1) = long_arg.split_at(index);
|
||||||
debug!("Yes '{:?}'", p1);
|
debug!("Yes '{:?}'", p1);
|
||||||
(p0, Some(p1))
|
(p0, Some(p1))
|
||||||
} else {
|
} else {
|
||||||
|
@ -1204,20 +1206,20 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
(long_arg, None)
|
(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!(
|
debug!(
|
||||||
"Parser::parse_long_arg: Found valid opt or flag '{}'",
|
"Parser::parse_long_arg: Found valid opt or flag '{}'",
|
||||||
opt.to_string()
|
opt.to_string()
|
||||||
);
|
);
|
||||||
Some(opt)
|
Some(opt)
|
||||||
} else if self.is_set(AS::InferLongArgs) {
|
} 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| {
|
self.app.args.args().find(|a| {
|
||||||
a.long
|
a.long
|
||||||
.map_or(false, |long| long.starts_with(arg_str.as_ref()))
|
.map_or(false, |long| long.starts_with(&*arg_str))
|
||||||
|| a.aliases
|
|| a.aliases
|
||||||
.iter()
|
.iter()
|
||||||
.any(|(alias, _)| alias.starts_with(arg_str.as_ref()))
|
.any(|(alias, _)| alias.starts_with(&*arg_str))
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -1231,7 +1233,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
"Parser::parse_long_arg: Found an opt with value '{:?}'",
|
"Parser::parse_long_arg: Found an opt with value '{:?}'",
|
||||||
&val
|
&val
|
||||||
);
|
);
|
||||||
self.parse_opt(&val, opt, matcher, trailing_values)
|
self.parse_opt(val, opt, matcher, trailing_values)
|
||||||
} else if let Some(rest) = val {
|
} else if let Some(rest) = val {
|
||||||
debug!(
|
debug!(
|
||||||
"Parser::parse_long_arg: Got invalid literal `{:?}`",
|
"Parser::parse_long_arg: Got invalid literal `{:?}`",
|
||||||
|
@ -1248,7 +1250,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
ParseResult::UnneededAttachedValue {
|
ParseResult::UnneededAttachedValue {
|
||||||
rest: rest.to_string_lossy().to_string(),
|
rest: rest.to_str_lossy().into_owned(),
|
||||||
used,
|
used,
|
||||||
arg: opt.to_string(),
|
arg: opt.to_string(),
|
||||||
}
|
}
|
||||||
|
@ -1264,7 +1266,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
ParseResult::MaybeHyphenValue
|
ParseResult::MaybeHyphenValue
|
||||||
} else {
|
} else {
|
||||||
ParseResult::NoMatchingArg {
|
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(
|
fn parse_short_arg(
|
||||||
&mut self,
|
&mut self,
|
||||||
matcher: &mut ArgMatcher,
|
matcher: &mut ArgMatcher,
|
||||||
full_arg: &ArgStr,
|
short_arg: &RawOsStr,
|
||||||
parse_state: &ParseState,
|
parse_state: &ParseState,
|
||||||
// change this to possible pos_arg when removing the usage of &mut Parser.
|
// change this to possible pos_arg when removing the usage of &mut Parser.
|
||||||
pos_counter: usize,
|
pos_counter: usize,
|
||||||
valid_arg_found: &mut bool,
|
valid_arg_found: &mut bool,
|
||||||
trailing_values: bool,
|
trailing_values: bool,
|
||||||
) -> ParseResult {
|
) -> ParseResult {
|
||||||
debug!("Parser::parse_short_arg: full_arg={:?}", full_arg);
|
debug!("Parser::parse_short_arg: short_arg={:?}", short_arg);
|
||||||
let arg_os = full_arg.trim_start_matches(b'-');
|
let arg = short_arg.to_str_lossy();
|
||||||
let arg = arg_os.to_string_lossy();
|
|
||||||
|
|
||||||
if (self.is_set(AS::AllowNegativeNumbers) && arg.parse::<f64>().is_ok())
|
if (self.is_set(AS::AllowNegativeNumbers) && arg.parse::<f64>().is_ok())
|
||||||
|| (self.is_set(AS::AllowLeadingHyphen)
|
|| (self.is_set(AS::AllowLeadingHyphen)
|
||||||
|
@ -1332,24 +1333,12 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for trailing concatenated value
|
// 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!(
|
debug!(
|
||||||
"Parser::parse_short_arg:iter:{}: i={}, arg_os={:?}",
|
"Parser::parse_short_arg:iter:{}: val={:?} (bytes), val={:?} (ascii), rest={:?}, arg_os={:?}",
|
||||||
c, i, arg_os
|
c, val, val.as_raw_bytes(), arg_os
|
||||||
);
|
);
|
||||||
let val = if i != arg_os.len() {
|
let val = Some(val).filter(|v| !v.is_empty());
|
||||||
// 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
|
|
||||||
};
|
|
||||||
|
|
||||||
// Default to "we're expecting a value later".
|
// 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
|
// e.g. `-xvf`, when RequireEquals && x.min_vals == 0, we don't
|
||||||
// consume the `vf`, even if it's provided as value.
|
// 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,
|
ParseResult::AttachedValueNotConsumed => continue,
|
||||||
x => return x,
|
x => return x,
|
||||||
}
|
}
|
||||||
|
@ -1393,7 +1382,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
|
|
||||||
fn parse_opt(
|
fn parse_opt(
|
||||||
&self,
|
&self,
|
||||||
attached_value: &Option<ArgStr>,
|
attached_value: Option<&RawOsStr>,
|
||||||
opt: &Arg<'help>,
|
opt: &Arg<'help>,
|
||||||
matcher: &mut ArgMatcher,
|
matcher: &mut ArgMatcher,
|
||||||
trailing_values: bool,
|
trailing_values: bool,
|
||||||
|
@ -1435,8 +1424,8 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let Some(fv) = attached_value {
|
} else if let Some(fv) = attached_value {
|
||||||
let v = fv.trim_start_n_matches(1, b'=');
|
let v = fv.strip_prefix("=").unwrap_or(fv);
|
||||||
debug!("Found - {:?}, len: {}", v, v.len());
|
debug!("Found - {:?}, len: {}", v, v.raw_len());
|
||||||
debug!(
|
debug!(
|
||||||
"Parser::parse_opt: {:?} contains '='...{:?}",
|
"Parser::parse_opt: {:?} contains '='...{:?}",
|
||||||
fv,
|
fv,
|
||||||
|
@ -1466,7 +1455,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
fn add_val_to_arg(
|
fn add_val_to_arg(
|
||||||
&self,
|
&self,
|
||||||
arg: &Arg<'help>,
|
arg: &Arg<'help>,
|
||||||
val: ArgStr,
|
val: &RawOsStr,
|
||||||
matcher: &mut ArgMatcher,
|
matcher: &mut ArgMatcher,
|
||||||
ty: ValueType,
|
ty: ValueType,
|
||||||
append: bool,
|
append: bool,
|
||||||
|
@ -1495,7 +1484,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
};
|
};
|
||||||
self.add_multiple_vals_to_arg(
|
self.add_multiple_vals_to_arg(
|
||||||
arg,
|
arg,
|
||||||
vals.into_iter().map(|x| x.into_os_string()),
|
vals.into_iter().map(|x| x.to_os_str().into_owned()),
|
||||||
matcher,
|
matcher,
|
||||||
ty,
|
ty,
|
||||||
append,
|
append,
|
||||||
|
@ -1503,7 +1492,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
// If there was a delimiter used or we must use the delimiter to
|
// 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
|
// separate the values or no more vals is needed, we're not
|
||||||
// looking for more values.
|
// looking for more values.
|
||||||
return if val.contains_char(delim)
|
return if val.contains(delim)
|
||||||
|| arg.is_set(ArgSettings::RequireDelimiter)
|
|| arg.is_set(ArgSettings::RequireDelimiter)
|
||||||
|| !matcher.needs_more_vals(arg)
|
|| !matcher.needs_more_vals(arg)
|
||||||
{
|
{
|
||||||
|
@ -1518,7 +1507,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
return ParseResult::ValuesDone;
|
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) {
|
if matcher.needs_more_vals(arg) {
|
||||||
ParseResult::Opt(arg.id.clone())
|
ParseResult::Opt(arg.id.clone())
|
||||||
} else {
|
} else {
|
||||||
|
@ -1686,7 +1675,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
if let Some(default) = default {
|
if let Some(default) = default {
|
||||||
self.add_val_to_arg(
|
self.add_val_to_arg(
|
||||||
arg,
|
arg,
|
||||||
ArgStr::new(default),
|
&RawOsStr::new(default),
|
||||||
matcher,
|
matcher,
|
||||||
ty,
|
ty,
|
||||||
false,
|
false,
|
||||||
|
@ -1782,7 +1771,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
|
|
||||||
debug!("Parser::add_env: Checking arg `{}`", a);
|
debug!("Parser::add_env: Checking arg `{}`", a);
|
||||||
if let Some((_, Some(ref val))) = a.env {
|
if let Some((_, Some(ref val))) = a.env {
|
||||||
let val = ArgStr::new(val);
|
let val = RawOsStr::new(val);
|
||||||
|
|
||||||
if a.is_set(ArgSettings::TakesValue) {
|
if a.is_set(ArgSettings::TakesValue) {
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -1791,7 +1780,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
);
|
);
|
||||||
self.add_val_to_arg(
|
self.add_val_to_arg(
|
||||||
a,
|
a,
|
||||||
val,
|
&val,
|
||||||
matcher,
|
matcher,
|
||||||
ValueType::EnvVariable,
|
ValueType::EnvVariable,
|
||||||
false,
|
false,
|
||||||
|
@ -1813,7 +1802,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Parser::add_env: Found a flag with value `{:?}`", val);
|
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);
|
debug!("Parser::add_env: Found boolean literal `{}`", predicate);
|
||||||
if predicate {
|
if predicate {
|
||||||
matcher.add_index_to(&a.id, self.cur_idx.get(), ValueType::EnvVariable);
|
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()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
return Err(Error::invalid_value(
|
return Err(Error::invalid_value(
|
||||||
val_str.to_string(),
|
val_str.into_owned(),
|
||||||
&arg.possible_vals,
|
&arg.possible_vals,
|
||||||
arg,
|
arg,
|
||||||
Usage::new(self.p).create_usage_with_title(&used),
|
Usage::new(self.p).create_usage_with_title(&used),
|
||||||
|
@ -149,7 +149,7 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
|
||||||
debug!("error");
|
debug!("error");
|
||||||
return Err(Error::value_validation(
|
return Err(Error::value_validation(
|
||||||
arg.to_string(),
|
arg.to_string(),
|
||||||
val.to_string_lossy().to_string(),
|
val.to_string_lossy().into_owned(),
|
||||||
e,
|
e,
|
||||||
self.p.app.color(),
|
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)]
|
#![allow(clippy::single_component_path_imports)]
|
||||||
|
|
||||||
mod argstr;
|
|
||||||
mod fnv;
|
mod fnv;
|
||||||
mod graph;
|
mod graph;
|
||||||
mod id;
|
mod id;
|
||||||
|
@ -11,7 +10,7 @@ pub use self::fnv::Key;
|
||||||
|
|
||||||
#[cfg(feature = "env")]
|
#[cfg(feature = "env")]
|
||||||
pub(crate) use self::str_to_bool::str_to_bool;
|
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;
|
pub(crate) use vec_map::VecMap;
|
||||||
|
|
||||||
#[cfg(feature = "color")]
|
#[cfg(feature = "color")]
|
||||||
|
|
Loading…
Reference in a new issue