///|
let unicode_symbol_decompositions : Map[String, String] = Map::from_array([
  ("á", "á"),
  ("à", "à"),
  ("ä", "ä"),
  ("ǟ", "ǟ"),
  ("ã", "ã"),
  ("ā", "ā"),
  ("ă", "ă"),
  ("ắ", "ắ"),
  ("ằ", "ằ"),
  ("ẵ", "ẵ"),
  ("ǎ", "ǎ"),
  ("â", "â"),
  ("ấ", "ấ"),
  ("ầ", "ầ"),
  ("ẫ", "ẫ"),
  ("ȧ", "ȧ"),
  ("ǡ", "ǡ"),
  ("å", "å"),
  ("ǻ", "ǻ"),
  ("ḃ", "ḃ"),
  ("ć", "ć"),
  ("ḉ", "ḉ"),
  ("č", "č"),
  ("ĉ", "ĉ"),
  ("ċ", "ċ"),
  ("ç", "ç"),
  ("ď", "ď"),
  ("ḋ", "ḋ"),
  ("ḑ", "ḑ"),
  ("é", "é"),
  ("è", "è"),
  ("ë", "ë"),
  ("ẽ", "ẽ"),
  ("ē", "ē"),
  ("ḗ", "ḗ"),
  ("ḕ", "ḕ"),
  ("ĕ", "ĕ"),
  ("ḝ", "ḝ"),
  ("ě", "ě"),
  ("ê", "ê"),
  ("ế", "ế"),
  ("ề", "ề"),
  ("ễ", "ễ"),
  ("ė", "ė"),
  ("ȩ", "ȩ"),
  ("ḟ", "ḟ"),
  ("ǵ", "ǵ"),
  ("ḡ", "ḡ"),
  ("ğ", "ğ"),
  ("ǧ", "ǧ"),
  ("ĝ", "ĝ"),
  ("ġ", "ġ"),
  ("ģ", "ģ"),
  ("ḧ", "ḧ"),
  ("ȟ", "ȟ"),
  ("ĥ", "ĥ"),
  ("ḣ", "ḣ"),
  ("ḩ", "ḩ"),
  ("í", "í"),
  ("ì", "ì"),
  ("ï", "ï"),
  ("ḯ", "ḯ"),
  ("ĩ", "ĩ"),
  ("ī", "ī"),
  ("ĭ", "ĭ"),
  ("ǐ", "ǐ"),
  ("î", "î"),
  ("ǰ", "ǰ"),
  ("ĵ", "ĵ"),
  ("ḱ", "ḱ"),
  ("ǩ", "ǩ"),
  ("ķ", "ķ"),
  ("ĺ", "ĺ"),
  ("ľ", "ľ"),
  ("ļ", "ļ"),
  ("ḿ", "ḿ"),
  ("ṁ", "ṁ"),
  ("ń", "ń"),
  ("ǹ", "ǹ"),
  ("ñ", "ñ"),
  ("ň", "ň"),
  ("ṅ", "ṅ"),
  ("ņ", "ņ"),
  ("ó", "ó"),
  ("ò", "ò"),
  ("ö", "ö"),
  ("ȫ", "ȫ"),
  ("õ", "õ"),
  ("ṍ", "ṍ"),
  ("ṏ", "ṏ"),
  ("ȭ", "ȭ"),
  ("ō", "ō"),
  ("ṓ", "ṓ"),
  ("ṑ", "ṑ"),
  ("ŏ", "ŏ"),
  ("ǒ", "ǒ"),
  ("ô", "ô"),
  ("ố", "ố"),
  ("ồ", "ồ"),
  ("ỗ", "ỗ"),
  ("ȯ", "ȯ"),
  ("ȱ", "ȱ"),
  ("ő", "ő"),
  ("ṕ", "ṕ"),
  ("ṗ", "ṗ"),
  ("ŕ", "ŕ"),
  ("ř", "ř"),
  ("ṙ", "ṙ"),
  ("ŗ", "ŗ"),
  ("ś", "ś"),
  ("ṥ", "ṥ"),
  ("š", "š"),
  ("ṧ", "ṧ"),
  ("ŝ", "ŝ"),
  ("ṡ", "ṡ"),
  ("ş", "ş"),
  ("ẗ", "ẗ"),
  ("ť", "ť"),
  ("ṫ", "ṫ"),
  ("ţ", "ţ"),
  ("ú", "ú"),
  ("ù", "ù"),
  ("ü", "ü"),
  ("ǘ", "ǘ"),
  ("ǜ", "ǜ"),
  ("ǖ", "ǖ"),
  ("ǚ", "ǚ"),
  ("ũ", "ũ"),
  ("ṹ", "ṹ"),
  ("ū", "ū"),
  ("ṻ", "ṻ"),
  ("ŭ", "ŭ"),
  ("ǔ", "ǔ"),
  ("û", "û"),
  ("ů", "ů"),
  ("ű", "ű"),
  ("ṽ", "ṽ"),
  ("ẃ", "ẃ"),
  ("ẁ", "ẁ"),
  ("ẅ", "ẅ"),
  ("ŵ", "ŵ"),
  ("ẇ", "ẇ"),
  ("ẘ", "ẘ"),
  ("ẍ", "ẍ"),
  ("ẋ", "ẋ"),
  ("ý", "ý"),
  ("ỳ", "ỳ"),
  ("ÿ", "ÿ"),
  ("ỹ", "ỹ"),
  ("ȳ", "ȳ"),
  ("ŷ", "ŷ"),
  ("ẏ", "ẏ"),
  ("ẙ", "ẙ"),
  ("ź", "ź"),
  ("ž", "ž"),
  ("ẑ", "ẑ"),
  ("ż", "ż"),
  ("Á", "Á"),
  ("À", "À"),
  ("Ä", "Ä"),
  ("Ǟ", "Ǟ"),
  ("Ã", "Ã"),
  ("Ā", "Ā"),
  ("Ă", "Ă"),
  ("Ắ", "Ắ"),
  ("Ằ", "Ằ"),
  ("Ẵ", "Ẵ"),
  ("Ǎ", "Ǎ"),
  ("Â", "Â"),
  ("Ấ", "Ấ"),
  ("Ầ", "Ầ"),
  ("Ẫ", "Ẫ"),
  ("Ȧ", "Ȧ"),
  ("Ǡ", "Ǡ"),
  ("Å", "Å"),
  ("Ǻ", "Ǻ"),
  ("Ḃ", "Ḃ"),
  ("Ć", "Ć"),
  ("Ḉ", "Ḉ"),
  ("Č", "Č"),
  ("Ĉ", "Ĉ"),
  ("Ċ", "Ċ"),
  ("Ç", "Ç"),
  ("Ď", "Ď"),
  ("Ḋ", "Ḋ"),
  ("Ḑ", "Ḑ"),
  ("É", "É"),
  ("È", "È"),
  ("Ë", "Ë"),
  ("Ẽ", "Ẽ"),
  ("Ē", "Ē"),
  ("Ḗ", "Ḗ"),
  ("Ḕ", "Ḕ"),
  ("Ĕ", "Ĕ"),
  ("Ḝ", "Ḝ"),
  ("Ě", "Ě"),
  ("Ê", "Ê"),
  ("Ế", "Ế"),
  ("Ề", "Ề"),
  ("Ễ", "Ễ"),
  ("Ė", "Ė"),
  ("Ȩ", "Ȩ"),
  ("Ḟ", "Ḟ"),
  ("Ǵ", "Ǵ"),
  ("Ḡ", "Ḡ"),
  ("Ğ", "Ğ"),
  ("Ǧ", "Ǧ"),
  ("Ĝ", "Ĝ"),
  ("Ġ", "Ġ"),
  ("Ģ", "Ģ"),
  ("Ḧ", "Ḧ"),
  ("Ȟ", "Ȟ"),
  ("Ĥ", "Ĥ"),
  ("Ḣ", "Ḣ"),
  ("Ḩ", "Ḩ"),
  ("Í", "Í"),
  ("Ì", "Ì"),
  ("Ï", "Ï"),
  ("Ḯ", "Ḯ"),
  ("Ĩ", "Ĩ"),
  ("Ī", "Ī"),
  ("Ĭ", "Ĭ"),
  ("Ǐ", "Ǐ"),
  ("Î", "Î"),
  ("İ", "İ"),
  ("Ĵ", "Ĵ"),
  ("Ḱ", "Ḱ"),
  ("Ǩ", "Ǩ"),
  ("Ķ", "Ķ"),
  ("Ĺ", "Ĺ"),
  ("Ľ", "Ľ"),
  ("Ļ", "Ļ"),
  ("Ḿ", "Ḿ"),
  ("Ṁ", "Ṁ"),
  ("Ń", "Ń"),
  ("Ǹ", "Ǹ"),
  ("Ñ", "Ñ"),
  ("Ň", "Ň"),
  ("Ṅ", "Ṅ"),
  ("Ņ", "Ņ"),
  ("Ó", "Ó"),
  ("Ò", "Ò"),
  ("Ö", "Ö"),
  ("Ȫ", "Ȫ"),
  ("Õ", "Õ"),
  ("Ṍ", "Ṍ"),
  ("Ṏ", "Ṏ"),
  ("Ȭ", "Ȭ"),
  ("Ō", "Ō"),
  ("Ṓ", "Ṓ"),
  ("Ṑ", "Ṑ"),
  ("Ŏ", "Ŏ"),
  ("Ǒ", "Ǒ"),
  ("Ô", "Ô"),
  ("Ố", "Ố"),
  ("Ồ", "Ồ"),
  ("Ỗ", "Ỗ"),
  ("Ȯ", "Ȯ"),
  ("Ȱ", "Ȱ"),
  ("Ő", "Ő"),
  ("Ṕ", "Ṕ"),
  ("Ṗ", "Ṗ"),
  ("Ŕ", "Ŕ"),
  ("Ř", "Ř"),
  ("Ṙ", "Ṙ"),
  ("Ŗ", "Ŗ"),
  ("Ś", "Ś"),
  ("Ṥ", "Ṥ"),
  ("Š", "Š"),
  ("Ṧ", "Ṧ"),
  ("Ŝ", "Ŝ"),
  ("Ṡ", "Ṡ"),
  ("Ş", "Ş"),
  ("Ť", "Ť"),
  ("Ṫ", "Ṫ"),
  ("Ţ", "Ţ"),
  ("Ú", "Ú"),
  ("Ù", "Ù"),
  ("Ü", "Ü"),
  ("Ǘ", "Ǘ"),
  ("Ǜ", "Ǜ"),
  ("Ǖ", "Ǖ"),
  ("Ǚ", "Ǚ"),
  ("Ũ", "Ũ"),
  ("Ṹ", "Ṹ"),
  ("Ū", "Ū"),
  ("Ṻ", "Ṻ"),
  ("Ŭ", "Ŭ"),
  ("Ǔ", "Ǔ"),
  ("Û", "Û"),
  ("Ů", "Ů"),
  ("Ű", "Ű"),
  ("Ṽ", "Ṽ"),
  ("Ẃ", "Ẃ"),
  ("Ẁ", "Ẁ"),
  ("Ẅ", "Ẅ"),
  ("Ŵ", "Ŵ"),
  ("Ẇ", "Ẇ"),
  ("Ẍ", "Ẍ"),
  ("Ẋ", "Ẋ"),
  ("Ý", "Ý"),
  ("Ỳ", "Ỳ"),
  ("Ÿ", "Ÿ"),
  ("Ỹ", "Ỹ"),
  ("Ȳ", "Ȳ"),
  ("Ŷ", "Ŷ"),
  ("Ẏ", "Ẏ"),
  ("Ź", "Ź"),
  ("Ž", "Ž"),
  ("Ẑ", "Ẑ"),
  ("Ż", "Ż"),
  ("ά", "ά"),
  ("ὰ", "ὰ"),
  ("ᾱ", "ᾱ"),
  ("ᾰ", "ᾰ"),
  ("έ", "έ"),
  ("ὲ", "ὲ"),
  ("ή", "ή"),
  ("ὴ", "ὴ"),
  ("ί", "ί"),
  ("ὶ", "ὶ"),
  ("ϊ", "ϊ"),
  ("ΐ", "ΐ"),
  ("ῒ", "ῒ"),
  ("ῑ", "ῑ"),
  ("ῐ", "ῐ"),
  ("ό", "ό"),
  ("ὸ", "ὸ"),
  ("ύ", "ύ"),
  ("ὺ", "ὺ"),
  ("ϋ", "ϋ"),
  ("ΰ", "ΰ"),
  ("ῢ", "ῢ"),
  ("ῡ", "ῡ"),
  ("ῠ", "ῠ"),
  ("ώ", "ώ"),
  ("ὼ", "ὼ"),
  ("Ύ", "Ύ"),
  ("Ὺ", "Ὺ"),
  ("Ϋ", "Ϋ"),
  ("Ῡ", "Ῡ"),
  ("Ῠ", "Ῠ"),
  ("Ώ", "Ώ"),
  ("Ὼ", "Ὼ"),
])

///|
fn normalize_unicode_symbol(mode : Mode, text : String) -> String {
  guard text.length() != 0 else { text }
  let first = text.unsafe_substring(start=0, end=1)
  match unicode_symbol_decompositions.get(first) {
    Some(decomposition) if lookup_symbol(mode, first) is None =>
      decomposition + text.unsafe_substring(start=1, end=text.length())
    _ => text
  }
}

///|
fn trailing_combining_mark_start(text : String) -> Int? {
  let mut start = text.length()
  while start > 0 && is_combining_diacritical_mark(text[start - 1]) {
    start = start - 1
  }
  guard start != text.length() else { None }
  Some(start)
}

///|
fn unicode_accent_command(mode : Mode, accent : String) -> String? {
  match accent {
    "́" => Some(if mode == Math { "\\acute" } else { "\\'" })
    "̀" => Some(if mode == Math { "\\grave" } else { "\\`" })
    "̈" => Some(if mode == Math { "\\ddot" } else { "\\\"" })
    "̃" => Some(if mode == Math { "\\tilde" } else { "\\~" })
    "̄" => Some(if mode == Math { "\\bar" } else { "\\=" })
    "̆" => Some(if mode == Math { "\\breve" } else { "\\u" })
    "̌" => Some(if mode == Math { "\\check" } else { "\\v" })
    "̂" => Some(if mode == Math { "\\hat" } else { "\\^" })
    "̇" => Some(if mode == Math { "\\dot" } else { "\\." })
    "̊" => Some(if mode == Math { "\\mathring" } else { "\\r" })
    "̋" => Some("\\H")
    "̧" => Some("\\c")
    _ => None
  }
}