marco_core/render/
math.rs1use katex::{
2 render_to_string as katex_render, KatexContext, OutputFormat, Settings as KatexSettings,
3};
4use std::sync::OnceLock;
5
6static KATEX_CONTEXT: OnceLock<KatexContext> = OnceLock::new();
8
9pub(crate) fn render_inline_math(latex: &str) -> Result<String, Box<dyn std::error::Error>> {
11 let ctx = KATEX_CONTEXT.get_or_init(KatexContext::default);
12 let settings = KatexSettings::builder()
13 .output(OutputFormat::Mathml)
14 .build();
15 let html = katex_render(ctx, latex, &settings)?;
16 Ok(normalize_math_attrs(html))
17}
18
19pub(crate) fn render_display_math(latex: &str) -> Result<String, Box<dyn std::error::Error>> {
21 let ctx = KATEX_CONTEXT.get_or_init(KatexContext::default);
22 let settings = KatexSettings::builder()
23 .display_mode(true)
24 .output(OutputFormat::Mathml)
25 .build();
26 let html = katex_render(ctx, latex, &settings)?;
27 Ok(normalize_math_attrs(html))
28}
29
30fn normalize_math_attrs(html: String) -> String {
34 html.replace(
35 r#"<math display="block" xmlns="http://www.w3.org/1998/Math/MathML">"#,
36 r#"<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">"#,
37 )
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn smoke_test_render_inline_math() {
46 let html = render_inline_math("E = mc^2").expect("inline math should render");
47 assert!(html.contains("<math") || html.contains("katex"));
48 }
49
50 #[test]
51 fn smoke_test_render_display_math() {
52 let html = render_display_math(r"\\frac{a}{b}").expect("display math should render");
53 assert!(html.contains("<math") || html.contains("katex"));
54 }
55}