Skip to content

Commit

Permalink
Auto merge of #540 - kbknapp:issues-536_to_539, r=kbknapp
Browse files Browse the repository at this point in the history
Issues 536 to 539
  • Loading branch information
homu committed Jun 24, 2016
2 parents 89d208e + e84cc01 commit 16c693a
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 35 deletions.
5 changes: 3 additions & 2 deletions src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -895,12 +895,13 @@ impl<'a, 'b> App<'a, 'b> {
///
/// ```rust
/// # use clap::App;
/// let app = App::new("myprog");
/// let mut app = App::new("myprog");
/// app.print_help();
/// ```
/// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html
/// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
pub fn print_help(&self) -> ClapResult<()> {
pub fn print_help(&mut self) -> ClapResult<()> {
self.p.create_help_and_version();
let out = io::stdout();
let mut buf_w = BufWriter::new(out.lock());
self.write_help(&mut buf_w)
Expand Down
128 changes: 107 additions & 21 deletions src/app/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ impl<'a, 'b> Parser<'a, 'b>

pub fn add_subcommand(&mut self, mut subcmd: App<'a, 'b>) {
debugln!("fn=Parser::add_subcommand;");
debugln!("Term widnth...{:?}", self.p.meta.term_w);
debugln!("Term widnth...{:?}", self.meta.term_w);
subcmd.p.meta.term_w = self.meta.term_w;
debug!("Is help...");
if subcmd.p.meta.name == "help" {
Expand Down Expand Up @@ -363,14 +363,81 @@ impl<'a, 'b> Parser<'a, 'b>
ret_val
}

pub fn has_flags(&self) -> bool {
!self.flags.is_empty()
pub fn get_args_tag(&self) -> Option<String> {
let mut count = 0;
'outer: for p in self.positionals.values().filter(|p| !p.is_set(ArgSettings::Required)) {
if let Some(g_vec) = self.groups_for_arg(p.name) {
for grp_s in &g_vec {
debugln!("iter;grp_s={};", grp_s);
if let Some(grp) = self.groups.get(grp_s) {
debug!("Is group required...");
if grp.required {
sdebugln!("Yes (continuing)");
continue 'outer;
} else {
sdebugln!("No (breaking)");
}
}
}
debugln!("Arg not required...");
count +=1;
} else {
debugln!("Arg not required...");
count +=1;
}
}
if count > 1 {
return None;
} else if count == 1 && self.positionals.len() > 1 {
return None;
} else if count == 1 {
let p = self.positionals.values().next().expect(INTERNAL_ERROR_MSG);
return Some(format!(" [{}]{}", p.name_no_brackets(), p.multiple_str()));
}
Some("".into())
}

pub fn needs_flags_tag(&self) -> bool {
debugln!("exec=needs_flags_tag;");
'outer: for f in &self.flags {
debugln!("iter;f={};", f.name);
if let Some(l) = f.long {
if l == "help" || l == "version" {
continue;
}
}
if let Some(g_vec) = self.groups_for_arg(f.name) {
for grp_s in &g_vec {
debugln!("iter;grp_s={};", grp_s);
if let Some(grp) = self.groups.get(grp_s) {
debug!("Is group required...");
if grp.required {
sdebugln!("Yes (continuing)");
continue 'outer;
} else {
sdebugln!("No (breaking)");
}
}
}
debugln!("Flag not required...(returning true)");
return true;
} else {
debugln!("Flag not required...(returning true)");
return true;
}
}

false
}

pub fn has_opts(&self) -> bool {
!self.opts.is_empty()
}

pub fn has_flags(&self) -> bool {
!self.flags.is_empty()
}

pub fn has_positionals(&self) -> bool {
!self.positionals.is_empty()
}
Expand Down Expand Up @@ -520,9 +587,13 @@ impl<'a, 'b> Parser<'a, 'b>
if &*arg_os == "help" &&
self.settings.is_set(AppSettings::NeedsSubcommandHelp) {
let cmds: Vec<OsString> = it.map(|c| c.into()).collect();
let mut help_help = false;
let mut sc = {
let mut sc: &Parser = self;
for (i, cmd) in cmds.iter().enumerate() {
if &*cmd.to_string_lossy() == "help" { // cmd help help
help_help = true;
}
if let Some(c) = sc.subcommands
.iter()
.filter(|s| &*s.p.meta.name == cmd)
Expand Down Expand Up @@ -563,7 +634,30 @@ impl<'a, 'b> Parser<'a, 'b>
}
sc.clone()
};
sc.create_help_and_version();
if help_help {
let mut pb = PosBuilder::new("subcommand", 1);
pb.help = Some("The subcommand whose help message to display");
pb.set(ArgSettings::Multiple);
sc.positionals.insert(1, pb);
for s in self.g_settings.clone() {
sc.set(s);
}
} else {
sc.create_help_and_version();
}
if sc.meta.bin_name != self.meta.bin_name {
sc.meta.bin_name = Some(format!("{}{}{}",
self.meta
.bin_name
.as_ref()
.unwrap_or(&String::new()),
if self.meta.bin_name.is_some() {
" "
} else {
""
},
&*sc.meta.name));
}
return sc._help();
}
subcmd_name = Some(arg_os.to_str().expect(INVALID_UTF8).to_owned());
Expand Down Expand Up @@ -873,10 +967,10 @@ impl<'a, 'b> Parser<'a, 'b>
args.iter().map(|s| *s).collect()
}

fn create_help_and_version(&mut self) {
pub fn create_help_and_version(&mut self) {
debugln!("fn=create_help_and_version;");
// name is "hclap_help" because flags are sorted by name
if !self.flags.iter().any(|a| a.long.is_some() && a.long.unwrap() == "help") {
if self.is_set(AppSettings::NeedsLongHelp) {
debugln!("Building --help");
if self.help_short.is_none() && !self.short_list.contains(&'h') {
self.help_short = Some('h');
Expand All @@ -892,7 +986,7 @@ impl<'a, 'b> Parser<'a, 'b>
self.flags.push(arg);
}
if !self.settings.is_set(AppSettings::DisableVersion) &&
!self.flags.iter().any(|a| a.long.is_some() && a.long.unwrap() == "version") {
self.is_set(AppSettings::NeedsLongVersion) {
debugln!("Building --version");
if self.version_short.is_none() && !self.short_list.contains(&'V') {
self.version_short = Some('V');
Expand All @@ -908,10 +1002,7 @@ impl<'a, 'b> Parser<'a, 'b>
self.long_list.push("version");
self.flags.push(arg);
}
if !self.subcommands.is_empty() &&
!self.subcommands
.iter()
.any(|s| &s.p.meta.name[..] == "help") {
if !self.subcommands.is_empty() && self.is_set(AppSettings::NeedsSubcommandHelp) {
debugln!("Building help");
self.subcommands
.push(App::new("help")
Expand Down Expand Up @@ -1516,9 +1607,10 @@ impl<'a, 'b> Parser<'a, 'b>
.iter()
.fold(String::new(), |a, s| a + &format!(" {}", s)[..]);

if self.has_flags() && !self.is_set(AppSettings::UnifiedHelpMessage) {
let flags = self.needs_flags_tag();
if flags && !self.is_set(AppSettings::UnifiedHelpMessage) {
usage.push_str(" [FLAGS]");
} else {
} else if flags {
usage.push_str(" [OPTIONS]");
}
if !self.is_set(AppSettings::UnifiedHelpMessage) && self.has_opts() &&
Expand All @@ -1538,14 +1630,8 @@ impl<'a, 'b> Parser<'a, 'b>
}
if self.has_positionals() &&
self.positionals.values().any(|a| !a.settings.is_set(ArgSettings::Required)) {
if self.positionals.len() == 1 {
let p = self.positionals.values().next().expect(INTERNAL_ERROR_MSG);
if !self.groups.values().any(|g| g.args.iter().any(|a| a == &p.name)) {
usage.push_str(&*format!(" [{}]{}", p.name_no_brackets(),
p.multiple_str()));
} else {
usage.push_str(" [ARGS]");
}
if let Some(args_tag) = self.get_args_tag() {
usage.push_str(&*args_tag);
} else {
usage.push_str(" [ARGS]");
}
Expand Down
2 changes: 1 addition & 1 deletion tests/app_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ Kevin K.
tests stuff
USAGE:
test [FLAGS] [OPTIONS] [arg1]
test [OPTIONS] [arg1]
FLAGS:
-h, --help Prints help information
Expand Down
4 changes: 2 additions & 2 deletions tests/groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ fn req_group_usage_string() {
<base|--delete>
USAGE:
clap-test [FLAGS] <base|--delete> [ARGS]
clap-test <base|--delete>
For more information try --help", true);

Expand Down Expand Up @@ -179,4 +179,4 @@ fn group_multiple_args_error() {
let err = result.unwrap_err();
assert_eq!(err.kind, ErrorKind::ArgumentConflict);

}
}
2 changes: 1 addition & 1 deletion tests/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ clap-test v1.4.8
tests clap library
USAGE:
clap-test [FLAGS]
clap-test
FLAGS:
-h, --help Prints help information
Expand Down
10 changes: 5 additions & 5 deletions tests/positionals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,13 @@ fn default_values_user_value() {
#[test]
fn single_positional_usage_string() {
let m = App::new("test").arg_from_usage("[FILE] 'some file'").get_matches_from(vec!["test"]);
assert_eq!(m.usage(), "USAGE:\n test [FLAGS] [FILE]");
assert_eq!(m.usage(), "USAGE:\n test [FILE]");
}

#[test]
fn single_positional_multiple_usage_string() {
let m = App::new("test").arg_from_usage("[FILE]... 'some file'").get_matches_from(vec!["test"]);
assert_eq!(m.usage(), "USAGE:\n test [FLAGS] [FILE]...");
assert_eq!(m.usage(), "USAGE:\n test [FILE]...");
}

#[test]
Expand All @@ -195,7 +195,7 @@ fn multiple_positional_usage_string() {
.arg_from_usage("[FILE] 'some file'")
.arg_from_usage("[FILES]... 'some file'")
.get_matches_from(vec!["test"]);
assert_eq!(m.usage(), "USAGE:\n test [FLAGS] [ARGS]");
assert_eq!(m.usage(), "USAGE:\n test [ARGS]");
}

#[test]
Expand All @@ -204,13 +204,13 @@ fn multiple_positional_one_required_usage_string() {
.arg_from_usage("<FILE> 'some file'")
.arg_from_usage("[FILES]... 'some file'")
.get_matches_from(vec!["test", "file"]);
assert_eq!(m.usage(), "USAGE:\n test [FLAGS] <FILE> [ARGS]");
assert_eq!(m.usage(), "USAGE:\n test <FILE> [ARGS]");
}

#[test]
fn single_positional_required_usage_string() {
let m = App::new("test")
.arg_from_usage("<FILE> 'some file'")
.get_matches_from(vec!["test", "file"]);
assert_eq!(m.usage(), "USAGE:\n test [FLAGS] <FILE>");
assert_eq!(m.usage(), "USAGE:\n test <FILE>");
}
6 changes: 3 additions & 3 deletions tests/subcommands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use clap::{App, Arg, SubCommand, ErrorKind};
static VISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6
USAGE:
clap-test [FLAGS] [SUBCOMMAND]
clap-test [SUBCOMMAND]
FLAGS:
-h, --help Prints help information
Expand All @@ -21,7 +21,7 @@ SUBCOMMANDS:
static INVISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6
USAGE:
clap-test [FLAGS] [SUBCOMMAND]
clap-test [SUBCOMMAND]
FLAGS:
-h, --help Prints help information
Expand Down Expand Up @@ -150,4 +150,4 @@ fn invisible_aliases_help_output() {
.about("Some help")
.alias("invisible"));
test::check_help(app, INVISIBLE_ALIAS_HELP);
}
}

0 comments on commit 16c693a

Please sign in to comment.