use crate::chars::latex_table::LATEX_TABLE;
use crate::strings::typst::ToTypst;
use core::fmt::{Formatter, Result, Write};
fn script(c: char) -> Option<(char, &'static str)> {
let i = LATEX_TABLE.binary_search_by_key(&c, |&(k, _, _)| k).ok()?;
let (_, is_math, latex) = LATEX_TABLE[i];
if !is_math {
return None;
}
match latex.as_bytes().first() {
Some(&k @ (b'^' | b'_')) => Some((char::from(k), &latex[1..])),
_ => None,
}
}
pub(crate) fn fmt_typst_chars<I: Iterator<Item = char>>(cs: I, f: &mut Formatter) -> Result {
let mut cs = cs.peekable();
let mut in_string = false;
let mut any = false;
let mut needs_base = true;
while let Some(c) = cs.next() {
any = true;
if let Some((kind, head)) = script(c) {
if in_string {
f.write_char('"')?;
in_string = false;
}
if needs_base {
f.write_str("\"\"")?;
}
f.write_char(kind)?;
f.write_str("(\"")?;
f.write_str(head)?;
while let Some((k, tail)) = cs.peek().copied().and_then(script) {
if k != kind {
break;
}
cs.next();
f.write_str(tail)?;
}
f.write_str("\")")?;
needs_base = true;
continue;
}
needs_base = false;
if !in_string {
f.write_char('"')?;
in_string = true;
}
match c {
'\\' => f.write_str("\\\\")?,
'"' => f.write_str("\\\"")?,
'\n' => f.write_str("\\n")?,
'\r' => f.write_str("\\r")?,
'\t' => f.write_str("\\t")?,
_ if c.is_control() => write!(f, "\\u{{{:x}}}", u32::from(c))?,
_ => f.write_char(c)?,
}
}
if in_string {
f.write_char('"')
} else if any {
Ok(())
} else {
f.write_str("\"\"")
}
}
impl ToTypst for char {
#[inline]
fn fmt_typst(&self, f: &mut Formatter) -> Result {
fmt_typst_chars(core::iter::once(*self), f)
}
}