use super::block_handlers::{handle_block_end, handle_block_start};
use super::event_handlers::{
finalize_block_element, handle_footnote_end, handle_footnote_reference, handle_symbol, handle_thematic_break,
};
use super::inline_handlers::{
finalize_inline_element, handle_image_end, handle_inline_end, handle_inline_start, handle_link_end, handle_math_end,
};
use super::state::{ExtractionState, pop_block};
use super::text_extraction::extract_text_from_events;
use crate::extractors::djot_format::attributes::parse_jotdown_attributes;
use crate::types::{Attributes, DjotContent, DjotImage, DjotLink, FormattedBlock};
use jotdown::{Container, Event};
pub fn extract_complete_djot_content(
events: &[Event],
metadata: crate::types::Metadata,
tables: Vec<crate::types::Table>,
) -> DjotContent {
let plain_text = extract_text_from_events(events);
let mut blocks = Vec::new();
let mut images = Vec::new();
let mut links = Vec::new();
let mut footnotes = Vec::new();
let attributes_map: Vec<(String, Attributes)> = Vec::new();
let mut state = ExtractionState::new();
for event in events {
match event {
Event::Start(container, attrs) => {
handle_start_event(
&mut state,
container,
attrs,
&mut blocks,
&mut images,
&mut links,
&mut footnotes,
);
}
Event::End(container) => {
handle_end_event(
&mut state,
container,
&mut blocks,
&mut images,
&mut links,
&mut footnotes,
);
}
Event::Str(s) => {
if state.in_code_block || state.in_raw_block {
state.code_content.push_str(s);
} else if state.in_math {
state.math_content.push_str(s);
} else {
state.current_text.push_str(s);
}
}
Event::FootnoteReference(label) => {
handle_footnote_reference(&mut state, label);
}
Event::Symbol(sym) => {
handle_symbol(&mut state, sym);
}
Event::Attributes(attrs) => {
state.pending_attributes = Some(parse_jotdown_attributes(attrs));
}
Event::Softbreak => {
if state.in_math {
state.math_content.push(' ');
} else if !state.inline_type_stack.is_empty() {
state.current_text.push(' ');
} else {
state.current_text.push('\n');
}
}
Event::Hardbreak => {
if state.in_math {
state.math_content.push('\n');
} else {
state.current_text.push('\n');
}
}
Event::NonBreakingSpace => {
state.current_text.push(' ');
}
Event::Blankline => {
}
Event::ThematicBreak(attrs) => {
handle_thematic_break(&mut state, attrs, &mut blocks);
}
Event::LeftSingleQuote => {
state.current_text.push('\'');
}
Event::RightSingleQuote => {
state.current_text.push('\'');
}
Event::LeftDoubleQuote => {
state.current_text.push('"');
}
Event::RightDoubleQuote => {
state.current_text.push('"');
}
Event::Ellipsis => {
state.current_text.push_str("...");
}
Event::EnDash => {
state.current_text.push_str("--");
}
Event::EmDash => {
state.current_text.push_str("---");
}
Event::Escape => {
}
}
}
state.flush_text();
while !state.block_stack.is_empty() {
pop_block(&mut state, &mut blocks);
}
if !state.current_inline_elements.is_empty()
&& let Some(last_block) = blocks.last_mut()
{
last_block.inline_content.append(&mut state.current_inline_elements);
}
DjotContent {
plain_text,
blocks,
metadata,
tables,
images,
links,
footnotes,
attributes: attributes_map,
}
}
fn handle_start_event(
state: &mut ExtractionState,
container: &Container,
attrs: &jotdown::Attributes,
_blocks: &mut Vec<FormattedBlock>,
images: &mut Vec<DjotImage>,
links: &mut Vec<DjotLink>,
footnotes: &mut Vec<crate::types::Footnote>,
) {
let parsed_attrs = if attrs.is_empty() {
state.pending_attributes.take()
} else {
Some(parse_jotdown_attributes(attrs))
};
if handle_block_start(state, container, attrs, parsed_attrs.as_ref().cloned(), footnotes) {
return;
}
if handle_inline_start(state, container, parsed_attrs, images, links) {
return;
}
match container {
Container::Table | Container::TableRow { .. } | Container::TableCell { .. } | Container::Caption => {
}
Container::LinkDefinition { .. } => {
}
_ => {}
}
}
fn handle_end_event(
state: &mut ExtractionState,
container: &Container,
blocks: &mut Vec<FormattedBlock>,
images: &mut [DjotImage],
links: &mut [DjotLink],
footnotes: &mut [crate::types::Footnote],
) {
if handle_block_end(state, container) {
finalize_block_element(state, blocks);
return;
}
match container {
Container::Footnote { .. } => {
handle_footnote_end(state, footnotes);
}
Container::Math { display } => {
handle_math_end(state, *display);
}
Container::Link(url, _) => {
handle_link_end(state, url, links);
}
Container::Image(src, _) => {
handle_image_end(state, src, images);
}
_ => {
if handle_inline_end(state, container) {
finalize_inline_element(state, container);
}
}
}
match container {
Container::Table | Container::TableRow { .. } | Container::TableCell { .. } | Container::Caption => {
}
Container::LinkDefinition { .. } => {
}
_ => {}
}
}