Skip to content

Commit

Permalink
Merge pull request #1241 from kbknapp/v3-dev
Browse files Browse the repository at this point in the history
V3 dev
  • Loading branch information
kbknapp authored Apr 4, 2018
2 parents c9159d3 + 36815fe commit 4df65d8
Show file tree
Hide file tree
Showing 7 changed files with 516 additions and 21 deletions.
35 changes: 24 additions & 11 deletions src/app/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,17 @@ 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')
self.longest = 2;
let mut arg_v = Vec::with_capacity(10);
let use_long = self.use_long;
for arg in args.filter(|arg| {
!(arg.is_set(ArgSettings::Hidden)) || arg.is_set(ArgSettings::NextLineHelp)
should_show_arg(use_long, *arg)
}) {
if arg.longest_filter() {
self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str()));
Expand All @@ -207,20 +208,21 @@ 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')
self.longest = 2;
let mut ord_m = VecMap::new();
let use_long = self.use_long;
// Determine the longest
for arg in args.filter(|arg| {
// If it's NextLineHelp we don't care to compute how long it is because it may be
// NextLineHelp on purpose simply *because* it's so long and would throw off all other
// args alignment
!arg.is_set(ArgSettings::Hidden) || arg.is_set(ArgSettings::NextLineHelp)
should_show_arg(use_long, *arg)
}) {
if arg.longest_filter() {
debugln!("Help::write_args: Current Longest...{}", self.longest);
Expand Down Expand Up @@ -682,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();
Expand Down Expand Up @@ -1099,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()
Expand Down
55 changes: 50 additions & 5 deletions src/app/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -926,6 +926,51 @@ where
Ok(())
}

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: &Arg| {
v.long_help.is_some() ||
v.is_set(ArgSettings::HiddenLongHelp) ||
v.is_set(ArgSettings::HiddenShortHelp)
};

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) -> 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,
matcher: &mut ArgMatcher<'a>,
Expand Down Expand Up @@ -1464,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,
Expand All @@ -1478,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) {
Expand Down
157 changes: 156 additions & 1 deletion src/args/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -3769,6 +3770,160 @@ impl<'a, 'b> Arg<'a, 'b> {
self.multiple(raw).allow_hyphen_values(raw).last(raw)
}

/// Hides an argument from short help message output.
///
/// **NOTE:** This does **not** hide the argument from usage strings on error
///
/// **NOTE:** Setting this option will cause next-line-help output style to be used
/// when long help (`--help`) is called.
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// Arg::with_name("debug")
/// .hidden_short_help(true)
/// # ;
/// ```
/// Setting `hidden_short_help(true)` will hide the argument when displaying short help text
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("prog")
/// .arg(Arg::with_name("cfg")
/// .long("config")
/// .hidden_short_help(true)
/// .help("Some help text describing the --config arg"))
/// .get_matches_from(vec![
/// "prog", "-h"
/// ]);
/// ```
///
/// The above example displays
///
/// ```notrust
/// helptest
///
/// USAGE:
/// helptest [FLAGS]
///
/// FLAGS:
/// -h, --help Prints help information
/// -V, --version Prints version information
/// ```
///
/// However, when --help is called
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("prog")
/// .arg(Arg::with_name("cfg")
/// .long("config")
/// .hidden_short_help(true)
/// .help("Some help text describing the --config arg"))
/// .get_matches_from(vec![
/// "prog", "--help"
/// ]);
/// ```
///
/// Then the following would be displayed
///
/// ```notrust
/// helptest
///
/// USAGE:
/// helptest [FLAGS]
///
/// FLAGS:
/// --config Some help text describing the --config arg
/// -h, --help Prints help information
/// -V, --version Prints version information
/// ```
pub fn hidden_short_help(self, hide: bool) -> Self {
if hide {
self.set(ArgSettings::HiddenShortHelp)
} else {
self.unset(ArgSettings::HiddenShortHelp)
}
}

/// Hides an argument from long help message output.
///
/// **NOTE:** This does **not** hide the argument from usage strings on error
///
/// **NOTE:** Setting this option will cause next-line-help output style to be used
/// when long help (`--help`) is called.
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// Arg::with_name("debug")
/// .hidden_long_help(true)
/// # ;
/// ```
/// Setting `hidden_long_help(true)` will hide the argument when displaying long help text
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("prog")
/// .arg(Arg::with_name("cfg")
/// .long("config")
/// .hidden_long_help(true)
/// .help("Some help text describing the --config arg"))
/// .get_matches_from(vec![
/// "prog", "--help"
/// ]);
/// ```
///
/// The above example displays
///
/// ```notrust
/// helptest
///
/// USAGE:
/// helptest [FLAGS]
///
/// FLAGS:
/// -h, --help Prints help information
/// -V, --version Prints version information
/// ```
///
/// However, when -h is called
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("prog")
/// .arg(Arg::with_name("cfg")
/// .long("config")
/// .hidden_long_help(true)
/// .help("Some help text describing the --config arg"))
/// .get_matches_from(vec![
/// "prog", "-h"
/// ]);
/// ```
///
/// Then the following would be displayed
///
/// ```notrust
/// helptest
///
/// USAGE:
/// helptest [FLAGS]
///
/// FLAGS:
/// --config Some help text describing the --config arg
/// -h, --help Prints help information
/// -V, --version Prints version information
/// ```
pub fn hidden_long_help(self, hide: bool) -> Self {
if hide {
self.set(ArgSettings::HiddenLongHelp)
} else {
self.unset(ArgSettings::HiddenLongHelp)
}
}

// @TODO @docs @v3-beta: write better docs as ArgSettings is now critical
/// Checks if one of the [`ArgSettings`] is set for the argument
/// [`ArgSettings`]: ./enum.ArgSettings.html
Expand Down Expand Up @@ -4096,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]
Expand Down
22 changes: 20 additions & 2 deletions src/args/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ bitflags! {
const HIDE_DEFAULT_VAL = 1 << 15 | Self::TAKES_VAL.bits;
const CASE_INSENSITIVE = 1 << 16;
const HIDE_ENV_VALS = 1 << 17;
const MULTIPLE_VALS = 1 << 18 | Self::TAKES_VAL.bits;
const HIDDEN_SHORT_H = 1 << 18;
const HIDDEN_LONG_H = 1 << 19;
const MULTIPLE_VALS = 1 << 20 | Self::TAKES_VAL.bits;
}
}

Expand Down Expand Up @@ -54,7 +56,9 @@ impl ArgFlags {
Last => Flags::LAST,
IgnoreCase => Flags::CASE_INSENSITIVE,
HideEnvValues => Flags::HIDE_ENV_VALS,
HideDefaultValue => Flags::HIDE_DEFAULT_VAL
HideDefaultValue => Flags::HIDE_DEFAULT_VAL,
HiddenShortHelp => Flags::HIDDEN_SHORT_H,
HiddenLongHelp => Flags::HIDDEN_LONG_H
}
}

Expand Down Expand Up @@ -111,6 +115,10 @@ pub enum ArgSettings {
/// Hides any values currently assigned to ENV variables in the help message (good for sensitive
/// information)
HideEnvValues,
/// The argument should **not** be shown in short help text
HiddenShortHelp,
/// The argument should **not** be shown in long help text
HiddenLongHelp,
#[doc(hidden)] RequiredUnlessAll,
#[doc(hidden)] ValueDelimiterNotSet,
}
Expand All @@ -136,6 +144,8 @@ impl FromStr for ArgSettings {
"hidedefaultvalue" => Ok(ArgSettings::HideDefaultValue),
"ignorecase" => Ok(ArgSettings::IgnoreCase),
"hideenvvalues" => Ok(ArgSettings::HideEnvValues),
"hiddenshorthelp" => Ok(ArgSettings::HiddenShortHelp),
"hiddenlonghelp" => Ok(ArgSettings::HiddenLongHelp),
_ => Err("unknown ArgSetting, cannot convert from str".to_owned()),
}
}
Expand Down Expand Up @@ -212,6 +222,14 @@ mod test {
"hideenvvalues".parse::<ArgSettings>().unwrap(),
ArgSettings::HideEnvValues
);
assert_eq!(
"hiddenshorthelp".parse::<ArgSettings>().unwrap(),
ArgSettings::HiddenShortHelp
);
assert_eq!(
"hiddenlonghelp".parse::<ArgSettings>().unwrap(),
ArgSettings::HiddenLongHelp
);
assert!("hahahaha".parse::<ArgSettings>().is_err());
}
}
Loading

0 comments on commit 4df65d8

Please sign in to comment.