use crate::atom::AtomClass;
use crate::node::{
AccentKind, DelimSize, FracSpec, LineAlign, MathFont, PhantomKind, SpaceKind, StackKind,
TextStyle,
};
use crate::style::Style;
pub const TIER2_TRACKING: &str = "franken_manim fm-j5t (the tier-2 construct program)";
pub const UNTIERED_TRACKING: &str = "https://github.com/Dicklesworthstone/franken_manim/issues";
pub const LAYOUT_PENDING_TRACKING: &str = "franken_manim fm-kg9 (the fmd-math extensions bead)";
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Tier {
T1,
T2,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ConstructStatus {
Supported,
UnsupportedT2,
Unknown,
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum Cmd {
Sym {
ch: char,
class: AtomClass,
delim: bool,
},
BigOp { ch: char, integral: bool },
OpName {
rendered: &'static str,
limits: bool,
},
OperatorName,
Accent(AccentKind),
Frac(FracSpec),
OverInfix(FracSpec),
Radical,
Text,
TextStyled(TextStyle),
Alphabet(MathFont),
StyleSwitch(Style),
AlignDecl(LineAlign),
LineSpacing(f64),
SizeChange(f64),
Spacing(SpaceKind),
Phantom(PhantomKind),
Stack(StackKind),
Substack,
Color,
SizedDelim {
size: DelimSize,
class: Option<AtomClass>,
},
Left,
Right,
Limits,
NoLimits,
Begin,
End,
Ding,
XArrow {
mapsto: bool,
},
UnsupportedT2,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct EnvDef {
pub(crate) has_spec: bool,
}
const fn sym(ch: char, class: AtomClass) -> Cmd {
Cmd::Sym {
ch,
class,
delim: false,
}
}
const fn delim_sym(ch: char, class: AtomClass) -> Cmd {
Cmd::Sym {
ch,
class,
delim: true,
}
}
#[allow(clippy::too_many_lines)]
pub(crate) fn lookup(name: &str) -> Option<Cmd> {
use AtomClass::{Bin, Close, Inner, Open, Ord, Punct, Rel};
Some(match name {
"alpha" => sym('α', Ord),
"beta" => sym('β', Ord),
"gamma" => sym('γ', Ord),
"delta" => sym('δ', Ord),
"epsilon" => sym('ϵ', Ord),
"varepsilon" => sym('ε', Ord),
"zeta" => sym('ζ', Ord),
"eta" => sym('η', Ord),
"theta" => sym('θ', Ord),
"vartheta" => sym('ϑ', Ord),
"iota" => sym('ι', Ord),
"kappa" => sym('κ', Ord),
"lambda" => sym('λ', Ord),
"mu" => sym('μ', Ord),
"nu" => sym('ν', Ord),
"xi" => sym('ξ', Ord),
"pi" => sym('π', Ord),
"varpi" => sym('ϖ', Ord),
"rho" => sym('ρ', Ord),
"varrho" => sym('ϱ', Ord),
"sigma" => sym('σ', Ord),
"varsigma" => sym('ς', Ord),
"tau" => sym('τ', Ord),
"upsilon" => sym('υ', Ord),
"phi" => sym('ϕ', Ord),
"varphi" => sym('φ', Ord),
"chi" => sym('χ', Ord),
"psi" => sym('ψ', Ord),
"omega" => sym('ω', Ord),
"Gamma" => sym('Γ', Ord),
"Delta" => sym('Δ', Ord),
"Theta" => sym('Θ', Ord),
"Lambda" => sym('Λ', Ord),
"Xi" => sym('Ξ', Ord),
"Pi" => sym('Π', Ord),
"Sigma" => sym('Σ', Ord),
"Upsilon" => sym('ϒ', Ord),
"Phi" => sym('Φ', Ord),
"Psi" => sym('Ψ', Ord),
"Omega" => sym('Ω', Ord),
"infty" => sym('∞', Ord),
"partial" => sym('∂', Ord),
"nabla" => sym('∇', Ord),
"hbar" => sym('ℏ', Ord),
"ell" => sym('ℓ', Ord),
"wp" => sym('℘', Ord),
"Re" => sym('ℜ', Ord),
"Im" => sym('ℑ', Ord),
"aleph" => sym('ℵ', Ord),
"imath" | "i" => sym('ı', Ord),
"jmath" | "j" => sym('ȷ', Ord),
"emptyset" => sym('∅', Ord),
"varnothing" => sym('⌀', Ord),
"exists" => sym('∃', Ord),
"forall" => sym('∀', Ord),
"neg" | "lnot" => sym('¬', Ord),
"prime" => sym('′', Ord),
"angle" => sym('∠', Ord),
"triangle" => sym('△', Ord),
"checkmark" => sym('✓', Ord),
"copyright" => sym('©', Ord),
"female" => sym('\u{2640}', Ord),
"male" | "mars" => sym('\u{2642}', Ord),
"earth" => sym('\u{2641}', Ord),
"ding" => Cmd::Ding,
"xrightarrow" => Cmd::XArrow { mapsto: false },
"xmapsto" => Cmd::XArrow { mapsto: true },
"top" => sym('⊤', Ord),
"bot" => sym('⊥', Ord),
"flat" => sym('♭', Ord),
"natural" => sym('♮', Ord),
"sharp" => sym('♯', Ord),
"clubsuit" => sym('♣', Ord),
"diamondsuit" => sym('♢', Ord),
"heartsuit" => sym('♡', Ord),
"spadesuit" => sym('♠', Ord),
"backslash" => delim_sym('\\', Ord),
"vert" => delim_sym('|', Ord),
"Vert" => delim_sym('‖', Ord),
"ldots" | "dots" | "dotsc" | "dotso" => sym('…', Inner),
"cdots" | "dotsb" | "hdots" => sym('⋯', Inner),
"vdots" => sym('⋮', Ord),
"ddots" => sym('⋱', Inner),
"pm" => sym('±', Bin),
"mp" => sym('∓', Bin),
"cdot" => sym('⋅', Bin),
"times" => sym('×', Bin),
"div" => sym('÷', Bin),
"ast" => sym('∗', Bin),
"star" => sym('⋆', Bin),
"circ" => sym('∘', Bin),
"bullet" => sym('∙', Bin),
"oplus" => sym('⊕', Bin),
"ominus" => sym('⊖', Bin),
"otimes" => sym('⊗', Bin),
"oslash" => sym('⊘', Bin),
"odot" => sym('⊙', Bin),
"cup" => sym('∪', Bin),
"cap" => sym('∩', Bin),
"sqcup" => sym('⊔', Bin),
"sqcap" => sym('⊓', Bin),
"vee" | "lor" => sym('∨', Bin),
"wedge" | "land" => sym('∧', Bin),
"setminus" | "smallsetminus" => sym('∖', Bin),
"wr" => sym('≀', Bin),
"diamond" => sym('⋄', Bin),
"triangleleft" => sym('◁', Bin),
"triangleright" => sym('▷', Bin),
"uplus" => sym('⊎', Bin),
"amalg" => sym('⨿', Bin),
"dagger" => sym('†', Bin),
"ddagger" => sym('‡', Bin),
"minus" => sym('−', Bin),
"le" | "leq" => sym('≤', Rel),
"ge" | "geq" => sym('≥', Rel),
"ne" | "neq" => sym('≠', Rel),
"equiv" => sym('≡', Rel),
"approx" => sym('≈', Rel),
"sim" => sym('∼', Rel),
"simeq" => sym('≃', Rel),
"cong" => sym('≅', Rel),
"doteq" => sym('≐', Rel),
"propto" => sym('∝', Rel),
"perp" => sym('⊥', Rel),
"mid" => sym('∣', Rel),
"nmid" => sym('∤', Rel),
"parallel" => sym('∥', Rel),
"in" => sym('∈', Rel),
"ni" => sym('∋', Rel),
"notin" => sym('∉', Rel),
"subset" => sym('⊂', Rel),
"supset" => sym('⊃', Rel),
"subseteq" => sym('⊆', Rel),
"supseteq" => sym('⊇', Rel),
"sqsubseteq" => sym('⊑', Rel),
"sqsupseteq" => sym('⊒', Rel),
"ll" => sym('≪', Rel),
"gg" => sym('≫', Rel),
"prec" => sym('≺', Rel),
"succ" => sym('≻', Rel),
"preceq" => sym('⪯', Rel),
"succeq" => sym('⪰', Rel),
"asymp" => sym('≍', Rel),
"bowtie" => sym('⋈', Rel),
"models" => sym('⊨', Rel),
"vdash" => sym('⊢', Rel),
"dashv" => sym('⊣', Rel),
"smile" => sym('⌣', Rel),
"frown" => sym('⌢', Rel),
"colon" => sym(':', Punct),
"rightarrow" | "to" => sym('→', Rel),
"leftarrow" | "gets" => sym('←', Rel),
"leftrightarrow" => sym('↔', Rel),
"Rightarrow" => sym('⇒', Rel),
"Leftarrow" => sym('⇐', Rel),
"Leftrightarrow" => sym('⇔', Rel),
"longrightarrow" => sym('⟶', Rel),
"longleftarrow" => sym('⟵', Rel),
"longleftrightarrow" => sym('⟷', Rel),
"Longrightarrow" | "implies" => sym('⟹', Rel),
"Longleftarrow" | "impliedby" => sym('⟸', Rel),
"Longleftrightarrow" | "iff" => sym('⟺', Rel),
"mapsto" => sym('↦', Rel),
"longmapsto" => sym('⟼', Rel),
"uparrow" => delim_sym('↑', Rel),
"downarrow" => delim_sym('↓', Rel),
"updownarrow" => delim_sym('↕', Rel),
"Uparrow" => delim_sym('⇑', Rel),
"Downarrow" => delim_sym('⇓', Rel),
"Updownarrow" => delim_sym('⇕', Rel),
"nearrow" => sym('↗', Rel),
"searrow" => sym('↘', Rel),
"swarrow" => sym('↙', Rel),
"nwarrow" => sym('↖', Rel),
"hookrightarrow" => sym('↪', Rel),
"circlearrowleft" => sym('↺', Rel),
"circlearrowright" => sym('↻', Rel),
"hookleftarrow" => sym('↩', Rel),
"rightharpoonup" => sym('⇀', Rel),
"rightharpoondown" => sym('⇁', Rel),
"leftharpoonup" => sym('↼', Rel),
"leftharpoondown" => sym('↽', Rel),
"rightleftharpoons" => sym('⇌', Rel),
"langle" => delim_sym('⟨', Open),
"rangle" => delim_sym('⟩', Close),
"lceil" => delim_sym('⌈', Open),
"rceil" => delim_sym('⌉', Close),
"lfloor" => delim_sym('⌊', Open),
"rfloor" => delim_sym('⌋', Close),
"lbrace" => delim_sym('{', Open),
"rbrace" => delim_sym('}', Close),
"lbrack" => delim_sym('[', Open),
"rbrack" => delim_sym(']', Close),
"sum" => Cmd::BigOp {
ch: '∑',
integral: false,
},
"prod" => Cmd::BigOp {
ch: '∏',
integral: false,
},
"coprod" => Cmd::BigOp {
ch: '∐',
integral: false,
},
"int" => Cmd::BigOp {
ch: '∫',
integral: true,
},
"oint" => Cmd::BigOp {
ch: '∮',
integral: true,
},
"iint" => Cmd::BigOp {
ch: '∬',
integral: true,
},
"oiint" => Cmd::BigOp {
ch: '∯',
integral: true,
},
"iiint" => Cmd::BigOp {
ch: '∭',
integral: true,
},
"bigcup" => Cmd::BigOp {
ch: '⋃',
integral: false,
},
"bigcap" => Cmd::BigOp {
ch: '⋂',
integral: false,
},
"bigvee" => Cmd::BigOp {
ch: '⋁',
integral: false,
},
"bigwedge" => Cmd::BigOp {
ch: '⋀',
integral: false,
},
"bigoplus" => Cmd::BigOp {
ch: '⨁',
integral: false,
},
"bigotimes" => Cmd::BigOp {
ch: '⨂',
integral: false,
},
"bigodot" => Cmd::BigOp {
ch: '⨀',
integral: false,
},
"biguplus" => Cmd::BigOp {
ch: '⨄',
integral: false,
},
"bigsqcup" => Cmd::BigOp {
ch: '⨆',
integral: false,
},
"sin" => Cmd::OpName {
rendered: "sin",
limits: false,
},
"cos" => Cmd::OpName {
rendered: "cos",
limits: false,
},
"tan" => Cmd::OpName {
rendered: "tan",
limits: false,
},
"cot" => Cmd::OpName {
rendered: "cot",
limits: false,
},
"sec" => Cmd::OpName {
rendered: "sec",
limits: false,
},
"csc" => Cmd::OpName {
rendered: "csc",
limits: false,
},
"arcsin" => Cmd::OpName {
rendered: "arcsin",
limits: false,
},
"arccos" => Cmd::OpName {
rendered: "arccos",
limits: false,
},
"arctan" => Cmd::OpName {
rendered: "arctan",
limits: false,
},
"sinh" => Cmd::OpName {
rendered: "sinh",
limits: false,
},
"cosh" => Cmd::OpName {
rendered: "cosh",
limits: false,
},
"tanh" => Cmd::OpName {
rendered: "tanh",
limits: false,
},
"coth" => Cmd::OpName {
rendered: "coth",
limits: false,
},
"exp" => Cmd::OpName {
rendered: "exp",
limits: false,
},
"log" => Cmd::OpName {
rendered: "log",
limits: false,
},
"lg" => Cmd::OpName {
rendered: "lg",
limits: false,
},
"ln" => Cmd::OpName {
rendered: "ln",
limits: false,
},
"arg" => Cmd::OpName {
rendered: "arg",
limits: false,
},
"deg" => Cmd::OpName {
rendered: "deg",
limits: false,
},
"dim" => Cmd::OpName {
rendered: "dim",
limits: false,
},
"hom" => Cmd::OpName {
rendered: "hom",
limits: false,
},
"ker" => Cmd::OpName {
rendered: "ker",
limits: false,
},
"mod" | "bmod" => Cmd::OpName {
rendered: "mod",
limits: false,
},
"lim" => Cmd::OpName {
rendered: "lim",
limits: true,
},
"limsup" => Cmd::OpName {
rendered: "lim sup",
limits: true,
},
"liminf" => Cmd::OpName {
rendered: "lim inf",
limits: true,
},
"max" => Cmd::OpName {
rendered: "max",
limits: true,
},
"min" => Cmd::OpName {
rendered: "min",
limits: true,
},
"sup" => Cmd::OpName {
rendered: "sup",
limits: true,
},
"inf" => Cmd::OpName {
rendered: "inf",
limits: true,
},
"det" => Cmd::OpName {
rendered: "det",
limits: true,
},
"gcd" => Cmd::OpName {
rendered: "gcd",
limits: true,
},
"Pr" => Cmd::OpName {
rendered: "Pr",
limits: true,
},
"operatorname" => Cmd::OperatorName,
"hat" => Cmd::Accent(AccentKind::Hat),
"check" => Cmd::Accent(AccentKind::Check),
"tilde" => Cmd::Accent(AccentKind::Tilde),
"acute" => Cmd::Accent(AccentKind::Acute),
"grave" => Cmd::Accent(AccentKind::Grave),
"dot" => Cmd::Accent(AccentKind::Dot),
"ddot" => Cmd::Accent(AccentKind::Ddot),
"dddot" => Cmd::Accent(AccentKind::Dddot),
"ddddot" => Cmd::Accent(AccentKind::Ddddot),
"breve" => Cmd::Accent(AccentKind::Breve),
"bar" => Cmd::Accent(AccentKind::Bar),
"vec" => Cmd::Accent(AccentKind::Vec),
"mathring" => Cmd::Accent(AccentKind::Ring),
"widehat" => Cmd::Accent(AccentKind::WideHat),
"widetilde" => Cmd::Accent(AccentKind::WideTilde),
"overline" => Cmd::Accent(AccentKind::OverLine),
"overbrace" => Cmd::Accent(AccentKind::OverBrace),
"underbrace" => Cmd::Accent(AccentKind::UnderBrace),
"overrightarrow" => Cmd::Accent(AccentKind::OverRightArrow),
"overleftarrow" => Cmd::Accent(AccentKind::OverLeftArrow),
"underline" => Cmd::Accent(AccentKind::UnderLine),
"frac" => Cmd::Frac(FracSpec {
bar: true,
delims: None,
forced_style: None,
}),
"dfrac" => Cmd::Frac(FracSpec {
bar: true,
delims: None,
forced_style: Some(Style::Display),
}),
"tfrac" => Cmd::Frac(FracSpec {
bar: true,
delims: None,
forced_style: Some(Style::Text),
}),
"binom" => Cmd::Frac(FracSpec {
bar: false,
delims: Some(('(', ')')),
forced_style: None,
}),
"over" => Cmd::OverInfix(FracSpec {
bar: true,
delims: None,
forced_style: None,
}),
"choose" => Cmd::OverInfix(FracSpec {
bar: false,
delims: Some(('(', ')')),
forced_style: None,
}),
"sqrt" => Cmd::Radical,
"text" => Cmd::Text,
"textbf" => Cmd::TextStyled(TextStyle::Bold),
"emph" => Cmd::TextStyled(TextStyle::Emph),
"mathbb" => Cmd::Alphabet(MathFont::Blackboard),
"mathds" => Cmd::Alphabet(MathFont::Blackboard),
"mathcal" => Cmd::Alphabet(MathFont::Calligraphic),
"mathrm" => Cmd::Alphabet(MathFont::Roman),
"mathbf" => Cmd::Alphabet(MathFont::Bold),
"boldsymbol" => Cmd::Alphabet(MathFont::BoldItalic),
"mathsf" => Cmd::Alphabet(MathFont::SansSerif),
"mathtt" => Cmd::Alphabet(MathFont::Typewriter),
"mathit" => Cmd::Alphabet(MathFont::Italic),
"displaystyle" => Cmd::StyleSwitch(Style::Display),
"textstyle" => Cmd::StyleSwitch(Style::Text),
"scriptstyle" => Cmd::StyleSwitch(Style::Script),
"scriptscriptstyle" => Cmd::StyleSwitch(Style::ScriptScript),
"tiny" => Cmd::SizeChange(0.5),
"footnotesize" => Cmd::SizeChange(0.8),
"small" => Cmd::SizeChange(0.9),
"large" => Cmd::SizeChange(1.2),
"Large" => Cmd::SizeChange(1.44),
"huge" => Cmd::SizeChange(2.074),
"quad" => Cmd::Spacing(SpaceKind::Quad),
"qquad" => Cmd::Spacing(SpaceKind::Qquad),
"phantom" => Cmd::Phantom(PhantomKind::Full),
"hphantom" => Cmd::Phantom(PhantomKind::Horizontal),
"vphantom" => Cmd::Phantom(PhantomKind::Vertical),
"stackrel" => Cmd::Stack(StackKind::Stackrel),
"overset" => Cmd::Stack(StackKind::Overset),
"underset" => Cmd::Stack(StackKind::Underset),
"substack" => Cmd::Substack,
"color" => Cmd::Color,
"big" => Cmd::SizedDelim {
size: DelimSize::Big,
class: None,
},
"Big" => Cmd::SizedDelim {
size: DelimSize::BBig,
class: None,
},
"bigg" => Cmd::SizedDelim {
size: DelimSize::Bigg,
class: None,
},
"Bigg" => Cmd::SizedDelim {
size: DelimSize::BBigg,
class: None,
},
"bigl" => Cmd::SizedDelim {
size: DelimSize::Big,
class: Some(AtomClass::Open),
},
"Bigl" => Cmd::SizedDelim {
size: DelimSize::BBig,
class: Some(AtomClass::Open),
},
"biggl" => Cmd::SizedDelim {
size: DelimSize::Bigg,
class: Some(AtomClass::Open),
},
"Biggl" => Cmd::SizedDelim {
size: DelimSize::BBigg,
class: Some(AtomClass::Open),
},
"bigr" => Cmd::SizedDelim {
size: DelimSize::Big,
class: Some(AtomClass::Close),
},
"Bigr" => Cmd::SizedDelim {
size: DelimSize::BBig,
class: Some(AtomClass::Close),
},
"biggr" => Cmd::SizedDelim {
size: DelimSize::Bigg,
class: Some(AtomClass::Close),
},
"Biggr" => Cmd::SizedDelim {
size: DelimSize::BBigg,
class: Some(AtomClass::Close),
},
"bigm" => Cmd::SizedDelim {
size: DelimSize::Big,
class: Some(AtomClass::Rel),
},
"Bigm" => Cmd::SizedDelim {
size: DelimSize::BBig,
class: Some(AtomClass::Rel),
},
"biggm" => Cmd::SizedDelim {
size: DelimSize::Bigg,
class: Some(AtomClass::Rel),
},
"Biggm" => Cmd::SizedDelim {
size: DelimSize::BBigg,
class: Some(AtomClass::Rel),
},
"left" => Cmd::Left,
"right" => Cmd::Right,
"limits" => Cmd::Limits,
"nolimits" => Cmd::NoLimits,
"begin" => Cmd::Begin,
"end" => Cmd::End,
"centering" => Cmd::AlignDecl(LineAlign::Center),
"doublespacing" => Cmd::LineSpacing(1.667),
"dx" => Cmd::UnsupportedT2,
_ => return None,
})
}
#[inline(always)]
pub(crate) fn ding_char(code: u32) -> Option<char> {
match code {
51 => Some('✓'),
_ => None,
}
}
#[inline(always)]
pub(crate) fn lookup_env(name: &str) -> Option<EnvDef> {
match name {
"array" => Some(EnvDef { has_spec: true }),
"align" | "align*" | "aligned" | "cases" | "matrix" | "pmatrix" | "bmatrix" | "Bmatrix"
| "vmatrix" | "Vmatrix" | "smallmatrix" | "substack" => Some(EnvDef { has_spec: false }),
_ => None,
}
}
#[inline(always)]
pub(crate) fn line_align_env(name: &str) -> Option<LineAlign> {
match name {
"flushleft" => Some(LineAlign::Left),
"center" => Some(LineAlign::Center),
"flushright" => Some(LineAlign::Right),
_ => None,
}
}
#[inline(always)]
pub(crate) fn control_symbol_is_t2(ch: char) -> bool {
let _ = ch;
false
}
pub(crate) fn compose_text_accent(accent: char, base: char) -> Option<char> {
Some(match (accent, base) {
('\'', 'a') => 'á',
('\'', 'e') => 'é',
('\'', 'i') => 'í',
('\'', 'o') => 'ó',
('\'', 'u') => 'ú',
('\'', 'y') => 'ý',
('\'', 'A') => 'Á',
('\'', 'E') => 'É',
('\'', 'I') => 'Í',
('\'', 'O') => 'Ó',
('\'', 'U') => 'Ú',
('"', 'a') => 'ä',
('"', 'e') => 'ë',
('"', 'i') => 'ï',
('"', 'o') => 'ö',
('"', 'u') => 'ü',
('"', 'y') => 'ÿ',
('"', 'A') => 'Ä',
('"', 'E') => 'Ë',
('"', 'I') => 'Ï',
('"', 'O') => 'Ö',
('"', 'U') => 'Ü',
_ => return None,
})
}
pub(crate) fn char_is_delim(ch: char) -> bool {
matches!(ch, '(' | ')' | '[' | ']' | '|' | '/' | '<' | '>' | '.')
}
#[must_use]
pub fn construct_status(construct: &str) -> ConstructStatus {
match construct {
"script:sup" | "script:sub" | "prime" | "tie" | "alignment-tab" | "math-island" => {
return ConstructStatus::Supported;
}
_ => {}
}
if construct.starts_with("char:U+") {
return ConstructStatus::Supported;
}
if let Some(env) = construct.strip_prefix("env:") {
if lookup_env(env).is_some() || line_align_env(env).is_some() {
return ConstructStatus::Supported;
}
return ConstructStatus::Unknown;
}
if let Some(name) = construct.strip_prefix('\\') {
let mut chars = name.chars();
if let (Some(c), None) = (chars.next(), chars.next()) {
if !c.is_ascii_alphabetic() {
if control_symbol_is_t2(c) {
return ConstructStatus::UnsupportedT2;
}
return if matches!(
c,
'\\' | ','
| ':'
| ';'
| '!'
| ' '
| '{'
| '}'
| '%'
| '$'
| '&'
| '#'
| '_'
| '|'
| '\''
| '"'
) {
ConstructStatus::Supported
} else {
ConstructStatus::Unknown
};
}
}
if matches!(name, "newcommand" | "renewcommand") {
return ConstructStatus::Supported;
}
return match lookup(name) {
Some(Cmd::UnsupportedT2) => ConstructStatus::UnsupportedT2,
Some(_) => ConstructStatus::Supported,
None => ConstructStatus::Unknown,
};
}
ConstructStatus::Unknown
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn t1_headliners_are_supported() {
for c in [
r"\frac",
r"\over",
r"\text",
r"\pi",
r"\cdot",
r"\left",
r"\right",
r"\sqrt",
r"\sum",
r"\mathds",
r"\minus",
r"\checkmark",
r"\textbf",
r"\emph",
r"\big",
r"\substack",
r"\,",
r"\\",
r"\{",
"env:array",
"env:substack",
"env:align*",
"env:cases",
"env:aligned",
"script:sup",
"math-island",
"prime",
"alignment-tab",
"tie",
] {
assert_eq!(
construct_status(c),
ConstructStatus::Supported,
"expected {c} supported"
);
}
}
#[test]
fn t2_vocabulary_is_tiered() {
assert_eq!(
construct_status(r"\dx"),
ConstructStatus::UnsupportedT2,
r"expected \dx tier-2 (the last pending construct)"
);
for c in [
r"\nmid",
r"\oiint",
r"\i",
r"\j",
r"\circlearrowright",
r"\dddot",
r"\ddddot",
r"\xrightarrow",
r"\xmapsto",
r"\doublespacing",
r"\'",
"\\\"",
] {
assert_eq!(
construct_status(c),
ConstructStatus::Supported,
"expected {c} graduated"
);
}
}
#[test]
fn astronomy_and_misc_symbols_are_supported() {
for c in [
r"\female",
r"\male",
r"\mars",
r"\earth",
r"\copyright",
r"\ding",
] {
assert_eq!(
construct_status(c),
ConstructStatus::Supported,
"expected {c} supported"
);
}
}
#[test]
fn line_alignment_constructs_are_supported() {
for c in [
r"\centering",
"env:flushleft",
"env:center",
"env:flushright",
] {
assert_eq!(
construct_status(c),
ConstructStatus::Supported,
"expected {c} supported"
);
}
}
#[test]
fn size_declarations_are_supported() {
for c in [
r"\tiny",
r"\footnotesize",
r"\small",
r"\large",
r"\Large",
r"\huge",
] {
assert_eq!(
construct_status(c),
ConstructStatus::Supported,
"expected {c} supported"
);
}
}
#[test]
fn unknown_vocabulary_is_unknown() {
assert_eq!(construct_status(r"\notacommand"), ConstructStatus::Unknown);
assert_eq!(construct_status("env:mystery"), ConstructStatus::Unknown);
}
#[test]
fn char_constructs_are_parse_supported() {
assert_eq!(construct_status("char:U+00F6"), ConstructStatus::Supported);
}
}