use comrak::{Arena, Options, format_commonmark};
use crate::types::internal::InternalDocument;
use super::comrak_bridge::build_comrak_ast;
pub fn render_markdown(doc: &InternalDocument) -> String {
tracing::debug!(element_count = doc.elements.len(), "markdown rendering starting");
let arena = Arena::new();
let root = build_comrak_ast(doc, &arena);
if root.first_child().is_none() {
tracing::debug!("markdown rendering: empty AST, returning empty string");
return String::new();
}
let mut options = comrak_options();
options.render.width = 0;
let mut output = String::new();
format_commonmark(root, &options, &mut output).expect("comrak formatting should not fail");
if output.contains("&#") {
output = output.replace(" ", " ").replace("", "");
}
if output.contains("\\_") {
output = output.replace("\\_", "_");
}
if output.contains("\\[") || output.contains("\\]") || output.contains("\\(") || output.contains("\\)") {
output = output
.replace("\\[", "[")
.replace("\\]", "]")
.replace("\\(", "(")
.replace("\\)", ")");
}
if output.contains("\\*") || output.contains("\\#") {
output = output
.lines()
.map(|line| {
let trimmed = line.trim_start();
if trimmed.starts_with("\\* ") || trimmed.starts_with("\\#.") || trimmed.starts_with("\\#\\.") {
line.replacen("\\*", "*", 1).replacen("\\#", "#", 1)
} else {
line.to_string()
}
})
.collect::<Vec<_>>()
.join("\n");
}
let trimmed_len = output.trim_end().len();
if trimmed_len == 0 {
return String::new();
}
output.truncate(trimmed_len);
output.push('\n');
tracing::debug!(output_length = output.len(), "markdown rendering complete");
output
}
pub(crate) fn comrak_options<'a>() -> Options<'a> {
let mut options = Options::default();
options.extension.table = true;
options.extension.strikethrough = true;
options.extension.footnotes = true;
options.extension.description_lists = true;
options.extension.math_dollars = true;
options.extension.underline = true;
options.extension.subscript = true;
options.extension.superscript = true;
options.extension.highlight = true;
options.extension.alerts = true;
options.render.prefer_fenced = true;
options
}