Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(line): line truncation respects alignment #987

Merged
merged 9 commits into from
Mar 31, 2024
93 changes: 86 additions & 7 deletions src/text/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,40 @@
pub fn iter_mut(&mut self) -> std::slice::IterMut<Span<'a>> {
self.spans.iter_mut()
}

/// Returns a line that's truncated corresponding to it's alignment and result width
#[must_use = "method moves the value of self and returns the modified value"]
joshka marked this conversation as resolved.
Show resolved Hide resolved
pub fn truncated(&'a self, result_width: u16) -> Self {
let mut truncated_line = Line::default();
let width = self.width() as u16;
let mut offset = match self.alignment {
Some(Alignment::Center) => (width.saturating_sub(result_width)) / 2,
Some(Alignment::Right) => width.saturating_sub(result_width),
_ => 0,
};
let mut x = 0;
for span in &self.spans {
let span_width = span.width() as u16;
if offset >= span_width {
offset -= span_width;
continue;

Check warning on line 470 in src/text/line.rs

View check run for this annotation

Codecov / codecov/patch

src/text/line.rs#L469-L470

Added lines #L469 - L470 were not covered by tests
TadoTheMiner marked this conversation as resolved.
Show resolved Hide resolved
}
let mut new_span = span.clone();
let new_span_width = span_width - offset;
if x + new_span_width > result_width {
new_span.content =
Cow::from(&span.content[offset as usize..(result_width - x + offset) as usize]);
TadoTheMiner marked this conversation as resolved.
Show resolved Hide resolved
truncated_line.spans.push(new_span);
break;
}

new_span.content = Cow::from(&span.content[offset as usize..]);
truncated_line.spans.push(new_span);
x += new_span_width;
offset = 0;
}
truncated_line
}
}

impl<'a> IntoIterator for Line<'a> {
Expand Down Expand Up @@ -536,17 +570,23 @@
let area = area.intersection(buf.area);
buf.set_style(area, self.style);
let width = self.width() as u16;
let offset = match self.alignment {
Some(Alignment::Center) => (area.width.saturating_sub(width)) / 2,
Some(Alignment::Right) => area.width.saturating_sub(width),
Some(Alignment::Left) | None => 0,
let mut x = area.left();
let line = if width > area.width {
self.truncated(area.width)
} else {
let offset = match self.alignment {
Some(Alignment::Center) => (area.width.saturating_sub(width)) / 2,
Some(Alignment::Right) => area.width.saturating_sub(width),
Some(Alignment::Left) | None => 0,
};
x = x.saturating_add(offset);
self.to_owned()
};
let mut x = area.left().saturating_add(offset);
for span in &self.spans {
for span in &line.spans {
let span_width = span.width() as u16;
let span_area = Rect {
x,
width: span_width.min(area.right() - x),
width: span_width.min(area.right().saturating_sub(x)),
..area
};
span.render(span_area, buf);
Expand Down Expand Up @@ -586,6 +626,7 @@
use rstest::{fixture, rstest};

use super::*;
use crate::assert_buffer_eq;

#[test]
fn raw_str() {
Expand Down Expand Up @@ -824,6 +865,44 @@

assert_eq!(format!("{line_from_styled_span}"), "Hello, world!");
}
#[test]
fn render_truncates_left() {
let mut buf = Buffer::empty(Rect::new(0, 0, 5, 1));
Line::from("Hello world")
.left_aligned()
.render(buf.area, &mut buf);
let expected = Buffer::with_lines(vec!["Hello"]);
assert_buffer_eq!(buf, expected);

Check warning on line 875 in src/text/line.rs

View check run for this annotation

Codecov / codecov/patch

src/text/line.rs#L875

Added line #L875 was not covered by tests
}

#[test]
fn render_truncates_right() {
let mut buf = Buffer::empty(Rect::new(0, 0, 5, 1));
Line::from("Hello world")
.right_aligned()
.render(buf.area, &mut buf);
let expected = Buffer::with_lines(vec!["world"]);
assert_buffer_eq!(buf, expected);

Check warning on line 885 in src/text/line.rs

View check run for this annotation

Codecov / codecov/patch

src/text/line.rs#L885

Added line #L885 was not covered by tests
}

#[test]
fn render_truncates_center() {
let mut buf = Buffer::empty(Rect::new(0, 0, 5, 1));
Line::from("Hello world")
.centered()
.render(buf.area, &mut buf);
let expected = Buffer::with_lines(vec!["lo wo"]);
assert_buffer_eq!(buf, expected);

Check warning on line 895 in src/text/line.rs

View check run for this annotation

Codecov / codecov/patch

src/text/line.rs#L895

Added line #L895 was not covered by tests
}

#[test]
fn truncate_line_with_multiple_spans() {
let line = Line::default().spans(vec!["foo", "bar"]);
assert_eq!(
line.right_aligned().truncated(4).to_string(),
String::from("obar")
);
}

mod widget {
use super::*;
Expand Down