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}