use mant_ast::{Block, Inline, LayoutHint, Section, SourceSpan};
use super::source::MarkdownSource;
pub(super) fn normalize_markdown_layout(
source: &MarkdownSource<'_>,
root_blocks: &mut [Block],
sections: &mut [Section],
) {
normalize_blocks(source, root_blocks);
normalize_sections(source, sections);
}
fn normalize_sections(source: &MarkdownSource<'_>, sections: &mut [Section]) {
for section in sections {
normalize_blocks(source, &mut section.blocks);
normalize_sections(source, &mut section.children);
}
}
fn normalize_blocks(source: &MarkdownSource<'_>, blocks: &mut [Block]) {
let mut previous_source = None;
for block in blocks {
if let (Some(previous), Some(current)) = (previous_source, block_source(block))
&& source.has_blank_line_between(previous, current)
&& let Some(layout) = block_layout_mut(block)
{
layout.spacing_before_lines = layout.spacing_before_lines.max(1);
}
normalize_nested_blocks(source, block);
previous_source = block_source(block);
}
}
fn normalize_nested_blocks(source: &MarkdownSource<'_>, block: &mut Block) {
match block {
Block::Preformatted { children, .. } => {
trim_code_framing_newline(children);
}
Block::List { items, .. } => {
for item in items {
normalize_blocks(source, &mut item.blocks);
}
}
Block::DefinitionList { items, .. } => {
for item in items {
normalize_blocks(source, &mut item.description);
}
}
Block::Table { rows, .. } => {
for cell in rows.iter_mut().flat_map(|row| &mut row.cells) {
normalize_blocks(source, &mut cell.blocks);
}
}
Block::Paragraph { .. }
| Block::Equation { .. }
| Block::VerticalSpace { .. }
| Block::ThematicBreak { .. }
| Block::Unsupported { .. } => {}
}
}
fn trim_code_framing_newline(children: &mut Vec<Inline>) {
let Some(last) = children.last_mut() else {
return;
};
match last {
Inline::Text { value } | Inline::Code { value } => {
if value.ends_with('\n') {
value.pop();
}
}
Inline::LineBreak => {
children.pop();
}
Inline::Strong { .. }
| Inline::Emphasis { .. }
| Inline::ExternalLink { .. }
| Inline::EmailLink { .. }
| Inline::ManualReference { .. }
| Inline::SectionReference { .. }
| Inline::Anchor { .. } => {}
}
}
fn block_source(block: &Block) -> Option<SourceSpan> {
match block {
Block::Paragraph { source, .. }
| Block::Preformatted { source, .. }
| Block::List { source, .. }
| Block::DefinitionList { source, .. }
| Block::Table { source, .. }
| Block::Equation { source, .. }
| Block::VerticalSpace { source, .. }
| Block::ThematicBreak { source }
| Block::Unsupported { source, .. } => *source,
}
}
fn block_layout_mut(block: &mut Block) -> Option<&mut LayoutHint> {
match block {
Block::Paragraph { layout, .. }
| Block::Preformatted { layout, .. }
| Block::List { layout, .. }
| Block::DefinitionList { layout, .. }
| Block::Table { layout, .. }
| Block::Equation { layout, .. }
| Block::Unsupported { layout, .. } => Some(layout),
Block::VerticalSpace { .. } | Block::ThematicBreak { .. } => None,
}
}