mirror of
https://github.com/clap-rs/clap
synced 2024-11-10 23:04:23 +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
119
src/app/help.rs
119
src/app/help.rs
|
@ -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()
|
||||
|
|
|
@ -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