use crate::ir::{Block, Document, Paragraph, Table};
pub fn to_markdown(doc: &Document) -> String {
let mut blocks = Vec::new();
for page in &doc.pages {
for block in &page.blocks {
match block {
Block::Paragraph(p) => blocks.push(paragraph_md(p)),
Block::Table(t) => blocks.push(table_md(t)),
Block::Image(_) => {}
}
}
}
blocks.join("\n\n")
}
fn paragraph_md(p: &Paragraph) -> String {
match p.heading_level {
Some(n) if n > 0 => format!("{} {}", "#".repeat(n as usize), p.text),
_ => p.text.clone(),
}
}
fn table_md(table: &Table) -> String {
let expanded: Vec<Vec<String>> = table
.rows
.iter()
.map(|row| {
let mut cols = Vec::new();
for cell in row {
let span = cell.col_span.max(1) as usize;
let text = escape_cell(&cell.text);
for _ in 0..span {
cols.push(text.clone());
}
}
cols
})
.collect();
let width = expanded.iter().map(Vec::len).max().unwrap_or(0);
if width == 0 {
return String::new();
}
let mut out = String::new();
for (i, row) in expanded.iter().enumerate() {
let mut cells: Vec<String> = row.clone();
cells.resize(width, String::new());
out.push_str(&format!("| {} |", cells.join(" | ")));
out.push('\n');
if i == 0 {
let sep = vec!["---"; width].join(" | ");
out.push_str(&format!("| {sep} |"));
out.push('\n');
}
}
out.pop();
out
}
fn escape_cell(text: &str) -> String {
text.replace('|', "\\|").replace('\n', " ")
}