From e1e06633c7de0e97a33a0bfb1f9075f1e9d5460f Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Sun, 8 Mar 2015 12:18:22 -0700 Subject: [PATCH] Added option to maintain indentation when wrapping lines. Currently only exposed in code, not in UI. Enabled by default. --- src/string_utils.rs | 32 ++++++++++++++++++++++ src/term_ui/formatter.rs | 59 ++++++++++++++++++++++++++++------------ 2 files changed, 74 insertions(+), 17 deletions(-) diff --git a/src/string_utils.rs b/src/string_utils.rs index 4aa7f42..0613ec0 100644 --- a/src/string_utils.rs +++ b/src/string_utils.rs @@ -19,6 +19,38 @@ pub fn is_line_ending(text: &str) -> bool { } } +pub fn is_whitespace(text: &str) -> bool { + // TODO: this is a naive categorization of whitespace characters. + // For better categorization these should be split up into groups + // based on e.g. breaking vs non-breaking spaces, among other things. + match text { + "\u{0020}" // SPACE + | "\u{0009}" // CHARACTER TABULATION + | "\u{00A0}" // NO-BREAK SPACE + //| "\u{1680}" // OGHAM SPACE MARK (here for completeness, but usually displayed as a dash, not as whitespace) + | "\u{180E}" // MONGOLIAN VOWEL SEPARATOR + | "\u{2000}" // EN QUAD + | "\u{2001}" // EM QUAD + | "\u{2002}" // EN SPACE + | "\u{2003}" // EM SPACE + | "\u{2004}" // THREE-PER-EM SPACE + | "\u{2005}" // FOUR-PER-EM SPACE + | "\u{2006}" // SIX-PER-EM SPACE + | "\u{2007}" // FIGURE SPACE + | "\u{2008}" // PUNCTUATION SPACE + | "\u{2009}" // THIN SPACE + | "\u{200A}" // HAIR SPACE + | "\u{200B}" // ZERO WIDTH SPACE + | "\u{202F}" // NARROW NO-BREAK SPACE + | "\u{205F}" // MEDIUM MATHEMATICAL SPACE + | "\u{3000}" // IDEOGRAPHIC SPACE + | "\u{FEFF}" // ZERO WIDTH NO-BREAK SPACE + => true, + + _ => false + } +} + pub fn line_ending_count(text: &str) -> usize { let mut count = 0; for g in text.graphemes(true) { diff --git a/src/term_ui/formatter.rs b/src/term_ui/formatter.rs index 0d85da5..1953414 100644 --- a/src/term_ui/formatter.rs +++ b/src/term_ui/formatter.rs @@ -1,6 +1,6 @@ use std::cmp::max; -use string_utils::{is_line_ending}; +use string_utils::{is_line_ending, is_whitespace}; use formatter::{LineFormatter, RoundingBehavior}; pub enum WrapType { @@ -25,7 +25,7 @@ impl ConsoleLineFormatter { ConsoleLineFormatter { tab_width: tab_width, wrap_type: WrapType::CharWrap(40), - maintain_indent: false, + maintain_indent: true, } } @@ -51,6 +51,8 @@ impl ConsoleLineFormatter { grapheme_iter: g_iter, f: self, pos: (0, 0), + indent: 0, + indent_found: false, } } } @@ -131,6 +133,8 @@ where T: Iterator grapheme_iter: T, f: &'a ConsoleLineFormatter, pos: (usize, usize), + indent: usize, + indent_found: bool, } @@ -160,11 +164,32 @@ where T: Iterator let width = grapheme_vis_width_at_vis_pos(g, self.pos.1, self.f.tab_width as usize); if (self.pos.1 + width) > wrap_width { - let pos = (self.pos.0 + self.f.single_line_height(), 0); - self.pos = (self.pos.0 + self.f.single_line_height(), width); - return Some((g, pos, width)); + if !self.indent_found { + self.indent = 0; + self.indent_found = true; + } + + if self.f.maintain_indent { + let pos = (self.pos.0 + self.f.single_line_height(), self.indent); + self.pos = (self.pos.0 + self.f.single_line_height(), self.indent + width); + return Some((g, pos, width)); + } + else { + let pos = (self.pos.0 + self.f.single_line_height(), 0); + self.pos = (self.pos.0 + self.f.single_line_height(), width); + return Some((g, pos, width)); + } } else { + if !self.indent_found { + if is_whitespace(g) { + self.indent += width; + } + else { + self.indent_found = true; + } + } + let pos = self.pos; self.pos = (self.pos.0, self.pos.1 + width); return Some((g, pos, width)); @@ -225,7 +250,7 @@ mod tests { fn dimensions_1() { let text = "Hello there, stranger!"; // 22 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 80; + f.set_wrap_width(80); assert_eq!(f.dimensions(text.graphemes(true)), (1, 22)); } @@ -235,7 +260,7 @@ mod tests { fn dimensions_2() { let text = "Hello there, stranger! How are you doing this fine day?"; // 56 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 12; + f.set_wrap_width(12); assert_eq!(f.dimensions(text.graphemes(true)), (5, 12)); } @@ -245,7 +270,7 @@ mod tests { fn index_to_v2d_1() { let text = "Hello there, stranger!"; // 22 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 80; + f.set_wrap_width(80); assert_eq!(f.index_to_v2d(text.graphemes(true), 0), (0, 0)); assert_eq!(f.index_to_v2d(text.graphemes(true), 5), (0, 5)); @@ -258,7 +283,7 @@ mod tests { fn index_to_v2d_2() { let text = "Hello there, stranger! How are you doing this fine day?"; // 56 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 12; + f.set_wrap_width(12); assert_eq!(f.index_to_v2d(text.graphemes(true), 0), (0, 0)); assert_eq!(f.index_to_v2d(text.graphemes(true), 5), (0, 5)); @@ -288,7 +313,7 @@ mod tests { fn v2d_to_index_1() { let text = "Hello there, stranger!"; // 22 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 80; + f.set_wrap_width(80); assert_eq!(f.v2d_to_index(text.graphemes(true), (0,0), (Floor, Floor)), 0); assert_eq!(f.v2d_to_index(text.graphemes(true), (0,5), (Floor, Floor)), 5); @@ -303,7 +328,7 @@ mod tests { fn v2d_to_index_2() { let text = "Hello there, stranger! How are you doing this fine day?"; // 56 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 12; + f.set_wrap_width(12); assert_eq!(f.v2d_to_index(text.graphemes(true), (0,0), (Floor, Floor)), 0); assert_eq!(f.v2d_to_index(text.graphemes(true), (0,11), (Floor, Floor)), 11); @@ -332,7 +357,7 @@ mod tests { fn index_to_horizontal_v2d_1() { let b = Buffer::new_from_str("Hello there, stranger!\nHow are you doing this fine day?"); // 55 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 80; + f.set_wrap_width(80); assert_eq!(f.index_to_horizontal_v2d(&b, 0), 0); assert_eq!(f.index_to_horizontal_v2d(&b, 5), 5); @@ -346,7 +371,7 @@ mod tests { fn index_to_horizontal_v2d_2() { let b = Buffer::new_from_str("Hello there, stranger!\nHow are you doing this fine day?"); // 55 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 12; + f.set_wrap_width(12); assert_eq!(f.index_to_horizontal_v2d(&b, 0), 0); assert_eq!(f.index_to_horizontal_v2d(&b, 11), 11); @@ -370,7 +395,7 @@ mod tests { fn index_set_horizontal_v2d_1() { let b = Buffer::new_from_str("Hello there, stranger!\nHow are you doing this fine day?"); // 55 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 80; + f.set_wrap_width(80); assert_eq!(f.index_set_horizontal_v2d(&b, 0, 0, Floor), 0); assert_eq!(f.index_set_horizontal_v2d(&b, 0, 22, Floor), 22); @@ -402,7 +427,7 @@ mod tests { fn index_set_horizontal_v2d_2() { let b = Buffer::new_from_str("Hello there, stranger! How are you doing this fine day?"); // 55 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 12; + f.set_wrap_width(12); assert_eq!(f.index_set_horizontal_v2d(&b, 0, 0, Floor), 0); assert_eq!(f.index_set_horizontal_v2d(&b, 0, 11, Floor), 11); @@ -434,7 +459,7 @@ mod tests { fn index_offset_vertical_v2d_1() { let b = Buffer::new_from_str("Hello there, stranger!\nHow are you doing this fine day?"); // 55 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 80; + f.set_wrap_width(80); assert_eq!(f.index_offset_vertical_v2d(&b, 0, 0, (Floor, Floor)), 0); assert_eq!(f.index_offset_vertical_v2d(&b, 0, 1, (Floor, Floor)), 23); @@ -458,7 +483,7 @@ mod tests { fn index_offset_vertical_v2d_2() { let b = Buffer::new_from_str("Hello there, stranger! How are you doing this fine day?"); // 55 graphemes long let mut f = ConsoleLineFormatter::new(4); - f.wrap_width = 12; + f.set_wrap_width(12); assert_eq!(f.index_offset_vertical_v2d(&b, 0, 0, (Floor, Floor)), 0); assert_eq!(f.index_offset_vertical_v2d(&b, 0, 1, (Floor, Floor)), 12);