mod flush;
mod state;
#[cfg(test)]
pub(crate) use flush::flush_paragraph;
pub(crate) use flush::{
apply_charpr_attrs, flush_active_paragraph_scope, flush_cell_paragraph, flush_footer_paragraph,
flush_footnote_paragraph, flush_header_paragraph, flush_list_item_paragraph,
flush_paragraph_staged, group_list_paragraphs, StagedBlock,
};
pub(crate) use state::{
FootnoteState, FormattingState, HeaderFooterState, ListState, PageLayoutState, TableState,
};
use crate::ir;
#[allow(clippy::struct_excessive_bools)]
pub(crate) struct ParseContext {
pub(crate) in_paragraph: bool,
pub(crate) in_run: bool,
pub(crate) in_text: bool,
pub(crate) current_text: String,
pub(crate) current_inlines: Vec<ir::Inline>,
pub(crate) face_names: Vec<String>,
pub(crate) heading_level: Option<u8>,
pub(crate) fmt: FormattingState,
pub(crate) table: TableState,
pub(crate) list: ListState,
pub(crate) equation_text: String,
pub(crate) in_equation: bool,
pub(crate) footnote: FootnoteState,
pub(crate) in_hyperlink: bool,
pub(crate) hyperlink_url: Option<String>,
pub(crate) in_ruby: bool,
pub(crate) ruby_base_text: String,
pub(crate) ruby_annotation_text: String,
pub(crate) ruby_current_part: RubyPart,
pub(crate) current_para_pr_id: Option<String>,
pub(crate) current_num_pr_id: Option<String>,
#[allow(clippy::option_option)]
pub(crate) pending_code_lang: Option<Option<String>>,
pub(crate) page_layout: PageLayoutState,
pub(crate) header_footer: HeaderFooterState,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub(crate) enum RubyPart {
#[default]
None,
Base,
Annotation,
}
impl Default for ParseContext {
fn default() -> Self {
Self {
in_paragraph: false,
in_run: false,
in_text: false,
current_text: String::new(),
current_inlines: Vec::new(),
face_names: Vec::new(),
heading_level: None,
fmt: FormattingState::default(),
table: TableState::default(),
list: ListState::default(),
equation_text: String::new(),
in_equation: false,
footnote: FootnoteState::default(),
in_hyperlink: false,
hyperlink_url: None,
in_ruby: false,
ruby_base_text: String::new(),
ruby_annotation_text: String::new(),
ruby_current_part: RubyPart::None,
current_para_pr_id: None,
current_num_pr_id: None,
pending_code_lang: None,
page_layout: PageLayoutState::default(),
header_footer: HeaderFooterState::default(),
}
}
}
impl ParseContext {
pub(crate) fn take_page_layout(&self) -> Option<ir::PageLayout> {
self.page_layout.take()
}
pub(crate) fn active_text_buf(&mut self) -> &mut String {
if self.header_footer.active
&& (self.header_footer.in_header || self.header_footer.in_footer)
{
&mut self.header_footer.text
} else if self.footnote.active {
&mut self.footnote.text
} else if self.list.in_item {
&mut self.list.item_text
} else if self.table.in_cell {
&mut self.table.cell_text
} else {
&mut self.current_text
}
}
pub(crate) fn push_inline(&mut self, inline: ir::Inline) {
if self.header_footer.active
&& (self.header_footer.in_header || self.header_footer.in_footer)
{
self.header_footer.inlines.push(inline);
} else if self.footnote.active {
self.footnote.inlines.push(inline);
} else if self.list.in_item {
self.list.item_inlines.push(inline);
} else if self.table.in_cell {
self.table.cell_inlines.push(inline);
} else {
self.current_inlines.push(inline);
}
}
pub(crate) fn push_block_scoped(&mut self, block: ir::Block) -> Option<ir::Block> {
if self.header_footer.in_header {
self.header_footer.header_blocks.push(block);
None
} else if self.header_footer.in_footer {
self.header_footer.footer_blocks.push(block);
None
} else if self.footnote.active {
self.footnote.blocks.push(block);
None
} else if self.list.in_item {
self.list.item_blocks.push(block);
None
} else if self.table.in_cell {
self.table.cell_blocks.push(block);
None
} else {
Some(block)
}
}
}