pub mod block;
pub mod inline;
thread_local! {
static MATH_CONVERTER: std::cell::RefCell<Option<math_core::LatexToMathML>> =
std::cell::RefCell::new(
math_core::LatexToMathML::new(math_core::MathCoreConfig::default()).ok()
);
}
fn escape_html_text(input: &str) -> String {
input
.replace('&', "&")
.replace('<', "<")
.replace('>', ">")
}
fn parse_args(args: &str) -> Vec<String> {
if args.trim().is_empty() {
return vec![];
}
args.split(',').map(|s| s.trim().to_string()).collect()
}
fn render_args_as_data(args: &str) -> String {
parse_args(args)
.iter()
.enumerate()
.map(|(i, arg)| format!("<data value=\"{}\">{}</data>", i, escape_html_text(arg)))
.collect::<Vec<_>>()
.join("")
}
fn render_math_html(formula: &str, block_display: bool) -> Option<String> {
let formula = formula.trim();
if formula.is_empty() {
return None;
}
let display = if block_display {
math_core::MathDisplay::Block
} else {
math_core::MathDisplay::Inline
};
let converted = MATH_CONVERTER.with(|converter_cell| {
let mut converter = converter_cell.borrow_mut();
converter
.as_mut()
.and_then(|converter| converter.convert_with_local_state(formula, display).ok())
});
match converted {
Some(result) => Some(result.mathml),
None => Some(format!(
"<span class=\"umd-math-error\" data-math-source=\"{}\">{}</span>",
escape_html_text(formula),
escape_html_text(formula)
)),
}
}
fn render_popover_html(trigger_text: &str, raw_content: &str) -> String {
let popover_id = format!("umd-popover-{}", uuid::Uuid::new_v4().simple());
let content_html = crate::parse(raw_content);
format!(
"<button command=\"show-popover\" commandfor=\"{}\">{}</button><div id=\"{}\" popover>{}</div>",
popover_id,
escape_html_text(trigger_text.trim()),
popover_id,
content_html
)
}
pub(super) fn scan_balanced(chars: &[char], start: usize, open: char, close: char) -> Option<usize> {
let mut depth = 1i32;
let mut i = start + 1;
while i < chars.len() {
if chars[i] == open {
depth += 1;
} else if chars[i] == close {
depth -= 1;
if depth == 0 {
return Some(i);
}
}
i += 1;
}
None
}
pub(super) fn scan_balanced_double(chars: &[char], start: usize) -> Option<usize> {
let mut depth = 1i32;
let mut i = start + 2;
while i + 1 < chars.len() {
if chars[i] == '{' && chars[i + 1] == '{' {
depth += 1;
i += 2;
} else if chars[i] == '}' && chars[i + 1] == '}' {
depth -= 1;
if depth == 0 {
return Some(i);
}
i += 2;
} else {
i += 1;
}
}
None
}