mirror of
https://github.com/clap-rs/clap
synced 2024-09-21 06:41:54 +00:00
fix: fixes hiding args from short or long help in v3 context
Fixes the implementation of the hiding of arguments form the short or long help on v3
This commit is contained in:
parent
82e8a47f24
commit
41e29417b5
4 changed files with 152 additions and 59 deletions
129
src/app/help.rs
129
src/app/help.rs
|
@ -174,9 +174,9 @@ impl<'w> Help<'w> {
|
|||
impl<'w> Help<'w> {
|
||||
/// Writes help for each argument in the order they were declared to the wrapped stream.
|
||||
fn write_args_unsorted<'a, 'b, I>(&mut self, args: I) -> io::Result<()>
|
||||
where
|
||||
'a: 'b,
|
||||
I: Iterator<Item = &'b Arg<'a, 'b>>,
|
||||
where
|
||||
'a: 'b,
|
||||
I: Iterator<Item=&'b Arg<'a, 'b>>,
|
||||
{
|
||||
debugln!("Help::write_args_unsorted;");
|
||||
// The shortest an arg can legally be is 2 (i.e. '-x')
|
||||
|
@ -208,9 +208,9 @@ impl<'w> Help<'w> {
|
|||
|
||||
/// Sorts arguments by length and display order and write their help to the wrapped stream.
|
||||
fn write_args<'a, 'b, I>(&mut self, args: I) -> io::Result<()>
|
||||
where
|
||||
'a: 'b,
|
||||
I: Iterator<Item = &'b Arg<'a, 'b>>,
|
||||
where
|
||||
'a: 'b,
|
||||
I: Iterator<Item=&'b Arg<'a, 'b>>,
|
||||
{
|
||||
debugln!("Help::write_args;");
|
||||
// The shortest an arg can legally be is 2 (i.e. '-x')
|
||||
|
@ -558,14 +558,17 @@ impl<'w> Help<'w> {
|
|||
}
|
||||
spec_vals.join(" ")
|
||||
}
|
||||
|
||||
fn should_show_arg(use_long: bool, arg: &Arg) -> bool {
|
||||
if arg.is_set(ArgSettings::Hidden) {
|
||||
return false;
|
||||
}
|
||||
(!arg.is_set(ArgSettings::HiddenLongHelp) && use_long) ||
|
||||
(!arg.is_set(ArgSettings::HiddenShortHelp) && !use_long) ||
|
||||
arg.is_set(ArgSettings::NextLineHelp)
|
||||
}
|
||||
|
||||
/// Methods to write a single subcommand
|
||||
impl<'w> Help<'w> {
|
||||
fn write_subcommand<'a, 'b>(&mut self, app: &App<'a, 'b>) -> io::Result<()> {
|
||||
debugln!("Help::write_subcommand;");
|
||||
write!(self.writer, "{}", TAB)?;
|
||||
color!(self, "{}", app.name, good)?;
|
||||
let spec_vals = self.sc_val(app)?;
|
||||
self.sc_help(app, &*spec_vals)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sc_val<'a, 'b>(&mut self, app: &App<'a, 'b>) -> Result<String, io::Error> {
|
||||
|
@ -587,6 +590,87 @@ impl<'w> Help<'w> {
|
|||
}
|
||||
Ok(spec_vals)
|
||||
}
|
||||
|
||||
fn sc_spec_vals(&self, a: &App) -> String {
|
||||
debugln!("Help::sc_spec_vals: a={}", a.name);
|
||||
let mut spec_vals = vec![];
|
||||
if let Some(ref aliases) = a.aliases {
|
||||
debugln!("Help::spec_vals: Found aliases...{:?}", aliases);
|
||||
let als = if self.color {
|
||||
aliases
|
||||
.iter()
|
||||
.filter(|&als| als.1) // visible
|
||||
.map(|&als| format!("{}", self.cizer.good(als.0))) // name
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
} else {
|
||||
aliases
|
||||
.iter()
|
||||
.filter(|&als| als.1)
|
||||
.map(|&als| als.0)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
};
|
||||
if !als.is_empty() {
|
||||
spec_vals.push(format!(" [aliases: {}]", als));
|
||||
}
|
||||
}
|
||||
spec_vals.join(" ")
|
||||
}
|
||||
|
||||
fn sc_help<'a, 'b>(&mut self, app: &App<'a, 'b>, spec_vals: &str) -> io::Result<()> {
|
||||
debugln!("Help::sc_help;");
|
||||
let h = if self.use_long {
|
||||
app.long_about.unwrap_or_else(|| app.about.unwrap_or(""))
|
||||
} else {
|
||||
app.about.unwrap_or_else(|| app.long_about.unwrap_or(""))
|
||||
};
|
||||
let mut help = String::from(h) + spec_vals;
|
||||
let nlh = self.next_line_help || self.use_long;
|
||||
debugln!("Help::sc_help: Next Line...{:?}", nlh);
|
||||
|
||||
let spcs = if nlh || self.force_next_line {
|
||||
12 // "tab" * 3
|
||||
} else {
|
||||
self.longest + 12
|
||||
};
|
||||
|
||||
let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= self.term_w;
|
||||
|
||||
// Is help on next line, if so then indent
|
||||
if nlh || self.force_next_line {
|
||||
write!(self.writer, "\n{}{}{}", TAB, TAB, TAB)?;
|
||||
}
|
||||
|
||||
debug!("Help::sc_help: Too long...");
|
||||
if too_long && spcs <= self.term_w || h.contains("{n}") {
|
||||
sdebugln!("Yes");
|
||||
debugln!("Help::sc_help: help...{}", help);
|
||||
debugln!("Help::sc_help: help width...{}", str_width(&*help));
|
||||
// Determine how many newlines we need to insert
|
||||
let avail_chars = self.term_w - spcs;
|
||||
debugln!("Help::sc_help: Usable space...{}", avail_chars);
|
||||
help = wrap_help(&help.replace("{n}", "\n"), avail_chars);
|
||||
} else {
|
||||
sdebugln!("No");
|
||||
}
|
||||
if let Some(part) = help.lines().next() {
|
||||
write!(self.writer, "{}", part)?;
|
||||
}
|
||||
for part in help.lines().skip(1) {
|
||||
write!(self.writer, "\n")?;
|
||||
if nlh || self.force_next_line {
|
||||
write!(self.writer, "{}{}{}", TAB, TAB, TAB)?;
|
||||
} else {
|
||||
write_nspaces!(self.writer, self.longest + 8);
|
||||
}
|
||||
write!(self.writer, "{}", part)?;
|
||||
}
|
||||
if !help.contains('\n') && (nlh || self.force_next_line) {
|
||||
write!(self.writer, "\n")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Methods to write Parser help.
|
||||
|
@ -600,10 +684,10 @@ impl<'w> Help<'w> {
|
|||
let flags = parser.has_flags();
|
||||
// Strange filter/count vs fold... https://github.com/rust-lang/rust/issues/33038
|
||||
let pos = positionals!(parser.app).fold(0, |acc, arg| {
|
||||
if arg.is_set(ArgSettings::Hidden) {
|
||||
acc
|
||||
} else {
|
||||
if should_show_arg(self.use_long, arg) {
|
||||
acc + 1
|
||||
} else {
|
||||
acc
|
||||
}
|
||||
}) > 0;
|
||||
let opts = parser.has_opts();
|
||||
|
@ -1017,6 +1101,17 @@ impl<'w> Help<'w> {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_show_arg(use_long: bool, arg: &Arg) -> bool {
|
||||
debugln!("Help::should_show_arg: use_long={:?}, arg={}", use_long, arg.name);
|
||||
if arg.is_set(ArgSettings::Hidden) {
|
||||
return false;
|
||||
}
|
||||
(!arg.is_set(ArgSettings::HiddenLongHelp) && use_long) ||
|
||||
(!arg.is_set(ArgSettings::HiddenShortHelp) && !use_long) ||
|
||||
arg.is_set(ArgSettings::NextLineHelp)
|
||||
}
|
||||
|
||||
|
||||
fn wrap_help(help: &str, avail_chars: usize) -> String {
|
||||
let wrapper = textwrap::Wrapper::new(avail_chars).break_words(false);
|
||||
help.lines()
|
||||
|
|
|
@ -8,8 +8,8 @@ use std::iter::Peekable;
|
|||
use std::mem;
|
||||
use std::cell::Cell;
|
||||
|
||||
// Third party
|
||||
use map::{self, VecMap};
|
||||
// Third party facade
|
||||
use map::VecMap;
|
||||
|
||||
// Internal
|
||||
use INTERNAL_ERROR_MSG;
|
||||
|
@ -927,52 +927,49 @@ where
|
|||
}
|
||||
|
||||
fn use_long_help(&self) -> bool {
|
||||
debugln!("Parser::use_long_help;");
|
||||
// In this case, both must be checked. This allows the retention of
|
||||
// original formatting, but also ensures that the actual -h or --help
|
||||
// specified by the user is sent through. If HiddenShortHelp is not included,
|
||||
// then items specified with hidden_short_help will also be hidden.
|
||||
let should_long = |v: &Base| {
|
||||
let should_long = |v: &Arg| {
|
||||
v.long_help.is_some() ||
|
||||
v.is_set(ArgSettings::HiddenLongHelp) ||
|
||||
v.is_set(ArgSettings::HiddenShortHelp)
|
||||
};
|
||||
|
||||
self.meta.long_about.is_some()
|
||||
|| self.flags.iter().any(|f| should_long(&f.b))
|
||||
|| self.opts.iter().any(|o| should_long(&o.b))
|
||||
|| self.positionals.values().any(|p| should_long(&p.b))
|
||||
|| self.subcommands
|
||||
.iter()
|
||||
.any(|s| s.p.meta.long_about.is_some())
|
||||
self.app.long_about.is_some()
|
||||
|| args!(self.app).any(|f| should_long(&f))
|
||||
|| subcommands!(self.app).any(|s| s.long_about.is_some())
|
||||
}
|
||||
|
||||
fn _help(&self, mut use_long: bool) -> Error {
|
||||
debugln!("Parser::_help: use_long={:?}", use_long);
|
||||
use_long = use_long && self.use_long_help();
|
||||
let mut buf = vec![];
|
||||
match Help::write_parser_help(&mut buf, self, use_long) {
|
||||
Err(e) => e,
|
||||
_ => Error {
|
||||
message: String::from_utf8(buf).unwrap_or_default(),
|
||||
kind: ErrorKind::HelpDisplayed,
|
||||
info: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn _version(&self, use_long: bool) -> Error {
|
||||
debugln!("Parser::_version: ");
|
||||
let out = io::stdout();
|
||||
let mut buf_w = BufWriter::new(out.lock());
|
||||
match self.print_version(&mut buf_w, use_long) {
|
||||
Err(e) => e,
|
||||
_ => Error {
|
||||
message: String::new(),
|
||||
kind: ErrorKind::VersionDisplayed,
|
||||
info: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
// fn _help(&self, mut use_long: bool) -> ClapError {
|
||||
// debugln!("Parser::_help: use_long={:?}", use_long && self.use_long_help());
|
||||
// use_long = use_long && self.use_long_help();
|
||||
// let mut buf = vec![];
|
||||
// match Help::write_parser_help(&mut buf, self, use_long) {
|
||||
// Err(e) => e,
|
||||
// _ => ClapError {
|
||||
// message: String::from_utf8(buf).unwrap_or_default(),
|
||||
// kind: ErrorKind::HelpDisplayed,
|
||||
// info: None,
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn _version(&self, use_long: bool) -> ClapError {
|
||||
// debugln!("Parser::_version: ");
|
||||
// let out = io::stdout();
|
||||
// let mut buf_w = BufWriter::new(out.lock());
|
||||
// match self.print_version(&mut buf_w, use_long) {
|
||||
// Err(e) => e,
|
||||
// _ => ClapError {
|
||||
// message: String::new(),
|
||||
// kind: ErrorKind::VersionDisplayed,
|
||||
// info: None,
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
|
||||
fn parse_long_arg(
|
||||
&mut self,
|
||||
|
@ -1512,8 +1509,8 @@ where
|
|||
}
|
||||
|
||||
fn help_err(&self, mut use_long: bool) -> ClapError {
|
||||
debugln!("Parser::_help: use_long={:?}", use_long);
|
||||
use_long = use_long && self.app.use_long_help();
|
||||
debugln!("Parser::help_err: use_long={:?}", use_long && self.use_long_help());
|
||||
use_long = use_long && self.use_long_help();
|
||||
let mut buf = vec![];
|
||||
match Help::write_parser_help(&mut buf, self, use_long) {
|
||||
Err(e) => e,
|
||||
|
@ -1526,7 +1523,7 @@ where
|
|||
}
|
||||
|
||||
fn version_err(&self, use_long: bool) -> ClapError {
|
||||
debugln!("Parser::_version: ");
|
||||
debugln!("Parser::version_err: ");
|
||||
let out = io::stdout();
|
||||
let mut buf_w = BufWriter::new(out.lock());
|
||||
match self.print_version(&mut buf_w, use_long) {
|
||||
|
|
|
@ -10,6 +10,7 @@ use osstringext::OsStrExt3;
|
|||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::env;
|
||||
use std::cmp::{Ord, Ordering};
|
||||
use std::str;
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
use yaml_rust::Yaml;
|
||||
|
@ -4250,7 +4251,7 @@ mod test {
|
|||
f.long = Some("flag");
|
||||
f.aliases = Some(vec![("als", true)]);
|
||||
|
||||
assert_eq!(&*format!("{}", f), "--flag");
|
||||
assert_eq!(&*format!("{}", f), "--flag")
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -30,7 +30,7 @@ fn hidden_args() {
|
|||
Arg::from_usage("-f, --flag 'some flag'").hidden(true),
|
||||
Arg::from_usage("-F, --flag2 'some other flag'"),
|
||||
Arg::from_usage("--option [opt] 'some option'"),
|
||||
Arg::with_name("DUMMY").required(false).hidden(true),
|
||||
Arg::with_name("DUMMY").hidden(true),
|
||||
]);
|
||||
assert!(test::compare_output(app, "test --help", HIDDEN_ARGS, false));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue