use alloc::string::String;
use alloc::vec::Vec;
use crate::ast::*;
use crate::parse::Definitions;
use crate::span::Span;
pub(crate) struct LeafMut<'a> {
pub(crate) span: Option<Span>,
pub(crate) inlines: &'a mut Vec<Inline>,
pub(crate) source: &'a mut Option<String>,
}
pub(crate) fn visit(
blocks: &[Block],
path: &mut Vec<usize>,
visit_leaf: &mut impl FnMut(&[usize], Option<Span>, Option<&str>),
) {
for (index, block) in blocks.iter().enumerate() {
path.push(index);
match block {
Block::Paragraph(node) => visit_leaf(path, node.meta.span, node.source.as_deref()),
Block::Heading(node) => visit_leaf(path, node.meta.span, node.source.as_deref()),
Block::LeafDirective(node) => {
visit_leaf(path, node.meta.span, node.label_source.as_deref())
}
Block::ContainerDirective(node) => {
visit_leaf(path, node.meta.span, node.label_source.as_deref());
visit(&node.children, path, visit_leaf);
}
Block::Table(node) => {
for (row, cells) in node.rows.iter().enumerate() {
for (cell, node) in cells.cells.iter().enumerate() {
path.extend([row, cell]);
visit_leaf(path, node.meta.span, node.source.as_deref());
path.truncate(path.len() - 2);
}
}
}
Block::BlockQuote(node) => visit(&node.children, path, visit_leaf),
Block::Alert(node) => visit(&node.children, path, visit_leaf),
Block::FootnoteDefinition(node) => visit(&node.children, path, visit_leaf),
Block::HtmlContainer(node) => match &node.content {
HtmlContainerContent::Blocks(children) => visit(children, path, visit_leaf),
HtmlContainerContent::Inlines(_) => {}
},
Block::List(node) => {
for (item, node) in node.children.iter().enumerate() {
path.push(item);
visit(&node.children, path, visit_leaf);
path.pop();
}
}
Block::ThematicBreak(_)
| Block::CodeBlock(_)
| Block::HtmlBlock(_)
| Block::Definition(_)
| Block::MathBlock(_)
| Block::Frontmatter(_)
| Block::BlankLine(_) => {}
}
path.pop();
}
}
pub(crate) fn visit_mut(blocks: &mut [Block], visit_leaf: &mut impl FnMut(LeafMut<'_>)) {
for block in blocks {
match block {
Block::Paragraph(node) => visit_leaf(LeafMut {
span: node.meta.span,
inlines: &mut node.children,
source: &mut node.source,
}),
Block::Heading(node) => visit_leaf(LeafMut {
span: node.meta.span,
inlines: &mut node.children,
source: &mut node.source,
}),
Block::LeafDirective(node) => visit_leaf(LeafMut {
span: node.meta.span,
inlines: &mut node.label,
source: &mut node.label_source,
}),
Block::ContainerDirective(node) => {
visit_leaf(LeafMut {
span: node.meta.span,
inlines: &mut node.label,
source: &mut node.label_source,
});
visit_mut(&mut node.children, visit_leaf);
}
Block::Table(node) => {
for cell in node.rows.iter_mut().flat_map(|row| &mut row.cells) {
visit_leaf(LeafMut {
span: cell.meta.span,
inlines: &mut cell.children,
source: &mut cell.source,
});
}
}
Block::BlockQuote(node) => visit_mut(&mut node.children, visit_leaf),
Block::Alert(node) => visit_mut(&mut node.children, visit_leaf),
Block::FootnoteDefinition(node) => visit_mut(&mut node.children, visit_leaf),
Block::HtmlContainer(node) => match &mut node.content {
HtmlContainerContent::Blocks(children) => visit_mut(children, visit_leaf),
HtmlContainerContent::Inlines(_) => {}
},
Block::List(node) => {
for item in &mut node.children {
visit_mut(&mut item.children, visit_leaf);
}
}
Block::ThematicBreak(_)
| Block::CodeBlock(_)
| Block::HtmlBlock(_)
| Block::Definition(_)
| Block::MathBlock(_)
| Block::Frontmatter(_)
| Block::BlankLine(_) => {}
}
}
}
pub(crate) fn any_kept(blocks: &[Block]) -> bool {
let mut kept = false;
visit(blocks, &mut Vec::new(), &mut |_, _, source| {
kept |= source.is_some()
});
kept
}
impl Document {
pub fn reread_kept_sources(&mut self) {
let definitions = Definitions::of(self);
visit_mut(&mut self.children, &mut |leaf| {
if let Some(text) = leaf.source.as_deref() {
*leaf.inlines = crate::parse::parse_inline_tree(text, &definitions).inlines;
}
});
}
}