aboutsummaryrefslogtreecommitdiff
path: root/helix-tui
diff options
context:
space:
mode:
authorPascal Kuthe2023-03-30 15:31:54 +0000
committerBlaž Hrastnik2023-03-31 06:19:22 +0000
commit67783ddfd4fc7f06bd6addaa6d65d49759934ace (patch)
tree3c0c7323834fa21421ea316a5ce18d8783cd2e1b /helix-tui
parente72be529968071abcd5fce1d9a06e8e2e2bbaacf (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')
-rw-r--r--helix-tui/src/buffer.rs60
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) {