use serde::Serialize;
use crate::markdown_layout::{Block, Cell, PositionedBlock};
use crate::types::Rect;
#[derive(Debug, Clone, Serialize)]
pub struct LayoutCell {
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub bbox: Option<Rect>,
}
impl From<&Cell> for LayoutCell {
fn from(c: &Cell) -> Self {
LayoutCell {
text: c.text.clone(),
bbox: c.bbox.clone(),
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct LayoutBlock {
pub kind: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub level: Option<u8>,
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub bold: bool,
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub italic: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub ordered: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub marker: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lines: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lang: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub header: Option<Vec<LayoutCell>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rows: Option<Vec<Vec<LayoutCell>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bbox: Option<Rect>,
}
impl LayoutBlock {
fn of(kind: &'static str, bbox: Option<Rect>) -> Self {
LayoutBlock {
kind,
text: None,
level: None,
bold: false,
italic: false,
ordered: None,
marker: None,
lines: None,
lang: None,
header: None,
rows: None,
id: None,
format: None,
bbox,
}
}
}
fn cells(row: &[Cell]) -> Vec<LayoutCell> {
row.iter().map(LayoutCell::from).collect()
}
impl From<&PositionedBlock> for LayoutBlock {
fn from(pb: &PositionedBlock) -> Self {
let bbox = pb.bbox.clone();
match &pb.block {
Block::Heading { level, text } => LayoutBlock {
text: Some(text.clone()),
level: Some(*level),
..LayoutBlock::of("heading", bbox)
},
Block::Paragraph { text, bold, italic } => LayoutBlock {
text: Some(text.clone()),
bold: *bold,
italic: *italic,
..LayoutBlock::of("paragraph", bbox)
},
Block::ListItem {
ordered,
marker,
level,
text,
bold,
italic,
} => LayoutBlock {
text: Some(text.clone()),
level: Some(*level),
ordered: Some(*ordered),
marker: Some(marker.clone()),
bold: *bold,
italic: *italic,
..LayoutBlock::of("list_item", bbox)
},
Block::CodeBlock { lines, lang } => LayoutBlock {
lines: Some(lines.clone()),
lang: lang.clone(),
..LayoutBlock::of("code", bbox)
},
Block::Table { header, rows } => LayoutBlock {
header: header.as_ref().map(|h| cells(h)),
rows: Some(rows.iter().map(|r| cells(r)).collect()),
..LayoutBlock::of("table", bbox)
},
Block::GridFallback { lines } => LayoutBlock {
lines: Some(lines.clone()),
..LayoutBlock::of("grid_fallback", bbox)
},
Block::HorizontalRule => LayoutBlock::of("rule", bbox),
Block::Figure { id, format } => LayoutBlock {
id: Some(id.clone()),
format: Some(format.clone()),
..LayoutBlock::of("figure", bbox)
},
}
}
}