diff options
author | Pascal Kuthe | 2023-03-30 15:31:54 +0000 |
---|---|---|
committer | Blaž Hrastnik | 2023-03-31 06:19:22 +0000 |
commit | 67783ddfd4fc7f06bd6addaa6d65d49759934ace (patch) | |
tree | 3c0c7323834fa21421ea316a5ce18d8783cd2e1b /helix-tui/src/buffer.rs | |
parent | e72be529968071abcd5fce1d9a06e8e2e2bbaacf (diff) |
Performant and correct set_spans_truncated
the previous implementation used set_string_truncated. This is not only
awkward with this kind of "streaming" string (and therefore lead to an
inefficient and incorrect initial implementation) but that function also
truncates strings of width 1 when there is only a single char available.
The implementation here is performant, correct and also handles the
single width case correctly.
Diffstat (limited to 'helix-tui/src/buffer.rs')
-rw-r--r-- | helix-tui/src/buffer.rs | 60 |
1 files changed, 38 insertions, 22 deletions
diff --git a/helix-tui/src/buffer.rs b/helix-tui/src/buffer.rs index 2c212b12..8e0b0adf 100644 --- a/helix-tui/src/buffer.rs +++ b/helix-tui/src/buffer.rs @@ -434,28 +434,44 @@ impl Buffer { } pub fn set_spans_truncated(&mut self, x: u16, y: u16, spans: &Spans, width: u16) -> (u16, u16) { - let mut remaining_width = width; - let mut alt_x = x; - let (text, styles) = - spans - .0 - .iter() - .fold((String::new(), vec![]), |(mut s, mut h), span| { - s.push_str(span.content.as_ref()); - let mut styles = span - .styled_graphemes(span.style) - .map(|grapheme| grapheme.style) - .collect(); - h.append(&mut styles); - - let w = span.width() as u16; - alt_x = alt_x + w; - remaining_width = remaining_width.saturating_sub(w); - - (s, h) - }); - self.set_string_truncated(x, y, &text, width.into(), |idx| styles[idx], true, true); - (x, y) + // prevent panic if out of range + if !self.in_bounds(x, y) || width == 0 { + return (x, y); + } + + let mut x_offset = x as usize; + let max_offset = min(self.area.right(), width.saturating_add(x)); + let mut start_index = self.index_of(x, y); + let mut index = self.index_of(max_offset as u16, y); + + let content_width = spans.width(); + let truncated = content_width > width as usize; + if truncated { + self.content[start_index].set_symbol("…"); + start_index += 1; + } else { + index -= width as usize - content_width; + } + for span in spans.0.iter().rev() { + for s in span.content.graphemes(true).rev() { + let width = s.width(); + if width == 0 { + continue; + } + let start = index - width; + if start < start_index { + break; + } + self.content[start].set_symbol(s); + self.content[start].set_style(span.style); + for i in start + 1..index { + self.content[i].reset(); + } + index -= width; + x_offset += width; + } + } + (x_offset as u16, y) } pub fn set_spans(&mut self, x: u16, y: u16, spans: &Spans, width: u16) -> (u16, u16) { |