use crate::{
Component,
RenderError,
Rendered,
};
pub struct Text {
text: String,
pad_x: u16,
pad_y: u16,
}
impl Text {
pub fn new(text: impl Into<String>, pad_x: u16, pad_y: u16) -> Self {
Self {
text: text.into(),
pad_x,
pad_y,
}
}
}
impl Component for Text {
fn render(&self, width: u16) -> Result<Rendered, RenderError> {
let mut lines = Vec::new();
let empty_line = " ".repeat(width as usize);
for _ in 0..self.pad_y {
lines.push(empty_line.clone());
}
let pad = " ".repeat(self.pad_x as usize);
for line in self.text.lines() {
let padded = format!("{}{}", pad, line);
let truncated = crate::utils::truncate_to_width(&padded, width, "…");
let vw = crate::utils::visible_width(&truncated);
let mut final_line = truncated;
if vw < width as usize {
final_line.push_str(&" ".repeat(width as usize - vw));
}
lines.push(final_line);
}
for _ in 0..self.pad_y {
lines.push(empty_line.clone());
}
Ok(Rendered {
lines,
cursor: None,
images: Vec::new(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn text_truncates_to_width() {
let text = Text::new("hello world", 0, 0);
let rendered = text.render(5).unwrap();
assert_eq!(rendered.lines.len(), 1);
assert_eq!(rendered.lines[0].trim_end(), "hell…"); }
#[test]
fn text_pads_to_width() {
let text = Text::new("hi", 0, 0);
let rendered = text.render(10).unwrap();
assert_eq!(rendered.lines.len(), 1);
assert_eq!(rendered.lines[0].len(), 10);
assert_eq!(rendered.lines[0], "hi ");
}
#[test]
fn text_pad_y_adds_blank_lines() {
let text = Text::new("a", 0, 2);
let rendered = text.render(10).unwrap();
assert_eq!(rendered.lines.len(), 5); assert_eq!(rendered.lines[0], " "); assert_eq!(rendered.lines[1], " ");
assert!(rendered.lines[2].starts_with("a"));
assert_eq!(rendered.lines[3], " ");
assert_eq!(rendered.lines[4], " ");
}
#[test]
fn text_pad_x_prefixes_spaces() {
let text = Text::new("x", 3, 0);
let rendered = text.render(10).unwrap();
assert_eq!(rendered.lines[0], " x "); }
#[test]
fn text_long_line_with_pad_x_truncates() {
let text = Text::new("abcdefghij", 5, 0);
let rendered = text.render(10).unwrap();
assert!(rendered.lines[0].starts_with(" ")); assert!(rendered.lines[0].trim_end().ends_with("abcd…"));
}
}