use retroglyph_core::layout::TextLayout;
use retroglyph_core::text::{Line, Span};
use retroglyph_core::{Backend, Rect, Style, Terminal};
use super::{Measure, Widget};
#[derive(Clone, Copy, Debug)]
pub struct Paragraph<'a> {
text: &'a str,
style: Style,
}
impl<'a> Paragraph<'a> {
#[must_use]
pub fn new(text: &'a str) -> Self {
Self {
text,
style: Style::new(),
}
}
#[must_use]
pub const fn style(mut self, style: Style) -> Self {
self.style = style;
self
}
fn line(&self) -> Line {
Line::from(Span::styled(self.text, self.style))
}
}
impl Measure for Paragraph<'_> {
fn height_for(&self, width: u16) -> u16 {
let line = self.line();
TextLayout::new(&line)
.rect(Rect::new(0, 0, width, u16::MAX))
.measure()
.height
}
}
impl<B: Backend> Widget<B> for Paragraph<'_> {
fn render(self, area: Rect, term: &mut Terminal<B>) {
let line = self.line();
TextLayout::new(&line).rect(area).render(term);
}
}
#[cfg(test)]
mod tests {
use retroglyph_core::Headless;
use super::*;
#[test]
fn height_for_matches_wrapped_line_count() {
let p = Paragraph::new("the quick brown fox jumps");
assert_eq!(p.height_for(10), 3); assert_eq!(p.height_for(100), 1);
}
#[test]
fn height_for_respects_hard_newlines() {
let p = Paragraph::new("first\nsecond\nthird");
assert_eq!(p.height_for(100), 3);
}
#[test]
fn render_draws_one_line_per_wrapped_row() {
let area = Rect::new(0, 0, 10, 5);
let mut term = Terminal::new(Headless::new(10, 5));
Paragraph::new("the quick brown fox jumps").render(area, &mut term);
let row0: String = (0..10).map(|x| term.grid().get(x, 0).glyph()).collect();
let row1: String = (0..10).map(|x| term.grid().get(x, 1).glyph()).collect();
let row2: String = (0..10).map(|x| term.grid().get(x, 2).glyph()).collect();
assert!(row0.starts_with("the quick"));
assert!(row1.starts_with("brown fox"));
assert!(row2.starts_with("jumps"));
}
#[test]
fn render_stops_at_the_area_bottom() {
let area = Rect::new(0, 0, 10, 1);
let mut term = Terminal::new(Headless::new(10, 2));
Paragraph::new("the quick brown fox jumps").render(area, &mut term);
let row1: String = (0..10).map(|x| term.grid().get(x, 1).glyph()).collect();
assert_eq!(row1.trim(), "");
}
}