use anstyle::Style;
use pulldown_cmark::{Alignment, CowStr, LinkType};
#[derive(Debug, PartialEq)]
pub struct PendingLink<'a> {
pub(crate) link_type: LinkType,
pub(crate) dest_url: CowStr<'a>,
pub(crate) title: CowStr<'a>,
}
#[derive(Debug, PartialEq)]
pub struct LinkReferenceDefinition<'a> {
pub(crate) index: u16,
pub(crate) target: CowStr<'a>,
pub(crate) title: CowStr<'a>,
pub(crate) style: Style,
}
#[derive(Debug)]
pub struct CurrentLine {
pub(super) length: u16,
pub(super) trailing_space: Option<String>,
}
impl CurrentLine {
pub(super) fn empty() -> Self {
Self {
length: 0,
trailing_space: None,
}
}
}
#[derive(Debug)]
pub struct TableCell<'a> {
pub(super) fragments: Vec<CowStr<'a>>,
}
impl TableCell<'_> {
pub(super) fn empty() -> Self {
Self {
fragments: Vec::new(),
}
}
}
#[derive(Debug)]
pub struct TableRow<'a> {
pub(super) cells: Vec<TableCell<'a>>,
pub(super) current_cell: TableCell<'a>,
}
impl TableRow<'_> {
pub(super) fn empty() -> Self {
Self {
cells: Vec::new(),
current_cell: TableCell::empty(),
}
}
}
#[derive(Debug)]
pub struct CurrentTable<'a> {
pub(super) head: Option<TableRow<'a>>,
pub(super) rows: Vec<TableRow<'a>>,
pub(super) current_row: TableRow<'a>,
pub(super) alignments: Vec<Alignment>,
}
impl<'a> CurrentTable<'a> {
pub(super) fn empty() -> Self {
Self {
head: None,
rows: Vec::new(),
current_row: TableRow::empty(),
alignments: Vec::new(),
}
}
pub(super) fn push_fragment(mut self, fragment: CowStr<'a>) -> Self {
self.current_row.current_cell.fragments.push(fragment);
self
}
pub(super) fn end_cell(mut self) -> Self {
self.current_row.cells.push(self.current_row.current_cell);
self.current_row.current_cell = TableCell::empty();
self
}
pub(super) fn end_head(mut self) -> Self {
self.head = Some(self.current_row);
self.current_row = TableRow::empty();
self
}
pub(super) fn end_row(mut self) -> Self {
self.rows.push(self.current_row);
self.current_row = TableRow::empty();
self
}
}
#[derive(Debug)]
pub struct StateData<'a> {
pub(super) pending_links: Vec<PendingLink<'a>>,
pub(super) pending_link_definitions: Vec<LinkReferenceDefinition<'a>>,
pub(super) next_link: u16,
pub(super) current_line: CurrentLine,
pub(super) current_table: CurrentTable<'a>,
}
impl<'a> StateData<'a> {
pub(crate) fn current_line(self, current_line: CurrentLine) -> Self {
Self {
current_line,
..self
}
}
pub(crate) fn push_pending_link(
mut self,
link_type: LinkType,
dest_url: CowStr<'a>,
title: CowStr<'a>,
) -> Self {
self.pending_links.push(PendingLink {
link_type,
dest_url,
title,
});
self
}
pub(crate) fn pop_pending_link(mut self) -> (Self, PendingLink<'a>) {
let link = self.pending_links.pop().unwrap();
(self, link)
}
pub(crate) fn add_link_reference(
mut self,
target: CowStr<'a>,
title: CowStr<'a>,
style: Style,
) -> (Self, u16) {
let index = self.next_link;
self.next_link += 1;
self.pending_link_definitions.push(LinkReferenceDefinition {
index,
target,
title,
style,
});
(self, index)
}
pub(crate) fn take_link_references(self) -> (Self, Vec<LinkReferenceDefinition<'a>>) {
let links = self.pending_link_definitions;
(
StateData {
pending_link_definitions: Vec::new(),
..self
},
links,
)
}
}
impl Default for StateData<'_> {
fn default() -> Self {
StateData {
pending_links: Vec::new(),
pending_link_definitions: Vec::new(),
next_link: 1,
current_line: CurrentLine::empty(),
current_table: CurrentTable::empty(),
}
}
}