From 1f33de545036e7fd2f80faba251fca009bd519b8 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Mon, 2 Jan 2017 15:05:40 -0500 Subject: [PATCH 1/3] imp(Default Values): improves the error message when default values are involved Closes #774 --- src/app/parser.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/parser.rs b/src/app/parser.rs index c7de9346..bbc4152f 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -313,7 +313,7 @@ impl<'a, 'b> Parser<'a, 'b> reqs: &[&'a str], matcher: Option<&ArgMatcher<'a>>) -> VecDeque { - debugln!("Parser::get_required_from;"); + debugln!("Parser::get_required_from; reqs={:?}", reqs); let mut c_flags: Vec<&str> = vec![]; let mut c_pos: Vec<&str> = vec![]; let mut c_opt: Vec<&str> = vec![]; @@ -994,15 +994,15 @@ impl<'a, 'b> Parser<'a, 'b> } } - try!(self.add_defaults(matcher)); try!(self.validate_blacklist(matcher)); - try!(self.validate_matched_args(matcher)); - matcher.usage(self.create_usage(&[])); - if !(self.settings.is_set(AppSettings::SubcommandsNegateReqs) && subcmd_name.is_some()) && !reqs_validated { try!(self.validate_required(matcher)); } + try!(self.add_defaults(matcher)); + try!(self.validate_matched_args(matcher)); + matcher.usage(self.create_usage(&[])); + if matcher.is_empty() && matcher.subcommand_name().is_none() && self.is_set(AppSettings::ArgRequiredElseHelp) { let mut out = vec![]; From ad4691b71a63e951ace346318238d8834e04ad8a Mon Sep 17 00:00:00 2001 From: Kevin K Date: Mon, 2 Jan 2017 16:43:45 -0500 Subject: [PATCH 2/3] feat(Help Wrapping): long app names (with spaces), authors, and descriptions are now wrapped appropriately Closes #777 --- src/app/help.rs | 58 ++++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/src/app/help.rs b/src/app/help.rs index c308abfb..1947d190 100644 --- a/src/app/help.rs +++ b/src/app/help.rs @@ -24,6 +24,18 @@ mod term_size { pub fn dimensions() -> Option<(usize, usize)> { None } } +macro_rules! find_longest { + ($help:expr) => {{ + let mut lw = 0; + for l in $help.split(' ').map(|s| str_width(s)) { + if l > lw { + lw = l; + } + } + lw + }}; +} + fn str_width(s: &str) -> usize { UnicodeWidthStr::width(s) } const TAB: &'static str = " "; @@ -383,15 +395,7 @@ impl<'a> Help<'a> { debugln!("Help::write_before_after_help: help width: {}", str_width(&*help)); // Determine how many newlines we need to insert debugln!("Help::write_before_after_help: Usable space: {}", self.term_w); - let longest_w = { - let mut lw = 0; - for l in help.split(' ').map(|s| str_width(s)) { - if l > lw { - lw = l; - } - } - lw - }; + let longest_w = find_longest!(help); help = help.replace("{n}", "\n"); wrap_help(&mut help, longest_w, self.term_w); } else { @@ -447,15 +451,7 @@ impl<'a> Help<'a> { // Determine how many newlines we need to insert let avail_chars = self.term_w - spcs; debugln!("Help::help: Usable space...{}", avail_chars); - let longest_w = { - let mut lw = 0; - for l in help.split(' ').map(|s| str_width(s)) { - if l > lw { - lw = l; - } - } - lw - }; + let longest_w = find_longest!(help); help = help.replace("{n}", "\n"); wrap_help(&mut help, longest_w, avail_chars); } else { @@ -630,15 +626,24 @@ impl<'a> Help<'a> { /// Writes binary name of a Parser Object to the wrapped stream. fn write_bin_name(&mut self, parser: &Parser) -> io::Result<()> { debugln!("Help::write_bin_name;"); + macro_rules! write_name { + () => {{ + let mut name = parser.meta.name.clone(); + let longest_w = find_longest!(name); + name = name.replace("{n}", "\n"); + wrap_help(&mut name, longest_w, self.term_w); + try!(color!(self, &*name, good)); + }}; + } if let Some(bn) = parser.meta.bin_name.as_ref() { if bn.contains(' ') { // Incase we're dealing with subcommands i.e. git mv is translated to git-mv try!(color!(self, bn.replace(" ", "-"), good)) } else { - try!(color!(self, &parser.meta.name[..], good)) + write_name!(); } } else { - try!(color!(self, &parser.meta.name[..], good)) + write_name!(); } Ok(()) } @@ -651,16 +656,25 @@ impl<'a> Help<'a> { try!(self.writer.write(b"\n\n")); } + macro_rules! write_thing { + ($thing:expr) => {{ + let mut owned_thing = $thing.to_owned(); + let longest_w = find_longest!(owned_thing); + owned_thing = owned_thing.replace("{n}", "\n"); + wrap_help(&mut owned_thing, longest_w, self.term_w); + try!(write!(self.writer, "{}\n", &*owned_thing)) + }}; + } // Print the version try!(self.write_bin_name(&parser)); try!(self.writer.write(b" ")); try!(self.write_version(&parser)); try!(self.writer.write(b"\n")); if let Some(author) = parser.meta.author { - try!(write!(self.writer, "{}\n", author)); + write_thing!(author) } if let Some(about) = parser.meta.about { - try!(write!(self.writer, "{}\n", about)); + write_thing!(about) } try!(color!(self, "\nUSAGE:", warning)); From fc3800b83015181609968c5bf44c95f320c64b66 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Mon, 2 Jan 2017 16:44:40 -0500 Subject: [PATCH 3/3] tests: adds tests for wrapping meta help items --- tests/help.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/help.rs b/tests/help.rs index 27beed76..2a4f9cf9 100644 --- a/tests/help.rs +++ b/tests/help.rs @@ -193,6 +193,23 @@ ARGS: some option ... some option"; +static ISSUE_777: &'static str = "A app with a crazy very long long +long name hahaha 1.0 +Some Very Long Name and crazy long +email +Show how the about text is not +wrapped + +USAGE: + ctest + +FLAGS: + -h, --help + Prints help information + -V, --version + Prints version + information"; + #[test] fn help_short() { let m = App::new("test") @@ -486,4 +503,14 @@ fn issue_760() { .long("opt") .takes_value(true)); test::check_err_output(app, "ctest --help", ISSUE_760, false); +} + +#[test] +fn issue_777_wrap_all_things() { + let app = App::new("A app with a crazy very long long long name hahaha") + .version("1.0") + .author("Some Very Long Name and crazy long email ") + .about("Show how the about text is not wrapped") + .set_term_width(35); + test::check_err_output(app, "ctest --help", ISSUE_777, false); } \ No newline at end of file