use crate::ir::{Block, Line, PageLayout};
pub trait Output {
fn render(&self, pages: &[PageLayout]) -> String;
}
pub struct Text;
impl Output for Text {
fn render(&self, pages: &[PageLayout]) -> String {
let mut out = String::new();
for (page_index, page) in pages.iter().enumerate() {
if page_index > 0 {
out.push('\u{c}');
}
let mut written = 0usize;
for block in &page.blocks {
match block {
Block::Heading { lines, .. } | Block::Paragraph { lines, .. } => {
for line in lines {
open_line(&mut out, &mut written);
push_line(&mut out, line);
}
}
Block::List { items, .. } => {
for line in items.iter().flat_map(|item| &item.lines) {
open_line(&mut out, &mut written);
push_line(&mut out, line);
}
}
Block::Table { rows, .. } => {
for row in rows {
open_line(&mut out, &mut written);
push_row(&mut out, row);
}
}
}
}
}
out
}
}
fn open_line(out: &mut String, written: &mut usize) {
if *written > 0 {
out.push('\n');
}
*written += 1;
}
pub(crate) fn line_text(line: &Line) -> String {
let mut out = String::new();
push_line(&mut out, line);
out
}
fn push_line(out: &mut String, line: &Line) {
for inline in &line.inlines {
out.push_str(&inline.text);
}
}
fn push_row(out: &mut String, row: &[crate::ir::Cell]) {
for (index, line) in row.iter().filter_map(|cell| cell.line.as_ref()).enumerate() {
if index > 0 {
out.push(' ');
}
push_line(out, line);
}
}