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:
Kevin K 2018-04-03 23:01:45 -04:00
parent 82e8a47f24
commit 41e29417b5
4 changed files with 152 additions and 59 deletions

View file

@ -176,7 +176,7 @@ impl<'w> Help<'w> {
fn write_args_unsorted<'a, 'b, I>(&mut self, args: I) -> io::Result<()>
where
'a: 'b,
I: Iterator<Item = &'b Arg<'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')
@ -210,7 +210,7 @@ impl<'w> Help<'w> {
fn write_args<'a, 'b, I>(&mut self, args: I) -> io::Result<()>
where
'a: 'b,
I: Iterator<Item = &'b Arg<'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()

View file

@ -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) {

View file

@ -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]

View file

@ -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));
}