Skip to main content

marco_core/render/
math.rs

1use katex::{
2    render_to_string as katex_render, KatexContext, OutputFormat, Settings as KatexSettings,
3};
4use std::sync::OnceLock;
5
6// Global KaTeX context (reused across renders for performance)
7static KATEX_CONTEXT: OnceLock<KatexContext> = OnceLock::new();
8
9/// Render inline math using KaTeX.
10pub(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(html)
17}
18
19/// Render display math using KaTeX.
20pub(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(html)
28}
29
30#[cfg(test)]
31mod tests {
32    use super::*;
33
34    #[test]
35    fn smoke_test_render_inline_math() {
36        let html = render_inline_math("E = mc^2").expect("inline math should render");
37        assert!(html.contains("<math") || html.contains("katex"));
38    }
39
40    #[test]
41    fn smoke_test_render_display_math() {
42        let html = render_display_math(r"\\frac{a}{b}").expect("display math should render");
43        assert!(html.contains("<math") || html.contains("katex"));
44    }
45}