use super::unicode::unicode_to_typst;
pub(crate) fn map_math_text(input: &str) -> String {
let mut result = String::new();
let mut word_buf = String::new();
let mut last_was_name = false;
let mut non_ascii_buf = String::new();
for ch in input.chars() {
if ch.is_ascii_alphabetic() {
if !non_ascii_buf.is_empty() {
flush_non_ascii_text(&mut result, &non_ascii_buf, &mut last_was_name);
non_ascii_buf.clear();
}
word_buf.push(ch);
continue;
}
if !word_buf.is_empty() {
if !non_ascii_buf.is_empty() {
flush_non_ascii_text(&mut result, &non_ascii_buf, &mut last_was_name);
non_ascii_buf.clear();
}
flush_math_word(&mut result, &word_buf, &mut last_was_name);
word_buf.clear();
}
if let Some(name) = unicode_to_typst(ch) {
if !non_ascii_buf.is_empty() {
flush_non_ascii_text(&mut result, &non_ascii_buf, &mut last_was_name);
non_ascii_buf.clear();
}
if !result.is_empty()
&& (last_was_name || result.chars().last().is_some_and(|c| c.is_alphanumeric()))
{
result.push(' ');
}
result.push_str(name);
last_was_name = true;
} else if ch.is_ascii_digit() {
if !non_ascii_buf.is_empty() {
flush_non_ascii_text(&mut result, &non_ascii_buf, &mut last_was_name);
non_ascii_buf.clear();
}
if last_was_name {
result.push(' ');
}
result.push(ch);
last_was_name = false;
} else if !ch.is_ascii() && ch.is_alphabetic() {
non_ascii_buf.push(ch);
} else {
if !non_ascii_buf.is_empty() {
flush_non_ascii_text(&mut result, &non_ascii_buf, &mut last_was_name);
non_ascii_buf.clear();
}
if ch == '(' || ch == ')' {
result.push('"');
result.push(ch);
result.push('"');
} else {
result.push(ch);
}
last_was_name = false;
}
}
if !word_buf.is_empty() {
flush_math_word(&mut result, &word_buf, &mut last_was_name);
}
if !non_ascii_buf.is_empty() {
flush_non_ascii_text(&mut result, &non_ascii_buf, &mut last_was_name);
}
result
}
fn flush_non_ascii_text(result: &mut String, text: &str, last_was_name: &mut bool) {
if !result.is_empty()
&& (*last_was_name || result.chars().last().is_some_and(|c| c.is_alphanumeric()))
{
result.push(' ');
}
result.push_str("upright(\"");
result.push_str(text);
result.push_str("\")");
*last_was_name = true;
}
fn flush_math_word(result: &mut String, word: &str, last_was_name: &mut bool) {
if is_known_math_name(word) {
if !result.is_empty()
&& (*last_was_name || result.chars().last().is_some_and(|c| c.is_alphanumeric()))
{
result.push(' ');
}
result.push_str(word);
*last_was_name = true;
} else if word.len() == 1 {
if *last_was_name {
result.push(' ');
}
result.push_str(word);
*last_was_name = false;
} else {
for (i, c) in word.chars().enumerate() {
if i > 0 || *last_was_name {
result.push(' ');
}
result.push(c);
}
*last_was_name = false;
}
}
fn is_known_math_name(text: &str) -> bool {
matches!(
text,
"sin"
| "cos"
| "tan"
| "cot"
| "sec"
| "csc"
| "arcsin"
| "arccos"
| "arctan"
| "sinh"
| "cosh"
| "tanh"
| "coth"
| "ln"
| "log"
| "lg"
| "exp"
| "det"
| "dim"
| "gcd"
| "lcm"
| "max"
| "min"
| "sup"
| "inf"
| "lim"
| "arg"
| "deg"
| "mod"
)
}