From 1f4da7676e6e71aa8dda799f3eeefad105a47819 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Mon, 13 Jun 2016 22:03:27 -0400 Subject: [PATCH] fix(Help): `App::before_help` and `App::after_help` now correctly wrap `before_help` and `after_help` weren't wrapping at the either the specified terminal width, or auto determined one. That is now fixed. Closes #516 --- src/app/help.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/src/app/help.rs b/src/app/help.rs index 9e8a7303cc2..b77e47539d8 100644 --- a/src/app/help.rs +++ b/src/app/help.rs @@ -327,6 +327,89 @@ impl<'a> Help<'a> { Ok(()) } + fn write_before_after_help<'b, 'c>(&mut self, h: &str) -> io::Result<()> { + debugln!("fn=before_help;"); + let mut help = String::new(); + // determine if our help fits or needs to wrap + let width = self.term_w; + debugln!("Term width...{}", width); + let too_long = str_width(h) >= width; + debugln!("Too long...{:?}", too_long); + + debug!("Too long..."); + if too_long { + sdebugln!("Yes"); + help.push_str(h); + debugln!("help: {}", help); + debugln!("help width: {}", str_width(&*help)); + // Determine how many newlines we need to insert + debugln!("Usable space: {}", width); + let longest_w = { + let mut lw = 0; + for l in help.split(' ').map(|s| str_width(s)) { + if l > lw { + lw = l; + } + } + lw + }; + debugln!("Longest word...{}", longest_w); + debug!("Enough space to wrap..."); + if longest_w < width { + sdebugln!("Yes"); + let mut indices = vec![]; + let mut idx = 0; + loop { + idx += width - 1; + if idx >= help.len() { + break; + } + // 'a' arbitrary non space char + if help.chars().nth(idx).unwrap_or('a') != ' ' { + idx = find_idx_of_space(&*help, idx); + } + debugln!("Adding idx: {}", idx); + debugln!("At {}: {:?}", idx, help.chars().nth(idx)); + indices.push(idx); + if str_width(&help[idx..]) <= width { + break; + } + } + for (i, idx) in indices.iter().enumerate() { + debugln!("iter;i={},idx={}", i, idx); + let j = idx + (2 * i); + debugln!("removing: {}", j); + debugln!("at {}: {:?}", j, help.chars().nth(j)); + help.remove(j); + help.insert(j, '{'); + help.insert(j + 1, 'n'); + help.insert(j + 2, '}'); + } + } else { + sdebugln!("No"); + } + } else { + sdebugln!("No"); + } + let help = if !help.is_empty() { + &*help + } else { + help.push_str(h); + &*help + }; + if help.contains("{n}") { + if let Some(part) = help.split("{n}").next() { + try!(write!(self.writer, "{}", part)); + } + for part in help.split("{n}").skip(1) { + try!(write!(self.writer, "\n{}", part)); + } + } else { + try!(write!(self.writer, "{}", help)); + } + Ok(()) + } + /// Writes argument's help to the wrapped stream. fn help<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>, longest: usize) -> io::Result<()> { debugln!("fn=help;"); @@ -605,7 +688,7 @@ impl<'a> Help<'a> { pub fn write_default_help(&mut self, parser: &Parser) -> ClapResult<()> { debugln!("fn=write_default_help;"); if let Some(h) = parser.meta.pre_help { - try!(write!(self.writer, "{}", h)); + try!(self.write_before_after_help(h)); try!(self.writer.write(b"\n\n")); } @@ -640,7 +723,7 @@ impl<'a> Help<'a> { if flags || opts || pos || subcmds { try!(self.writer.write(b"\n\n")); } - try!(write!(self.writer, "{}", h)); + try!(self.write_before_after_help(h)); } self.writer.flush().map_err(Error::from)