internal/texmath/symbols.go

184 lines · 8228 bytes

16 symbols in this file
  1package texmath
  2
  3type sym struct {
  4	tag     string
  5	text    string
  6	upright bool // mathvariant="normal": TeX sets capital Greek upright
  7	fixed   bool // stretchy="false": a bracket typed without \left
  8	limits  bool
  9}
 10
 11func mi(s string) sym      { return sym{tag: "mi", text: s} }
 12func mo(s string) sym      { return sym{tag: "mo", text: s} }
 13func upright(s string) sym { return sym{tag: "mi", text: s, upright: true} }
 14func bracket(s string) sym { return sym{tag: "mo", text: s, fixed: true} }
 15func large(s string) sym   { return sym{tag: "mo", text: s, limits: true} }
 16
 17var symbols = map[string]sym{
 18	// Greek
 19	"alpha": mi("α"), "beta": mi("β"), "gamma": mi("γ"), "delta": mi("δ"),
 20	"epsilon": mi("ϵ"), "varepsilon": mi("ε"), "zeta": mi("ζ"), "eta": mi("η"),
 21	"theta": mi("θ"), "vartheta": mi("ϑ"), "iota": mi("ι"), "kappa": mi("κ"),
 22	"lambda": mi("λ"), "mu": mi("μ"), "nu": mi("ν"), "xi": mi("ξ"),
 23	"omicron": mi("ο"), "pi": mi("π"), "varpi": mi("ϖ"), "rho": mi("ρ"),
 24	"varrho": mi("ϱ"), "sigma": mi("σ"), "varsigma": mi("ς"), "tau": mi("τ"),
 25	"upsilon": mi("υ"), "phi": mi("ϕ"), "varphi": mi("φ"), "chi": mi("χ"),
 26	"psi": mi("ψ"), "omega": mi("ω"),
 27	"Gamma": upright("Γ"), "Delta": upright("Δ"), "Theta": upright("Θ"),
 28	"Lambda": upright("Λ"), "Xi": upright("Ξ"), "Pi": upright("Π"),
 29	"Sigma": upright("Σ"), "Upsilon": upright("Υ"), "Phi": upright("Φ"),
 30	"Psi": upright("Ψ"), "Omega": upright("Ω"),
 31
 32	// Letter-like
 33	"infty": mi("∞"), "partial": mi("∂"), "nabla": mi("∇"), "emptyset": mi("∅"),
 34	"varnothing": mi("∅"), "hbar": mi("ℏ"), "ell": mi("ℓ"), "Re": mi("ℜ"),
 35	"Im": mi("ℑ"), "aleph": mi("ℵ"), "wp": mi("℘"), "imath": mi("ı"), "jmath": mi("ȷ"),
 36
 37	// Binary operators
 38	"pm": mo("±"), "mp": mo("∓"), "times": mo("×"), "div": mo("÷"),
 39	"cdot": mo("⋅"), "ast": mo("∗"), "star": mo("⋆"), "circ": mo("∘"),
 40	"bullet": mo("∙"), "cap": mo("∩"), "cup": mo("∪"), "setminus": mo("∖"),
 41	"wedge": mo("∧"), "land": mo("∧"), "vee": mo("∨"), "lor": mo("∨"),
 42	"oplus": mo("⊕"), "ominus": mo("⊖"), "otimes": mo("⊗"), "odot": mo("⊙"),
 43	"sqcup": mo("⊔"), "sqcap": mo("⊓"), "dagger": mo("†"), "ddagger": mo("‡"),
 44	"lnot": mo("¬"), "neg": mo("¬"),
 45
 46	// Relations
 47	"le": mo("≤"), "leq": mo("≤"), "ge": mo("≥"), "geq": mo("≥"),
 48	"ne": mo("≠"), "neq": mo("≠"), "ll": mo("≪"), "gg": mo("≫"),
 49	"approx": mo("≈"), "equiv": mo("≡"), "sim": mo("∼"), "simeq": mo("≃"),
 50	"cong": mo("≅"), "propto": mo("∝"), "in": mo("∈"), "notin": mo("∉"),
 51	"ni": mo("∋"), "subset": mo("⊂"), "supset": mo("⊃"), "subseteq": mo("⊆"),
 52	"supseteq": mo("⊇"), "perp": mo("⊥"), "parallel": mo("∥"), "mid": mo("∣"),
 53	"vdash": mo("⊢"), "models": mo("⊨"), "coloneqq": mo("≔"), "prec": mo("≺"),
 54	"succ": mo("≻"), "preceq": mo("⪯"), "succeq": mo("⪰"), "doteq": mo("≐"),
 55
 56	// Arrows
 57	"to": mo("→"), "rightarrow": mo("→"), "leftarrow": mo("←"), "gets": mo("←"),
 58	"leftrightarrow": mo("↔"), "Rightarrow": mo("⇒"), "Leftarrow": mo("⇐"),
 59	"Leftrightarrow": mo("⇔"), "implies": mo("⟹"), "impliedby": mo("⟸"),
 60	"iff": mo("⟺"), "mapsto": mo("↦"), "longrightarrow": mo("⟶"),
 61	"longleftarrow": mo("⟵"), "Longrightarrow": mo("⟹"), "uparrow": mo("↑"),
 62	"downarrow": mo("↓"), "hookrightarrow": mo("↪"), "rightharpoonup": mo("⇀"),
 63
 64	// Logic and sets
 65	"forall": mo("∀"), "exists": mo("∃"), "nexists": mo("∄"), "therefore": mo("∴"),
 66	"because": mo("∵"), "top": mo("⊤"), "bot": mo("⊥"), "angle": mo("∠"),
 67	"prime": mo("′"), "degree": mo("°"),
 68
 69	// Dots
 70	"ldots": mo("…"), "dots": mo("…"), "cdots": mo("⋯"), "vdots": mo("⋮"),
 71	"ddots": mo("⋱"),
 72
 73	// Brackets typed without \left
 74	"{": bracket("{"), "}": bracket("}"), "|": bracket("‖"),
 75	"langle": bracket("⟨"), "rangle": bracket("⟩"), "lvert": bracket("|"),
 76	"rvert": bracket("|"), "lVert": bracket("‖"), "rVert": bracket("‖"),
 77	"vert": bracket("|"), "Vert": bracket("‖"), "lfloor": bracket("⌊"),
 78	"rfloor": bracket("⌋"), "lceil": bracket("⌈"), "rceil": bracket("⌉"),
 79	"lbrace": bracket("{"), "rbrace": bracket("}"), "backslash": mo("\\"),
 80
 81	// Escaped characters
 82	"%": mo("%"), "$": mo("$"), "#": mo("#"), "&": mo("&"), "_": mo("_"),
 83
 84	// Large operators
 85	"sum": large("∑"), "prod": large("∏"), "coprod": large("∐"),
 86	"bigcup": large("⋃"), "bigcap": large("⋂"), "bigvee": large("⋁"),
 87	"bigwedge": large("⋀"), "bigoplus": large("⨁"), "bigotimes": large("⨂"),
 88	"bigsqcup": large("⨆"),
 89	"int":      mo("∫"), "iint": mo("∬"), "iiint": mo("∭"), "oint": mo("∮"),
 90}
 91
 92// spaces are the spacing commands and their widths.
 93var spaces = map[string]string{
 94	",": "0.1667em", "thinspace": "0.1667em",
 95	":": "0.2222em", ">": "0.2222em", "medspace": "0.2222em",
 96	";": "0.2778em", "thickspace": "0.2778em",
 97	"!": "-0.1667em", "negthinspace": "-0.1667em",
 98	" ": "0.3333em", "enspace": "0.5em",
 99	"quad": "1em", "qquad": "2em",
100}
101
102// functions are the named functions, set upright; true takes limits under
103// and over in display style.
104var functions = map[string]bool{
105	"sin": false, "cos": false, "tan": false, "cot": false, "sec": false, "csc": false,
106	"arcsin": false, "arccos": false, "arctan": false, "sinh": false, "cosh": false,
107	"tanh": false, "coth": false, "log": false, "ln": false, "lg": false, "exp": false,
108	"dim": false, "deg": false, "hom": false, "ker": false, "arg": false,
109	"lim": true, "liminf": true, "limsup": true, "max": true, "min": true,
110	"sup": true, "inf": true, "det": true, "gcd": true, "Pr": true,
111}
112
113type accent struct {
114	mark   string
115	accent bool // mover accent="true": the mark sits close, like an accent
116	under  bool
117}
118
119var accents = map[string]accent{
120	"hat": {mark: "^", accent: true}, "widehat": {mark: "^", accent: true},
121	"tilde": {mark: "~", accent: true}, "widetilde": {mark: "~", accent: true},
122	"bar": {mark: "¯", accent: true}, "overline": {mark: "‾", accent: true},
123	"vec": {mark: "→", accent: true}, "overrightarrow": {mark: "→", accent: true},
124	"dot": {mark: "˙", accent: true}, "ddot": {mark: "¨", accent: true},
125	"acute": {mark: "´", accent: true}, "grave": {mark: "`", accent: true},
126	"breve": {mark: "˘", accent: true}, "check": {mark: "ˇ", accent: true},
127	"overbrace":  {mark: "⏞"},
128	"underline":  {mark: "_", under: true},
129	"underbrace": {mark: "⏟", under: true},
130}
131
132var fonts = map[string]string{
133	"mathrm": "rm", "mathbf": "bf", "boldsymbol": "bf", "bm": "bf",
134	"mathbb": "bb", "mathcal": "cal", "mathscr": "cal", "mathfrak": "frak",
135	"mathsf": "sf", "mathtt": "tt", "mathit": "it",
136}
137
138var delimiters = map[string]string{
139	"{": "{", "}": "}", "lbrace": "{", "rbrace": "}", "|": "‖",
140	"langle": "⟨", "rangle": "⟩", "lvert": "|", "rvert": "|", "vert": "|",
141	"lVert": "‖", "rVert": "‖", "Vert": "‖", "lfloor": "⌊", "rfloor": "⌋",
142	"lceil": "⌈", "rceil": "⌉", "backslash": "\\",
143}
144
145// alphabet is where a font's capitals, small letters and digits start in
146// Mathematical Alphanumeric Symbols (0 where the font has none), plus the
147// letters Unicode had already encoded elsewhere and left as holes.
148type alphabet struct {
149	upper, lower, digit rune
150	holes               map[rune]rune
151}
152
153var alphabets = map[string]alphabet{
154	"bf": {0x1D400, 0x1D41A, 0x1D7CE, nil},
155	"it": {0x1D434, 0x1D44E, 0, map[rune]rune{'h': 'ℎ'}},
156	"bb": {0x1D538, 0x1D552, 0x1D7D8, map[rune]rune{
157		'C': 'ℂ', 'H': 'ℍ', 'N': 'ℕ', 'P': 'ℙ', 'Q': 'ℚ', 'R': 'ℝ', 'Z': 'ℤ'}},
158	"cal": {0x1D49C, 0x1D4B6, 0, map[rune]rune{
159		'B': 'ℬ', 'E': 'ℰ', 'F': 'ℱ', 'H': 'ℋ', 'I': 'ℐ', 'L': 'ℒ', 'M': 'ℳ',
160		'R': 'ℛ', 'e': 'ℯ', 'g': 'ℊ', 'o': 'ℴ'}},
161	"frak": {0x1D504, 0x1D51E, 0, map[rune]rune{
162		'C': 'ℭ', 'H': 'ℌ', 'I': 'ℑ', 'R': 'ℜ', 'Z': 'ℨ'}},
163	"sf": {0x1D5A0, 0x1D5BA, 0x1D7E2, nil},
164	"tt": {0x1D670, 0x1D68A, 0x1D7F6, nil},
165}
166
167func alphanumeric(font string, r rune) rune {
168	a, ok := alphabets[font]
169	if !ok {
170		return r
171	}
172	if h, ok := a.holes[r]; ok {
173		return h
174	}
175	switch {
176	case r >= 'A' && r <= 'Z':
177		return a.upper + r - 'A'
178	case r >= 'a' && r <= 'z':
179		return a.lower + r - 'a'
180	case r >= '0' && r <= '9' && a.digit != 0:
181		return a.digit + r - '0'
182	}
183	return r
184}