use super::renderer::{FrameKind, MarkupRenderer};
use crate::render::format::OutputFormat;
use pulldown_cmark::{Event, HeadingLevel, Options, Tag, TagEnd};
pub(crate) fn render_markdown_body<F: OutputFormat<Output = String>>(
body: &str,
fmt: &F,
) -> String {
let mut renderer = MarkupRenderer::new(fmt);
let parser = pulldown_cmark::Parser::new_ext(body, Options::ENABLE_STRIKETHROUGH);
for event in parser {
match event {
Event::Start(tag) => match tag {
Tag::Paragraph => {
renderer.start_container(FrameKind::Paragraph);
}
Tag::BlockQuote(_) => {
renderer.start_container(FrameKind::BlockQuote);
}
Tag::List(None) => {
renderer.start_container(FrameKind::BulletList);
}
Tag::List(Some(_)) => {
renderer.start_container(FrameKind::OrderedList);
}
Tag::Item => {
renderer.start_container(FrameKind::ListItem);
}
Tag::Heading { level, .. } => {
let lvl = match level {
HeadingLevel::H1 => 1,
HeadingLevel::H2 => 2,
HeadingLevel::H3 => 3,
HeadingLevel::H4 => 4,
HeadingLevel::H5 => 5,
HeadingLevel::H6 => 6,
};
renderer.start_container(FrameKind::Heading { level: lvl });
}
Tag::CodeBlock(kind) => {
let lang = match kind {
pulldown_cmark::CodeBlockKind::Fenced(lang) if !lang.is_empty() => {
Some(lang.to_string())
}
_ => None,
};
renderer.start_container(FrameKind::CodeBlock { lang });
}
Tag::Emphasis => {
renderer.start_container(FrameKind::Emph);
}
Tag::Strong => {
renderer.start_container(FrameKind::Strong);
}
Tag::Strikethrough => {
renderer.start_container(FrameKind::Strikeout);
}
Tag::Link { dest_url, .. } => {
renderer.start_container(FrameKind::Link {
url: dest_url.to_string(),
});
}
_ => {
renderer.start_container(FrameKind::Transparent);
}
},
Event::End(tag) => match tag {
TagEnd::Paragraph
| TagEnd::BlockQuote(_)
| TagEnd::List(_)
| TagEnd::Item
| TagEnd::Heading(_)
| TagEnd::CodeBlock
| TagEnd::Emphasis
| TagEnd::Strong
| TagEnd::Strikethrough
| TagEnd::Link => {
renderer.end_container();
}
_ => {
renderer.end_container();
}
},
Event::Text(text) => {
if renderer.in_raw_context() {
renderer.push_raw_text(text.to_string());
} else {
renderer.push_text(text.to_string());
}
}
Event::Code(code) => {
let output = fmt.inline_code(code.to_string());
renderer.push_output(output);
}
Event::SoftBreak => {
renderer.push_soft_break();
}
Event::HardBreak => {
renderer.push_hard_break();
}
_ => {}
}
}
renderer.finish()
}