From 575ebdbd01510bd023e1d78a102c836e66e9f1d6 Mon Sep 17 00:00:00 2001 From: chris west Date: Thu, 14 May 2020 14:56:49 -0700 Subject: [PATCH] ignore colors when calculating line length --- src/menu.rs | 47 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/menu.rs b/src/menu.rs index 3ceeb3a..7b897a8 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -66,6 +66,12 @@ pub struct Line { /// Where the text/label of this line ends. Might be the same as /// `end`, or might be earlier. text_end: usize, + /// Length of visible text, ignoring ANSI escape codes (colors). + visible_len: usize, + /// How many chars() to grab from text() if we want to only show + /// `MAX_COLS` visible chars on screen, aka ignore ANSI escape + /// codes and colors. + truncated_len: usize, /// Index of this link in the Menu::links vector, if it's a /// `gopher::Type.is_link()` pub link: usize, @@ -84,11 +90,7 @@ impl Line { /// Get the length of this line's text field. pub fn text_len(&self) -> usize { - if self.text_end > self.start { - self.text_end - self.start - } else { - 0 - } + self.visible_len } /// Get the URL for this line, if it's a link. @@ -304,7 +306,11 @@ impl Menu { } // truncate long lines, instead of wrapping - let text = line.text(&self.raw).chars().take(MAX_COLS).collect::(); + let text = line + .text(&self.raw) + .chars() + .take(line.truncated_len) + .collect::(); // color the line if line.typ.is_download() { @@ -911,10 +917,39 @@ pub fn parse_line(start: usize, raw: &str) -> Option { }; let typ = Type::from(line.chars().nth(0)?)?; + // calculate the visible length of this line as well as where to + // truncate it when abiding by `MAX_COLS` + let mut is_color = false; + let mut truncated_len = 0; + let mut visible_len = 0; + let mut iter = raw[start..text_end].char_indices().peekable(); + + while let Some((i, c)) = iter.next() { + if is_color { + if c == 'm' { + is_color = false; + } + } else { + if c == '\x1b' { + if let Some((_, '[')) = iter.peek() { + iter.next(); // skip [ + is_color = true; + } + } else { + if visible_len < MAX_COLS { + truncated_len = i; + } + visible_len += 1; + } + } + } + Some(Line { start, end, text_end, + truncated_len, + visible_len, typ, link: 0, })