mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 22:32:33 +00:00
fix: fixes group tests on v3-master
This commit is contained in:
parent
5a06a8270a
commit
a2cd63cc9e
6 changed files with 90 additions and 41 deletions
|
@ -1720,6 +1720,23 @@ impl<'a, 'b> App<'a, 'b> {
|
|||
write!(w, "{} {}", &self.name[..], ver)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn format_group(&self, g: &str) -> String {
|
||||
let g_string = self
|
||||
.unroll_args_in_group(g)
|
||||
.iter()
|
||||
.filter_map(|x| self.find(x))
|
||||
.map(|x| {
|
||||
if x.index.is_some() {
|
||||
x.name.to_owned()
|
||||
} else {
|
||||
x.to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("|");
|
||||
format!("<{}>", &*g_string)
|
||||
}
|
||||
}
|
||||
|
||||
// Internal Query Methods
|
||||
|
|
|
@ -1007,23 +1007,6 @@ macro_rules! groups_for_arg {
|
|||
}}
|
||||
}
|
||||
|
||||
|
||||
macro_rules! find_from {
|
||||
($app:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
|
||||
let mut ret = None;
|
||||
for k in $matcher.arg_names() {
|
||||
if let Some(a) = find!($app, k) {
|
||||
if let Some(ref v) = a.$from {
|
||||
if v.contains($arg_name) {
|
||||
ret = Some(a.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret
|
||||
}};
|
||||
}
|
||||
|
||||
// Finds an arg by name
|
||||
macro_rules! find {
|
||||
($app:expr, $name:expr, $what:ident) => {
|
||||
|
|
|
@ -303,8 +303,6 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
|
|||
}
|
||||
|
||||
// Returns the required args in usage string form by fully unrolling all groups
|
||||
// `used`: The args that were used
|
||||
// `incl`: Args that should be displayed even if not required
|
||||
// `incl_last`: should we incldue args that are Arg::Last? (i.e. `prog [foo] -- [last]). We
|
||||
// can't do that for required usages being built for subcommands because it would look like:
|
||||
// `prog [foo] -- [last] <subcommand>` which is totally wrong.
|
||||
|
@ -394,8 +392,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
|
|||
.iter()
|
||||
.filter(|n| self.p.app.groups.iter().any(|g| &&g.name == n))
|
||||
{
|
||||
let g_string = self.p.app.unroll_args_in_group(g).join("|");
|
||||
let elem = format!("<{}>", &g_string[..g_string.len()]);
|
||||
let elem = self.p.app.format_group(g);
|
||||
if !g_vec.contains(&elem) {
|
||||
g_vec.push(elem);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::process;
|
|||
use std::result::Result as StdResult;
|
||||
|
||||
// Internal
|
||||
use build::Arg;
|
||||
use build::{Arg, ArgGroup};
|
||||
use output::fmt::{ColorWhen, Colorizer, ColorizerOption};
|
||||
use parse::features::suggestions;
|
||||
|
||||
|
@ -405,6 +405,44 @@ impl Error {
|
|||
#[doc(hidden)]
|
||||
pub fn write_to<W: Write>(&self, w: &mut W) -> io::Result<()> { write!(w, "{}", self.message) }
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn group_conflict<'a, 'b, O, U>(
|
||||
group: &ArgGroup,
|
||||
other: Option<O>,
|
||||
usage: U,
|
||||
color: ColorWhen,
|
||||
) -> Self
|
||||
where
|
||||
O: Into<String>,
|
||||
U: Display,
|
||||
{
|
||||
let mut v = vec![group.name.to_owned()];
|
||||
let c = Colorizer::new(ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: color,
|
||||
});
|
||||
Error {
|
||||
message: format!(
|
||||
"{} The argument '{}' cannot be used with {}\n\n\
|
||||
{}\n\n\
|
||||
For more information try {}",
|
||||
c.error("error:"),
|
||||
c.warning(group.name),
|
||||
match other {
|
||||
Some(name) => {
|
||||
let n = name.into();
|
||||
v.push(n.clone());
|
||||
c.warning(format!("'{}'", n))
|
||||
}
|
||||
None => c.none("one or more of the other specified arguments".to_owned()),
|
||||
},
|
||||
usage,
|
||||
c.good("--help")
|
||||
),
|
||||
kind: ErrorKind::ArgumentConflict,
|
||||
info: Some(v),
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
pub fn argument_conflict<'a, 'b, O, U>(
|
||||
arg: &Arg,
|
||||
|
|
|
@ -161,28 +161,42 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
|
|||
|
||||
fn build_conflict_err(&self, name: &str, matcher: &ArgMatcher<'a>) -> ClapResult<()> {
|
||||
debugln!("build_err!: name={}", name);
|
||||
let mut c_with = find_from!(self.p.app, &name, blacklist, &matcher);
|
||||
c_with = c_with.or(self
|
||||
.p
|
||||
.app
|
||||
.find(&name)
|
||||
.map_or(None, |ref aa| aa.blacklist.as_ref())
|
||||
.map_or(None, |ref bl| bl.iter().find(|arg| matcher.contains(arg)))
|
||||
.map_or(None, |an| self.p.app.find(an))
|
||||
.map_or(None, |aa| Some(format!("{}", aa))));
|
||||
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name);
|
||||
let usg = Usage::new(self.p).create_usage_with_title(&[]);
|
||||
if let Some(f) = self.p.app.find(&name) {
|
||||
debugln!("build_err!: It was a flag...");
|
||||
Err(Error::argument_conflict(
|
||||
f,
|
||||
if let Some(a) = self.p.app.find(name) {
|
||||
for k in matcher.arg_names() {
|
||||
if let Some(a) = self.p.app.find(k) {
|
||||
if let Some(ref v) = a.blacklist {
|
||||
if v.contains(&name) {
|
||||
return Err(Error::argument_conflict(
|
||||
a,
|
||||
Some(a.to_string()),
|
||||
&*usg,
|
||||
self.p.app.color(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(g) = self.p.app.groups.iter().find(|x| x.name == name) {
|
||||
let args_in_group = self.p.app.unroll_args_in_group(g.name);
|
||||
let first = matcher
|
||||
.arg_names()
|
||||
.find(|x| args_in_group.contains(x))
|
||||
.expect(INTERNAL_ERROR_MSG);
|
||||
let c_with = matcher
|
||||
.arg_names()
|
||||
.find(|x| x != &first && args_in_group.contains(x))
|
||||
.map(|x| self.p.app.find(x).expect(INTERNAL_ERROR_MSG).to_string());
|
||||
debugln!("build_err!:c_with={:?}:group", c_with);
|
||||
return Err(Error::argument_conflict(
|
||||
self.p.app.find(first).expect(INTERNAL_ERROR_MSG),
|
||||
c_with,
|
||||
&*usg,
|
||||
self.p.app.color(),
|
||||
))
|
||||
} else {
|
||||
panic!(INTERNAL_ERROR_MSG);
|
||||
));
|
||||
}
|
||||
|
||||
panic!(INTERNAL_ERROR_MSG);
|
||||
}
|
||||
|
||||
fn validate_conflicts(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
|
||||
|
|
|
@ -22,7 +22,7 @@ USAGE:
|
|||
For more information try --help";
|
||||
|
||||
static REQ_GROUP_CONFLICT_REV: &'static str =
|
||||
"error: The argument '--delete' cannot be used with 'base'
|
||||
"error: The argument '--delete' cannot be used with '<base>'
|
||||
|
||||
USAGE:
|
||||
clap-test <base|--delete>
|
||||
|
@ -227,7 +227,7 @@ fn group_multiple_args_error() {
|
|||
let result = App::new("group")
|
||||
.args_from_usage(
|
||||
"-f, --flag 'some flag'
|
||||
-c, --color 'some other flag'",
|
||||
-c, --color 'some other flag'",
|
||||
)
|
||||
.group(ArgGroup::with_name("req").args(&["flag", "color"]))
|
||||
.get_matches_from_safe(vec!["group", "-f", "-c"]);
|
||||
|
|
Loading…
Reference in a new issue