diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7e2c98d6..cf2c45e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,13 @@
+
+### v2.10.4 (2016-08-25)
+
+
+#### Bug Fixes
+
+* **Help Wrapping:** fixes a bug where help is wrapped incorrectly and causing a panic with some non-English characters ([d0b442c7](https://github.com/kbknapp/clap-rs/commit/d0b442c7beeecac9764406bc3bd171ced0b8825e), closes [#626](https://github.com/kbknapp/clap-rs/issues/626))
+
+
+
### v2.10.3 (2016-08-25)
diff --git a/Cargo.toml b/Cargo.toml
index 9dfa66ec..f86a5edf 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "clap"
-version = "2.10.3"
+version = "2.10.4"
authors = ["Kevin K. "]
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
description = "A simple to use, efficient, and full featured Command Line Argument Parser"
diff --git a/README.md b/README.md
index ac315bbb..933f460b 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,10 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
## What's New
+Here's the highlights for v2.10.4
+
+* Fixes a bug where help is wrapped incorrectly and causing a panic with some non-English characters
+
Here's the highlights for v2.10.3
* Fixes a bug with non-English characters in help text wrapping, where the character is stripped or causes a panic
diff --git a/src/app/help.rs b/src/app/help.rs
index f5858d8e..dc949fae 100644
--- a/src/app/help.rs
+++ b/src/app/help.rs
@@ -25,7 +25,7 @@ mod term_size {
use unicode_width::UnicodeWidthStr;
-use strext::_StrExt;
+// use strext::_StrExt;
fn str_width(s: &str) -> usize {
UnicodeWidthStr::width(s)
@@ -336,7 +336,6 @@ impl<'a> Help<'a> {
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 {
@@ -355,41 +354,7 @@ impl<'a> Help<'a> {
}
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");
- }
+ wrap_help(&mut help, longest_w, width);
} else {
sdebugln!("No");
}
@@ -427,7 +392,7 @@ impl<'a> Help<'a> {
let width = self.term_w;
debugln!("Term width...{}", width);
let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= width;
- debugln!("Too long...{:?}", too_long);
+ debugln!("Spaces: {}", spcs);
// Is help on next line, if so newline + 2x tab
if self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) {
@@ -435,7 +400,7 @@ impl<'a> Help<'a> {
}
debug!("Too long...");
- if too_long {
+ if too_long && spcs <= width {
sdebugln!("Yes");
help.push_str(h);
help.push_str(&*spec_vals);
@@ -453,35 +418,7 @@ impl<'a> Help<'a> {
}
lw
};
- debugln!("Longest word...{}", longest_w);
- debug!("Enough space to wrap...");
- if longest_w < avail_chars {
- sdebugln!("Yes");
- let mut prev_space = 0;
- let mut j = 0;
- let mut i = 0;
- for (idx, g) in (&*help.clone()).grapheme_indices(true) {
- debugln!("iter;idx={},g={}", idx, g);
- if g != " " { continue; }
- if str_width(&help[j..idx]) < avail_chars {
- debugln!("Still enough space...");
- prev_space = idx;
- continue;
- }
- debugln!("Adding Newline...");
- j = prev_space + (2 * i);
- debugln!("i={},prev_space={},j={}", i, prev_space, j);
- debugln!("removing: {}", j);
- debugln!("char at {}: {}", j, &help[j..j]);
- help.remove(j);
- help.insert(j, '{');
- help.insert(j + 1, 'n');
- help.insert(j + 2, '}');
- i += 1;
- }
- } else {
- sdebugln!("No");
- }
+ wrap_help(&mut help, longest_w, avail_chars);
} else {
sdebugln!("No");
}
@@ -946,24 +883,34 @@ impl<'a> Help<'a> {
}
}
-
-fn find_idx_of_space(full: &str, mut start: usize) -> usize {
- debugln!("fn=find_idx_of_space;");
- let haystack = if full._is_char_boundary(start) {
- &full[..start]
+fn wrap_help(help: &mut String, longest_w: usize, avail_chars: usize) {
+ debugln!("fn=wrap_help;longest_w={},avail_chars={}", longest_w, avail_chars);
+ debug!("Enough space to wrap...");
+ if longest_w < avail_chars {
+ sdebugln!("Yes");
+ let mut prev_space = 0;
+ let mut j = 0;
+ let mut i = 0;
+ for (idx, g) in (&*help.clone()).grapheme_indices(true) {
+ debugln!("iter;idx={},g={}", idx, g);
+ if g != " " { continue; }
+ if str_width(&help[j..idx + (2 * i)]) < avail_chars {
+ debugln!("Still enough space...");
+ prev_space = idx;
+ continue;
+ }
+ debugln!("Adding Newline...");
+ j = prev_space + (2 * i);
+ debugln!("i={},prev_space={},j={}", i, prev_space, j);
+ debugln!("removing: {}", j);
+ debugln!("char at {}: {}", j, &help[j..j]);
+ help.remove(j);
+ help.insert(j, '{');
+ help.insert(j + 1, 'n');
+ help.insert(j + 2, '}');
+ i += 1;
+ }
} else {
- while !full._is_char_boundary(start) {
- start -= 1;
- }
- &full[..start]
- };
- debugln!("haystack: {}", haystack);
- for (i, c) in haystack.chars().rev().enumerate() {
- debugln!("iter;c={},i={}", c, i);
- if c == ' ' {
- debugln!("Found space returning start-i...{}", start - (i + 1));
- return start - (i + 1);
- }
+ sdebugln!("No");
}
- 0
}
diff --git a/tests/help.rs b/tests/help.rs
index 9077dc97..6fb2670b 100644
--- a/tests/help.rs
+++ b/tests/help.rs
@@ -93,12 +93,13 @@ FLAGS:
OPTIONS:
-c, --cafe A coffeehouse, coffee shop, or café is an
establishment which primarily serves hot
- coffee, related coffee beverages (e.g., café
- latte, cappuccino, espresso), tea, and other
- hot beverages. Some coffeehouses also serve cold
- beverages such as iced coffee and iced tea. Many
- cafés also serve some type of food, such as light
- snacks, muffins, or pastries.";
+ coffee, related coffee beverages (e.g.,
+ café latte, cappuccino, espresso), tea,
+ and other hot beverages. Some
+ coffeehouses also serve cold beverages
+ such as iced coffee and iced tea. Many
+ cafés also serve some type of food, such
+ as light snacks, muffins, or pastries.";
static ISSUE_626_PANIC: &'static str = "ctest 0.1
@@ -110,15 +111,19 @@ FLAGS:
-V, --version Prints version information
OPTIONS:
- -c, --cafe La culture du café est très
- développée dans de
- nombreux pays à climat chaud
- d'Amérique, d'Afrique et
- d'Asie, dans des plantations qui
- sont cultivées pour les marchés
- d'exportation. Le café est souvent
- une contribution majeure aux
- exportations des régions productrices.";
+ -c, --cafe La culture du café est
+ très développée dans de
+ nombreux pays à climat
+ chaud d'Amérique,
+ d'Afrique et d'Asie,
+ dans des plantations
+ qui sont cultivées pour
+ les marchés
+ d'exportation. Le café
+ est souvent une
+ contribution majeure
+ aux exportations des
+ régions productrices.";
#[test]
fn help_short() {
@@ -271,7 +276,7 @@ fn issue_626_unicode_cutoff() {
fn issue_626_panic() {
let app = App::new("ctest")
.version("0.1")
- .set_term_width(53)
+ .set_term_width(52)
.arg(Arg::with_name("cafe")
.short("c")
.long("cafe")
@@ -282,3 +287,21 @@ fn issue_626_panic() {
.takes_value(true));
test::check_err_output(app, "ctest --help", ISSUE_626_PANIC, false);
}
+
+#[test]
+fn issue_626_variable_panic() {
+ for i in 10..320 {
+ let _ = App::new("ctest")
+ .version("0.1")
+ .set_term_width(i)
+ .arg(Arg::with_name("cafe")
+ .short("c")
+ .long("cafe")
+ .value_name("FILE")
+ .help("La culture du café est très développée dans de nombreux pays à climat chaud d'Amérique, \
+ d'Afrique et d'Asie, dans des plantations qui sont cultivées pour les marchés d'exportation. \
+ Le café est souvent une contribution majeure aux exportations des régions productrices.")
+ .takes_value(true))
+ .get_matches_from_safe(vec!["ctest", "--help"]);
+ }
+}