@ny4n/tui 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +948 -2
  3. package/dist/alt-screen-search.d.ts +46 -0
  4. package/dist/alt-screen-search.d.ts.map +1 -0
  5. package/dist/alt-screen-search.js +282 -0
  6. package/dist/alt-screen-search.js.map +1 -0
  7. package/dist/autocomplete.d.ts +57 -0
  8. package/dist/autocomplete.d.ts.map +1 -0
  9. package/dist/autocomplete.js +693 -0
  10. package/dist/autocomplete.js.map +1 -0
  11. package/dist/colors.d.ts +73 -0
  12. package/dist/colors.d.ts.map +1 -0
  13. package/dist/colors.js +273 -0
  14. package/dist/colors.js.map +1 -0
  15. package/dist/components/alt-screen-flash.d.ts +13 -0
  16. package/dist/components/alt-screen-flash.d.ts.map +1 -0
  17. package/dist/components/alt-screen-flash.js +37 -0
  18. package/dist/components/alt-screen-flash.js.map +1 -0
  19. package/dist/components/box.d.ts +25 -0
  20. package/dist/components/box.d.ts.map +1 -0
  21. package/dist/components/box.js +138 -0
  22. package/dist/components/box.js.map +1 -0
  23. package/dist/components/cancellable-loader.d.ts +22 -0
  24. package/dist/components/cancellable-loader.d.ts.map +1 -0
  25. package/dist/components/cancellable-loader.js +35 -0
  26. package/dist/components/cancellable-loader.js.map +1 -0
  27. package/dist/components/editor.d.ts +260 -0
  28. package/dist/components/editor.d.ts.map +1 -0
  29. package/dist/components/editor.js +2044 -0
  30. package/dist/components/editor.js.map +1 -0
  31. package/dist/components/h-stack.d.ts +7 -0
  32. package/dist/components/h-stack.d.ts.map +1 -0
  33. package/dist/components/h-stack.js +43 -0
  34. package/dist/components/h-stack.js.map +1 -0
  35. package/dist/components/image.d.ts +40 -0
  36. package/dist/components/image.d.ts.map +1 -0
  37. package/dist/components/image.js +123 -0
  38. package/dist/components/image.js.map +1 -0
  39. package/dist/components/input.d.ts +48 -0
  40. package/dist/components/input.d.ts.map +1 -0
  41. package/dist/components/input.js +417 -0
  42. package/dist/components/input.js.map +1 -0
  43. package/dist/components/loader.d.ts +33 -0
  44. package/dist/components/loader.d.ts.map +1 -0
  45. package/dist/components/loader.js +76 -0
  46. package/dist/components/loader.js.map +1 -0
  47. package/dist/components/markdown.d.ts +104 -0
  48. package/dist/components/markdown.d.ts.map +1 -0
  49. package/dist/components/markdown.js +821 -0
  50. package/dist/components/markdown.js.map +1 -0
  51. package/dist/components/mouse-region.d.ts +12 -0
  52. package/dist/components/mouse-region.d.ts.map +1 -0
  53. package/dist/components/mouse-region.js +21 -0
  54. package/dist/components/mouse-region.js.map +1 -0
  55. package/dist/components/scroll-view.d.ts +59 -0
  56. package/dist/components/scroll-view.d.ts.map +1 -0
  57. package/dist/components/scroll-view.js +195 -0
  58. package/dist/components/scroll-view.js.map +1 -0
  59. package/dist/components/select-list.d.ts +53 -0
  60. package/dist/components/select-list.d.ts.map +1 -0
  61. package/dist/components/select-list.js +206 -0
  62. package/dist/components/select-list.js.map +1 -0
  63. package/dist/components/settings-list.d.ts +60 -0
  64. package/dist/components/settings-list.d.ts.map +1 -0
  65. package/dist/components/settings-list.js +252 -0
  66. package/dist/components/settings-list.js.map +1 -0
  67. package/dist/components/spacer.d.ts +12 -0
  68. package/dist/components/spacer.d.ts.map +1 -0
  69. package/dist/components/spacer.js +23 -0
  70. package/dist/components/spacer.js.map +1 -0
  71. package/dist/components/stack.d.ts +32 -0
  72. package/dist/components/stack.d.ts.map +1 -0
  73. package/dist/components/stack.js +111 -0
  74. package/dist/components/stack.js.map +1 -0
  75. package/dist/components/text.d.ts +20 -0
  76. package/dist/components/text.d.ts.map +1 -0
  77. package/dist/components/text.js +95 -0
  78. package/dist/components/text.js.map +1 -0
  79. package/dist/components/truncated-text.d.ts +13 -0
  80. package/dist/components/truncated-text.d.ts.map +1 -0
  81. package/dist/components/truncated-text.js +51 -0
  82. package/dist/components/truncated-text.js.map +1 -0
  83. package/dist/components/v-stack.d.ts +8 -0
  84. package/dist/components/v-stack.d.ts.map +1 -0
  85. package/dist/components/v-stack.js +26 -0
  86. package/dist/components/v-stack.js.map +1 -0
  87. package/dist/editor-component.d.ts +39 -0
  88. package/dist/editor-component.d.ts.map +1 -0
  89. package/dist/editor-component.js +2 -0
  90. package/dist/editor-component.js.map +1 -0
  91. package/dist/fuzzy.d.ts +16 -0
  92. package/dist/fuzzy.d.ts.map +1 -0
  93. package/dist/fuzzy.js +111 -0
  94. package/dist/fuzzy.js.map +1 -0
  95. package/dist/index.d.ts +37 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +50 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/keybindings.d.ts +273 -0
  100. package/dist/keybindings.d.ts.map +1 -0
  101. package/dist/keybindings.js +233 -0
  102. package/dist/keybindings.js.map +1 -0
  103. package/dist/keys.d.ts +184 -0
  104. package/dist/keys.d.ts.map +1 -0
  105. package/dist/keys.js +1206 -0
  106. package/dist/keys.js.map +1 -0
  107. package/dist/kill-ring.d.ts +28 -0
  108. package/dist/kill-ring.d.ts.map +1 -0
  109. package/dist/kill-ring.js +44 -0
  110. package/dist/kill-ring.js.map +1 -0
  111. package/dist/latex.d.ts +10 -0
  112. package/dist/latex.d.ts.map +1 -0
  113. package/dist/latex.js +1378 -0
  114. package/dist/latex.js.map +1 -0
  115. package/dist/layout-node.d.ts +40 -0
  116. package/dist/layout-node.d.ts.map +1 -0
  117. package/dist/layout-node.js +6 -0
  118. package/dist/layout-node.js.map +1 -0
  119. package/dist/layout.d.ts +42 -0
  120. package/dist/layout.d.ts.map +1 -0
  121. package/dist/layout.js +344 -0
  122. package/dist/layout.js.map +1 -0
  123. package/dist/native-modifiers.d.ts +4 -0
  124. package/dist/native-modifiers.d.ts.map +1 -0
  125. package/dist/native-modifiers.js +13 -0
  126. package/dist/native-modifiers.js.map +1 -0
  127. package/dist/native-module-path.d.ts +7 -0
  128. package/dist/native-module-path.d.ts.map +1 -0
  129. package/dist/native-module-path.js +19 -0
  130. package/dist/native-module-path.js.map +1 -0
  131. package/dist/native-platform.d.ts +20 -0
  132. package/dist/native-platform.d.ts.map +1 -0
  133. package/dist/native-platform.js +42 -0
  134. package/dist/native-platform.js.map +1 -0
  135. package/dist/oklab.d.ts +43 -0
  136. package/dist/oklab.d.ts.map +1 -0
  137. package/dist/oklab.js +210 -0
  138. package/dist/oklab.js.map +1 -0
  139. package/dist/program-status.d.ts +23 -0
  140. package/dist/program-status.d.ts.map +1 -0
  141. package/dist/program-status.js +43 -0
  142. package/dist/program-status.js.map +1 -0
  143. package/dist/stdin-buffer.d.ts +56 -0
  144. package/dist/stdin-buffer.d.ts.map +1 -0
  145. package/dist/stdin-buffer.js +366 -0
  146. package/dist/stdin-buffer.js.map +1 -0
  147. package/dist/terminal-colors.d.ts +27 -0
  148. package/dist/terminal-colors.d.ts.map +1 -0
  149. package/dist/terminal-colors.js +64 -0
  150. package/dist/terminal-colors.js.map +1 -0
  151. package/dist/terminal-image.d.ts +123 -0
  152. package/dist/terminal-image.d.ts.map +1 -0
  153. package/dist/terminal-image.js +603 -0
  154. package/dist/terminal-image.js.map +1 -0
  155. package/dist/terminal.d.ts +143 -0
  156. package/dist/terminal.d.ts.map +1 -0
  157. package/dist/terminal.js +493 -0
  158. package/dist/terminal.js.map +1 -0
  159. package/dist/tui-alt-screen.d.ts +168 -0
  160. package/dist/tui-alt-screen.d.ts.map +1 -0
  161. package/dist/tui-alt-screen.js +1552 -0
  162. package/dist/tui-alt-screen.js.map +1 -0
  163. package/dist/tui-main-screen.d.ts +39 -0
  164. package/dist/tui-main-screen.d.ts.map +1 -0
  165. package/dist/tui-main-screen.js +595 -0
  166. package/dist/tui-main-screen.js.map +1 -0
  167. package/dist/tui.d.ts +398 -0
  168. package/dist/tui.d.ts.map +1 -0
  169. package/dist/tui.js +1096 -0
  170. package/dist/tui.js.map +1 -0
  171. package/dist/undo-stack.d.ts +17 -0
  172. package/dist/undo-stack.d.ts.map +1 -0
  173. package/dist/undo-stack.js +25 -0
  174. package/dist/undo-stack.js.map +1 -0
  175. package/dist/utils.d.ts +107 -0
  176. package/dist/utils.d.ts.map +1 -0
  177. package/dist/utils.js +1263 -0
  178. package/dist/utils.js.map +1 -0
  179. package/dist/wheel-scroll.d.ts +23 -0
  180. package/dist/wheel-scroll.d.ts.map +1 -0
  181. package/dist/wheel-scroll.js +73 -0
  182. package/dist/wheel-scroll.js.map +1 -0
  183. package/dist/word-navigation.d.ts +25 -0
  184. package/dist/word-navigation.d.ts.map +1 -0
  185. package/dist/word-navigation.js +96 -0
  186. package/dist/word-navigation.js.map +1 -0
  187. package/native/clipboard.h +208 -0
  188. package/native/darwin/README.md +22 -0
  189. package/native/darwin/build.sh +69 -0
  190. package/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
  191. package/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
  192. package/native/darwin/src/darwin-platform.m +132 -0
  193. package/native/linux/README.md +23 -0
  194. package/native/linux/build.sh +65 -0
  195. package/native/linux/prebuilds/linux-arm64/linux-platform-x11.node +0 -0
  196. package/native/linux/prebuilds/linux-x64/linux-platform-x11.node +0 -0
  197. package/native/linux/src/clipboard-worker.h +70 -0
  198. package/native/linux/src/linux-platform-x11.c +274 -0
  199. package/native/napi.h +91 -0
  200. package/native/win32/README.md +31 -0
  201. package/native/win32/build.mjs +232 -0
  202. package/native/win32/prebuilds/win32-arm64/win32-platform.node +0 -0
  203. package/native/win32/prebuilds/win32-x64/win32-platform.node +0 -0
  204. package/native/win32/src/win32-platform.c +241 -0
  205. package/package.json +61 -5
package/dist/latex.js ADDED
@@ -0,0 +1,1378 @@
1
+ import { visibleWidth } from "./utils.js";
2
+ const SYMBOLS = {
3
+ alpha: "α",
4
+ beta: "β",
5
+ gamma: "γ",
6
+ delta: "δ",
7
+ epsilon: "ϵ",
8
+ varepsilon: "ε",
9
+ zeta: "ζ",
10
+ eta: "η",
11
+ theta: "θ",
12
+ vartheta: "ϑ",
13
+ iota: "ι",
14
+ kappa: "κ",
15
+ varkappa: "ϰ",
16
+ lambda: "λ",
17
+ mu: "μ",
18
+ nu: "ν",
19
+ xi: "ξ",
20
+ pi: "π",
21
+ varpi: "ϖ",
22
+ rho: "ρ",
23
+ varrho: "ϱ",
24
+ sigma: "σ",
25
+ varsigma: "ς",
26
+ tau: "τ",
27
+ upsilon: "υ",
28
+ phi: "ϕ",
29
+ varphi: "φ",
30
+ chi: "χ",
31
+ psi: "ψ",
32
+ omega: "ω",
33
+ Gamma: "Γ",
34
+ Delta: "Δ",
35
+ Theta: "Θ",
36
+ Lambda: "Λ",
37
+ Xi: "Ξ",
38
+ Pi: "Π",
39
+ Sigma: "Σ",
40
+ Upsilon: "Υ",
41
+ Phi: "Φ",
42
+ Psi: "Ψ",
43
+ Omega: "Ω",
44
+ pm: "±",
45
+ mp: "∓",
46
+ times: "×",
47
+ div: "÷",
48
+ cdot: "·",
49
+ ast: "∗",
50
+ star: "⋆",
51
+ circ: "∘",
52
+ bullet: "•",
53
+ oplus: "⊕",
54
+ ominus: "⊖",
55
+ otimes: "⊗",
56
+ oslash: "⊘",
57
+ odot: "⊙",
58
+ bigcirc: "○",
59
+ dagger: "†",
60
+ ddagger: "‡",
61
+ amalg: "⨿",
62
+ uplus: "⊎",
63
+ sqcap: "⊓",
64
+ sqcup: "⊔",
65
+ bowtie: "⋈",
66
+ Join: "⋈",
67
+ ltimes: "⋉",
68
+ rtimes: "⋊",
69
+ leftouterjoin: "⟕",
70
+ rightouterjoin: "⟖",
71
+ fullouterjoin: "⟗",
72
+ triangleleft: "◁",
73
+ triangleright: "▷",
74
+ wr: "≀",
75
+ cap: "∩",
76
+ cup: "∪",
77
+ bigcap: "⋂",
78
+ bigcup: "⋃",
79
+ bigwedge: "⋀",
80
+ bigvee: "⋁",
81
+ bigsqcup: "⨆",
82
+ biguplus: "⨄",
83
+ bigoplus: "⨁",
84
+ bigotimes: "⨂",
85
+ bigodot: "⨀",
86
+ setminus: "∖",
87
+ in: "∈",
88
+ notin: "∉",
89
+ ni: "∋",
90
+ subset: "⊂",
91
+ supset: "⊃",
92
+ subseteq: "⊆",
93
+ supseteq: "⊇",
94
+ sqsubset: "⊏",
95
+ sqsupset: "⊐",
96
+ sqsubseteq: "⊑",
97
+ sqsupseteq: "⊒",
98
+ prec: "≺",
99
+ preceq: "≼",
100
+ succ: "≻",
101
+ succeq: "≽",
102
+ ll: "≪",
103
+ gg: "≫",
104
+ le: "≤",
105
+ leq: "≤",
106
+ leqslant: "≤",
107
+ ge: "≥",
108
+ geq: "≥",
109
+ geqslant: "≥",
110
+ ne: "≠",
111
+ neq: "≠",
112
+ equiv: "≡",
113
+ approx: "≈",
114
+ sim: "∼",
115
+ simeq: "≃",
116
+ cong: "≅",
117
+ asymp: "≍",
118
+ doteq: "≐",
119
+ propto: "∝",
120
+ parallel: "∥",
121
+ perp: "⊥",
122
+ mid: "∣",
123
+ vdash: "⊢",
124
+ dashv: "⊣",
125
+ models: "⊨",
126
+ Vdash: "⊩",
127
+ Vvdash: "⊪",
128
+ nvdash: "⊬",
129
+ nvDash: "⊭",
130
+ forall: "∀",
131
+ exists: "∃",
132
+ nexists: "∄",
133
+ neg: "¬",
134
+ land: "∧",
135
+ wedge: "∧",
136
+ lor: "∨",
137
+ vee: "∨",
138
+ to: "→",
139
+ rightarrow: "→",
140
+ longrightarrow: "→",
141
+ leftarrow: "←",
142
+ longleftarrow: "←",
143
+ gets: "←",
144
+ leftrightarrow: "↔",
145
+ longleftrightarrow: "↔",
146
+ hookleftarrow: "↩",
147
+ hookrightarrow: "↪",
148
+ twoheadleftarrow: "↞",
149
+ twoheadrightarrow: "↠",
150
+ leftharpoonup: "↼",
151
+ leftharpoondown: "↽",
152
+ rightharpoonup: "⇀",
153
+ rightharpoondown: "⇁",
154
+ rightleftharpoons: "⇌",
155
+ leftrightharpoons: "⇋",
156
+ nearrow: "↗",
157
+ searrow: "↘",
158
+ swarrow: "↙",
159
+ nwarrow: "↖",
160
+ rightsquigarrow: "⇝",
161
+ leadsto: "⇝",
162
+ Rightarrow: "⇒",
163
+ Longrightarrow: "⇒",
164
+ Leftarrow: "⇐",
165
+ Longleftarrow: "⇐",
166
+ Leftrightarrow: "⇔",
167
+ Longleftrightarrow: "⇔",
168
+ implies: "⇒",
169
+ iff: "⇔",
170
+ mapsto: "↦",
171
+ longmapsto: "↦",
172
+ uparrow: "↑",
173
+ downarrow: "↓",
174
+ partial: "∂",
175
+ nabla: "∇",
176
+ int: "∫",
177
+ iint: "∬",
178
+ iiint: "∭",
179
+ oint: "∮",
180
+ sum: "∑",
181
+ prod: "∏",
182
+ coprod: "∐",
183
+ infty: "∞",
184
+ emptyset: "∅",
185
+ varnothing: "∅",
186
+ angle: "∠",
187
+ therefore: "∴",
188
+ because: "∵",
189
+ aleph: "ℵ",
190
+ beth: "ℶ",
191
+ gimel: "ℷ",
192
+ daleth: "ℸ",
193
+ top: "⊤",
194
+ bot: "⊥",
195
+ triangle: "△",
196
+ square: "□",
197
+ lozenge: "◊",
198
+ checkmark: "✓",
199
+ complement: "∁",
200
+ wp: "℘",
201
+ prime: "′",
202
+ ldots: "…",
203
+ dots: "…",
204
+ cdots: "⋯",
205
+ vdots: "⋮",
206
+ ddots: "⋱",
207
+ ell: "ℓ",
208
+ hbar: "ℏ",
209
+ Im: "ℑ",
210
+ Re: "ℜ",
211
+ langle: "⟨",
212
+ rangle: "⟩",
213
+ vert: "|",
214
+ lvert: "|",
215
+ rvert: "|",
216
+ Vert: "‖",
217
+ lVert: "‖",
218
+ rVert: "‖",
219
+ lbrace: "{",
220
+ rbrace: "}",
221
+ backslash: "\\",
222
+ lfloor: "⌊",
223
+ rfloor: "⌋",
224
+ lceil: "⌈",
225
+ rceil: "⌉",
226
+ colon: ":",
227
+ };
228
+ const NAMED_OPERATORS = new Set([
229
+ "arccos",
230
+ "arcsin",
231
+ "arctan",
232
+ "arg",
233
+ "cos",
234
+ "cosh",
235
+ "cot",
236
+ "coth",
237
+ "csc",
238
+ "deg",
239
+ "det",
240
+ "dim",
241
+ "exp",
242
+ "gcd",
243
+ "hom",
244
+ "inf",
245
+ "ker",
246
+ "lg",
247
+ "lim",
248
+ "liminf",
249
+ "limsup",
250
+ "ln",
251
+ "log",
252
+ "max",
253
+ "min",
254
+ "Pr",
255
+ "sec",
256
+ "sin",
257
+ "sinh",
258
+ "sup",
259
+ "tan",
260
+ "tanh",
261
+ ]);
262
+ const LIMIT_OPERATORS = new Set([
263
+ "argmax",
264
+ "argmin",
265
+ "inf",
266
+ "injlim",
267
+ "lim",
268
+ "liminf",
269
+ "limsup",
270
+ "max",
271
+ "min",
272
+ "projlim",
273
+ "sup",
274
+ ]);
275
+ const DISPLAY_LIMIT_SYMBOLS = new Set([
276
+ "bigcap",
277
+ "bigcup",
278
+ "bigodot",
279
+ "bigoplus",
280
+ "bigotimes",
281
+ "bigsqcup",
282
+ "biguplus",
283
+ "bigvee",
284
+ "bigwedge",
285
+ "coprod",
286
+ "int",
287
+ "iint",
288
+ "iiint",
289
+ "oint",
290
+ "prod",
291
+ "sum",
292
+ ]);
293
+ const RELATION_COMMANDS = new Set([
294
+ "Leftarrow",
295
+ "Leftrightarrow",
296
+ "Longleftarrow",
297
+ "Longleftrightarrow",
298
+ "Longrightarrow",
299
+ "Rightarrow",
300
+ "Join",
301
+ "Vdash",
302
+ "Vvdash",
303
+ "approx",
304
+ "asymp",
305
+ "bowtie",
306
+ "cong",
307
+ "dashv",
308
+ "fullouterjoin",
309
+ "doteq",
310
+ "downarrow",
311
+ "equiv",
312
+ "ge",
313
+ "geq",
314
+ "geqslant",
315
+ "gets",
316
+ "gg",
317
+ "hookleftarrow",
318
+ "hookrightarrow",
319
+ "iff",
320
+ "implies",
321
+ "in",
322
+ "leadsto",
323
+ "le",
324
+ "leftarrow",
325
+ "leftharpoondown",
326
+ "leftharpoonup",
327
+ "leftrightarrow",
328
+ "leftrightharpoons",
329
+ "leftouterjoin",
330
+ "leq",
331
+ "leqslant",
332
+ "ll",
333
+ "longleftarrow",
334
+ "longleftrightarrow",
335
+ "longmapsto",
336
+ "longrightarrow",
337
+ "ltimes",
338
+ "mapsto",
339
+ "mid",
340
+ "models",
341
+ "ne",
342
+ "nearrow",
343
+ "neq",
344
+ "ni",
345
+ "notin",
346
+ "nvdash",
347
+ "nvDash",
348
+ "nwarrow",
349
+ "parallel",
350
+ "perp",
351
+ "prec",
352
+ "preceq",
353
+ "propto",
354
+ "rightharpoondown",
355
+ "rightharpoonup",
356
+ "rightleftharpoons",
357
+ "rightouterjoin",
358
+ "rightarrow",
359
+ "rightsquigarrow",
360
+ "rtimes",
361
+ "searrow",
362
+ "sim",
363
+ "simeq",
364
+ "sqsubset",
365
+ "sqsubseteq",
366
+ "sqsupset",
367
+ "sqsupseteq",
368
+ "subset",
369
+ "subseteq",
370
+ "succ",
371
+ "succeq",
372
+ "supset",
373
+ "supseteq",
374
+ "swarrow",
375
+ "to",
376
+ "triangleleft",
377
+ "triangleright",
378
+ "twoheadleftarrow",
379
+ "twoheadrightarrow",
380
+ "uparrow",
381
+ "vdash",
382
+ ]);
383
+ const NEGATED_SYMBOLS = {
384
+ "<": "≮",
385
+ ">": "≯",
386
+ "=": "≠",
387
+ "∈": "∉",
388
+ "∋": "∌",
389
+ "∣": "∤",
390
+ "∥": "∦",
391
+ "∼": "≁",
392
+ "≃": "≄",
393
+ "≅": "≇",
394
+ "≈": "≉",
395
+ "≡": "≢",
396
+ "≤": "≰",
397
+ "≥": "≱",
398
+ "≺": "⊀",
399
+ "≻": "⊁",
400
+ "⊂": "⊄",
401
+ "⊃": "⊅",
402
+ "⊆": "⊈",
403
+ "⊇": "⊉",
404
+ "⊢": "⊬",
405
+ "⊨": "⊭",
406
+ "↔": "↮",
407
+ "←": "↚",
408
+ "→": "↛",
409
+ "⇒": "⇏",
410
+ "⇐": "⇍",
411
+ "⇔": "⇎",
412
+ "≼": "⋠",
413
+ "≽": "⋡",
414
+ };
415
+ const BLACKBOARD = {
416
+ C: "ℂ",
417
+ H: "ℍ",
418
+ N: "ℕ",
419
+ P: "ℙ",
420
+ Q: "ℚ",
421
+ R: "ℝ",
422
+ Z: "ℤ",
423
+ };
424
+ const SUPERSCRIPTS = {
425
+ "0": "⁰",
426
+ "1": "¹",
427
+ "2": "²",
428
+ "3": "³",
429
+ "4": "⁴",
430
+ "5": "⁵",
431
+ "6": "⁶",
432
+ "7": "⁷",
433
+ "8": "⁸",
434
+ "9": "⁹",
435
+ "+": "⁺",
436
+ "-": "⁻",
437
+ "=": "⁼",
438
+ "(": "⁽",
439
+ ")": "⁾",
440
+ a: "ᵃ",
441
+ b: "ᵇ",
442
+ c: "ᶜ",
443
+ d: "ᵈ",
444
+ e: "ᵉ",
445
+ f: "ᶠ",
446
+ g: "ᵍ",
447
+ h: "ʰ",
448
+ i: "ⁱ",
449
+ j: "ʲ",
450
+ k: "ᵏ",
451
+ l: "ˡ",
452
+ m: "ᵐ",
453
+ n: "ⁿ",
454
+ o: "ᵒ",
455
+ p: "ᵖ",
456
+ r: "ʳ",
457
+ s: "ˢ",
458
+ t: "ᵗ",
459
+ u: "ᵘ",
460
+ v: "ᵛ",
461
+ w: "ʷ",
462
+ x: "ˣ",
463
+ y: "ʸ",
464
+ z: "ᶻ",
465
+ };
466
+ const SUBSCRIPTS = {
467
+ "0": "₀",
468
+ "1": "₁",
469
+ "2": "₂",
470
+ "3": "₃",
471
+ "4": "₄",
472
+ "5": "₅",
473
+ "6": "₆",
474
+ "7": "₇",
475
+ "8": "₈",
476
+ "9": "₉",
477
+ "+": "₊",
478
+ "-": "₋",
479
+ "=": "₌",
480
+ "(": "₍",
481
+ ")": "₎",
482
+ a: "ₐ",
483
+ e: "ₑ",
484
+ h: "ₕ",
485
+ i: "ᵢ",
486
+ j: "ⱼ",
487
+ k: "ₖ",
488
+ l: "ₗ",
489
+ m: "ₘ",
490
+ n: "ₙ",
491
+ o: "ₒ",
492
+ p: "ₚ",
493
+ r: "ᵣ",
494
+ s: "ₛ",
495
+ t: "ₜ",
496
+ u: "ᵤ",
497
+ v: "ᵥ",
498
+ x: "ₓ",
499
+ };
500
+ const SPACING_COMMANDS = new Set([
501
+ ",",
502
+ ":",
503
+ ";",
504
+ " ",
505
+ ">",
506
+ "enspace",
507
+ "enskip",
508
+ "medspace",
509
+ "quad",
510
+ "qquad",
511
+ "thickspace",
512
+ "thinspace",
513
+ ]);
514
+ const NEGATIVE_SPACING_COMMANDS = new Set(["!", "negmedspace", "negthickspace", "negthinspace"]);
515
+ const NEGATIVE_SPACE = "\u0000";
516
+ const FONT_SWITCH_COMMANDS = new Set(["bf", "cal", "it", "rm", "sf", "sl", "tt"]);
517
+ const IGNORED_COMMANDS = new Set([
518
+ "displaystyle",
519
+ "limits",
520
+ "nolimits",
521
+ "scriptstyle",
522
+ "scriptscriptstyle",
523
+ "textstyle",
524
+ ]);
525
+ const SIZE_COMMANDS = new Set([
526
+ "big",
527
+ "Big",
528
+ "bigg",
529
+ "Bigg",
530
+ "bigl",
531
+ "Bigl",
532
+ "biggl",
533
+ "Biggl",
534
+ "bigr",
535
+ "Bigr",
536
+ "biggr",
537
+ "Biggr",
538
+ ]);
539
+ const PLAIN_WRAPPERS = new Set([
540
+ "emph",
541
+ "mathcal",
542
+ "mathbf",
543
+ "mathfrak",
544
+ "mathit",
545
+ "mathrm",
546
+ "mathnormal",
547
+ "mathscr",
548
+ "mathsf",
549
+ "mathtt",
550
+ "mathup",
551
+ "mbox",
552
+ "overbrace",
553
+ "pmb",
554
+ "smash",
555
+ "substack",
556
+ "text",
557
+ "textbf",
558
+ "textit",
559
+ "textmd",
560
+ "textnormal",
561
+ "textrm",
562
+ "textsc",
563
+ "textsf",
564
+ "textsl",
565
+ "texttt",
566
+ "textup",
567
+ "underbrace",
568
+ "bm",
569
+ "boldsymbol",
570
+ ]);
571
+ const ACCENTS = {
572
+ acute: "\u0301",
573
+ bar: "\u0305",
574
+ breve: "\u0306",
575
+ check: "\u030c",
576
+ ddot: "\u0308",
577
+ dot: "\u0307",
578
+ grave: "\u0300",
579
+ hat: "\u0302",
580
+ mathring: "\u030a",
581
+ overleftarrow: "\u20d6",
582
+ overleftrightarrow: "\u20e1",
583
+ overline: "\u0305",
584
+ overrightarrow: "\u20d7",
585
+ tilde: "\u0303",
586
+ underline: "\u0332",
587
+ vec: "\u20d7",
588
+ widehat: "\u0302",
589
+ widetilde: "\u0303",
590
+ };
591
+ function replaceCharacters(value, replacements) {
592
+ let result = "";
593
+ for (const character of value) {
594
+ const replacement = replacements[character];
595
+ if (replacement === undefined) {
596
+ return undefined;
597
+ }
598
+ result += replacement;
599
+ }
600
+ return result;
601
+ }
602
+ function normalizeScriptValue(value) {
603
+ return value.trim().replace(/\s*([=+-])\s*/g, "$1");
604
+ }
605
+ function formatUnicodeScript(value, kind) {
606
+ return replaceCharacters(normalizeScriptValue(value), kind === "sub" ? SUBSCRIPTS : SUPERSCRIPTS);
607
+ }
608
+ function formatScript(value, kind) {
609
+ value = normalizeScriptValue(value);
610
+ const unicode = formatUnicodeScript(value, kind);
611
+ if (unicode !== undefined) {
612
+ return unicode;
613
+ }
614
+ const prefix = kind === "sub" ? "_" : "^";
615
+ if (Array.from(value).length === 1 || (kind === "sub" && /^[A-Za-z]+$/.test(value))) {
616
+ return `${prefix}${value}`;
617
+ }
618
+ return `${prefix}(${value})`;
619
+ }
620
+ function formatFraction(numerator, denominator) {
621
+ numerator = numerator.trim();
622
+ denominator = denominator.trim();
623
+ const simpleNumerator = /^[\p{L}\p{N}.]+$/u.test(numerator);
624
+ const simpleDenominator = /^[\p{N}.]+$/u.test(denominator) || Array.from(denominator).length === 1;
625
+ return `${simpleNumerator ? numerator : `(${numerator})`}/${simpleDenominator ? denominator : `(${denominator})`}`;
626
+ }
627
+ function formatRoot(value, symbol = "√") {
628
+ value = value.trim();
629
+ return /^[\p{L}\p{N}.]+$/u.test(value) ? `${symbol}${value}` : `${symbol}(${value})`;
630
+ }
631
+ const NAMED_OPERATOR_START = "\u{f0004}";
632
+ const NAMED_OPERATOR_END = "\u{f0005}";
633
+ const NAMED_OPERATOR_LEFT_SPACING_PATTERN = /(?<=[\p{L}\p{N})\]}\u{f0001}])\u{f0004}/gu;
634
+ const NAMED_OPERATOR_RIGHT_SPACING_PATTERN = /\u{f0005}(?=[\p{L}\p{N}√\u{f0000}])/gu;
635
+ function normalizeOutput(value) {
636
+ return value
637
+ .replace(NAMED_OPERATOR_LEFT_SPACING_PATTERN, " ")
638
+ .replaceAll(NAMED_OPERATOR_START, "")
639
+ .replace(NAMED_OPERATOR_RIGHT_SPACING_PATTERN, " ")
640
+ .replaceAll(NAMED_OPERATOR_END, "")
641
+ .split("\n")
642
+ .map((line) => line.replace(/[ \t]+/g, " ").trim())
643
+ .filter((line, index, lines) => line.length > 0 || (index > 0 && index < lines.length - 1))
644
+ .join("\n")
645
+ .trim();
646
+ }
647
+ const LAYOUT_MARKER_START = "\u{f0000}";
648
+ const LAYOUT_MARKER_END = "\u{f0001}";
649
+ const LAYOUT_MARKER_PATTERN = /\u{f0000}(\d+)\u{f0001}/gu;
650
+ const TRAILING_LAYOUT_MARKER_PATTERN = /\u{f0000}(\d+)\u{f0001}$/u;
651
+ const PROTECTED_SPACE = "\u{f0002}";
652
+ function padLayoutLine(line, width, centered = false) {
653
+ const padding = Math.max(0, width - visibleWidth(line));
654
+ const left = centered ? Math.floor(padding / 2) : 0;
655
+ return `${" ".repeat(left)}${line}${" ".repeat(padding - left)}`;
656
+ }
657
+ function joinLayouts(layouts) {
658
+ if (layouts.length === 0) {
659
+ return { lines: [""], width: 0, baseline: 0 };
660
+ }
661
+ const baseline = Math.max(...layouts.map((layout) => layout.baseline));
662
+ const below = Math.max(...layouts.map((layout) => layout.lines.length - layout.baseline - 1));
663
+ const lines = [];
664
+ for (let row = 0; row <= baseline + below; row++) {
665
+ let line = "";
666
+ for (const layout of layouts) {
667
+ const sourceRow = row - baseline + layout.baseline;
668
+ line +=
669
+ sourceRow >= 0 && sourceRow < layout.lines.length
670
+ ? padLayoutLine(layout.lines[sourceRow] ?? "", layout.width)
671
+ : " ".repeat(layout.width);
672
+ }
673
+ lines.push(line.trimEnd());
674
+ }
675
+ return {
676
+ lines,
677
+ width: layouts.reduce((width, layout) => width + layout.width, 0),
678
+ baseline,
679
+ };
680
+ }
681
+ function renderLayout(source, nodes) {
682
+ const renderedLines = [];
683
+ let firstBaseline = 0;
684
+ for (const sourceLine of source.split("\n")) {
685
+ const layouts = [];
686
+ let position = 0;
687
+ let previousNode;
688
+ for (const match of sourceLine.matchAll(LAYOUT_MARKER_PATTERN)) {
689
+ const index = match.index;
690
+ const node = nodes[Number(match[1])];
691
+ if (!node) {
692
+ continue;
693
+ }
694
+ if (index > position) {
695
+ const sliced = sourceLine.slice(position, index);
696
+ const trimmed = (previousNode ? sliced.trimStart() : sliced).trimEnd();
697
+ const preserveLeadingSpace = previousNode?.type === "matrix" && /^\s/.test(sliced);
698
+ const preserveTrailingSpace = node.type === "matrix" && /\s$/.test(sliced);
699
+ const text = trimmed
700
+ ? `${preserveLeadingSpace ? " " : ""}${trimmed}${preserveTrailingSpace ? " " : ""}`
701
+ : preserveLeadingSpace || preserveTrailingSpace
702
+ ? " "
703
+ : "";
704
+ layouts.push({ lines: [text], width: visibleWidth(text), baseline: 0 });
705
+ }
706
+ if (node.type === "fraction") {
707
+ const numerator = renderLayout(node.numerator, nodes);
708
+ const denominator = renderLayout(node.denominator, nodes);
709
+ const contentWidth = Math.max(numerator.width, denominator.width, 1);
710
+ const width = contentWidth + 2;
711
+ layouts.push({
712
+ lines: [
713
+ ...numerator.lines.map((line) => padLayoutLine(line, width, true)),
714
+ ` ${"─".repeat(contentWidth)} `,
715
+ ...denominator.lines.map((line) => padLayoutLine(line, width, true)),
716
+ ],
717
+ width,
718
+ baseline: numerator.lines.length,
719
+ });
720
+ }
721
+ else if (node.type === "operator") {
722
+ const contentWidth = Math.max(visibleWidth(node.operator), node.lower === undefined ? 0 : visibleWidth(node.lower), node.upper === undefined ? 0 : visibleWidth(node.upper));
723
+ const lines = [];
724
+ if (node.upper !== undefined) {
725
+ lines.push(`${padLayoutLine(node.upper, contentWidth, true)} `);
726
+ }
727
+ lines.push(`${padLayoutLine(node.operator, contentWidth, true)} `);
728
+ if (node.lower !== undefined) {
729
+ lines.push(`${padLayoutLine(node.lower, contentWidth, true)} `);
730
+ }
731
+ layouts.push({
732
+ lines,
733
+ width: contentWidth + 1,
734
+ baseline: node.upper === undefined ? 0 : 1,
735
+ });
736
+ }
737
+ else if (node.type === "script") {
738
+ const upper = node.upper === undefined ? undefined : renderLayout(node.upper, nodes);
739
+ const lower = node.lower === undefined ? undefined : renderLayout(node.lower, nodes);
740
+ const width = Math.max(upper?.width ?? 0, lower?.width ?? 0);
741
+ layouts.push({
742
+ lines: [
743
+ ...(upper?.lines.map((line) => padLayoutLine(line, width)) ?? []),
744
+ " ".repeat(width),
745
+ ...(lower?.lines.map((line) => padLayoutLine(line, width)) ?? []),
746
+ ],
747
+ width,
748
+ baseline: upper?.lines.length ?? 0,
749
+ });
750
+ }
751
+ else {
752
+ const width = Math.max(0, ...node.lines.map((line) => visibleWidth(line)));
753
+ layouts.push({
754
+ lines: node.lines.map((line) => padLayoutLine(line, width)),
755
+ width,
756
+ baseline: node.baseline,
757
+ });
758
+ }
759
+ position = index + match[0].length;
760
+ previousNode = node;
761
+ }
762
+ if (position < sourceLine.length) {
763
+ const sliced = sourceLine.slice(position);
764
+ const trimmed = previousNode ? sliced.trimStart() : sliced;
765
+ const text = previousNode?.type === "matrix" && /^\s/.test(sliced) ? ` ${trimmed}` : trimmed;
766
+ layouts.push({ lines: [text], width: visibleWidth(text), baseline: 0 });
767
+ }
768
+ const lineLayout = joinLayouts(layouts);
769
+ if (renderedLines.length === 0) {
770
+ firstBaseline = lineLayout.baseline;
771
+ }
772
+ renderedLines.push(...lineLayout.lines);
773
+ }
774
+ return {
775
+ lines: renderedLines,
776
+ width: Math.max(0, ...renderedLines.map((line) => visibleWidth(line))),
777
+ baseline: firstBaseline,
778
+ };
779
+ }
780
+ class LatexParser {
781
+ source;
782
+ layoutNodes;
783
+ display;
784
+ position = 0;
785
+ supported = true;
786
+ stackFractions = true;
787
+ scriptDepth = 0;
788
+ constructor(source, layoutNodes, display) {
789
+ this.source = source;
790
+ this.layoutNodes = layoutNodes;
791
+ this.display = display;
792
+ }
793
+ render() {
794
+ const rendered = this.parseSequence();
795
+ if (!this.supported || this.position !== this.source.length) {
796
+ return undefined;
797
+ }
798
+ return normalizeOutput(rendered);
799
+ }
800
+ parseSequence(endCharacter) {
801
+ let result = "";
802
+ while (this.position < this.source.length) {
803
+ const character = this.source[this.position];
804
+ if (endCharacter && character === endCharacter) {
805
+ this.position++;
806
+ return result;
807
+ }
808
+ if (character === "}") {
809
+ this.supported = false;
810
+ return result;
811
+ }
812
+ if (character === "{") {
813
+ this.position++;
814
+ result += this.parseSequence("}");
815
+ continue;
816
+ }
817
+ if (character === "\\") {
818
+ const command = this.parseCommand();
819
+ if (command === NEGATIVE_SPACE) {
820
+ result = result.trimEnd();
821
+ if (result.endsWith(NAMED_OPERATOR_END)) {
822
+ result = result.slice(0, -NAMED_OPERATOR_END.length);
823
+ }
824
+ }
825
+ else {
826
+ result += command;
827
+ }
828
+ continue;
829
+ }
830
+ if (character === "^" || character === "_") {
831
+ this.position++;
832
+ result = result.trimEnd();
833
+ const script = this.parseScripts(character);
834
+ if (result.endsWith(NAMED_OPERATOR_END)) {
835
+ result = `${result.slice(0, -NAMED_OPERATOR_END.length)}${script}${NAMED_OPERATOR_END}`;
836
+ }
837
+ else {
838
+ result += script;
839
+ }
840
+ continue;
841
+ }
842
+ if (/\s/.test(character)) {
843
+ result += this.parseWhitespace();
844
+ continue;
845
+ }
846
+ if (character === "=" || character === "<" || character === ">") {
847
+ result = `${result.trimEnd()} ${character} `;
848
+ this.position++;
849
+ continue;
850
+ }
851
+ if (character === "&") {
852
+ this.position++;
853
+ continue;
854
+ }
855
+ if (character === "~") {
856
+ this.position++;
857
+ result += " ";
858
+ continue;
859
+ }
860
+ if (character === ".") {
861
+ const marker = TRAILING_LAYOUT_MARKER_PATTERN.exec(result);
862
+ const node = marker ? this.layoutNodes[Number(marker[1])] : undefined;
863
+ if (node?.type === "matrix") {
864
+ const lastLine = node.lines.length - 1;
865
+ node.lines[lastLine] = `${node.lines[lastLine] ?? ""}${character}`;
866
+ this.position++;
867
+ continue;
868
+ }
869
+ }
870
+ result += character;
871
+ this.position++;
872
+ }
873
+ if (endCharacter) {
874
+ this.supported = false;
875
+ }
876
+ return result;
877
+ }
878
+ parseScripts(initialMarker) {
879
+ const scripts = {};
880
+ const order = [];
881
+ const parse = (marker) => {
882
+ const kind = marker === "_" ? "sub" : "sup";
883
+ this.scriptDepth++;
884
+ try {
885
+ scripts[kind] = this.parseRequiredArgument(false);
886
+ }
887
+ finally {
888
+ this.scriptDepth--;
889
+ }
890
+ order.push(kind);
891
+ };
892
+ parse(initialMarker);
893
+ let nextPosition = this.position;
894
+ while (nextPosition < this.source.length && /\s/.test(this.source[nextPosition] ?? "")) {
895
+ nextPosition++;
896
+ }
897
+ const nextMarker = this.source[nextPosition];
898
+ if ((nextMarker === "^" || nextMarker === "_") && nextMarker !== initialMarker) {
899
+ this.position = nextPosition + 1;
900
+ parse(nextMarker);
901
+ }
902
+ const subUnicode = scripts.sub === undefined ? undefined : formatUnicodeScript(scripts.sub, "sub");
903
+ const supUnicode = scripts.sup === undefined ? undefined : formatUnicodeScript(scripts.sup, "sup");
904
+ const canUseLayout = ![scripts.sub, scripts.sup].some((value) => value !== undefined &&
905
+ (value.includes("/") ||
906
+ (!value.includes(LAYOUT_MARKER_START) && Array.from(value).length > 1 && !/[A-Z*∗]/.test(value))));
907
+ const needsLayout = this.display &&
908
+ canUseLayout &&
909
+ (this.scriptDepth > 0 ||
910
+ (scripts.sub !== undefined && subUnicode === undefined) ||
911
+ (scripts.sup !== undefined && supUnicode === undefined));
912
+ if (!needsLayout) {
913
+ return order
914
+ .map((kind) => kind === "sub"
915
+ ? (subUnicode ?? formatScript(scripts.sub ?? "", kind))
916
+ : (supUnicode ?? formatScript(scripts.sup ?? "", kind)))
917
+ .join("");
918
+ }
919
+ const index = this.layoutNodes.push({
920
+ type: "script",
921
+ lower: scripts.sub === undefined ? undefined : normalizeOutput(scripts.sub),
922
+ upper: scripts.sup === undefined ? undefined : normalizeOutput(scripts.sup),
923
+ }) - 1;
924
+ return `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;
925
+ }
926
+ parseWhitespace() {
927
+ while (this.position < this.source.length && /\s/.test(this.source[this.position] ?? "")) {
928
+ this.position++;
929
+ }
930
+ return " ";
931
+ }
932
+ parseCommand() {
933
+ this.position++;
934
+ if (this.position >= this.source.length) {
935
+ this.supported = false;
936
+ return "";
937
+ }
938
+ let command = "";
939
+ const first = this.source[this.position] ?? "";
940
+ if (first === "\n" || first === "\r") {
941
+ this.position++;
942
+ if (first === "\r" && this.source[this.position] === "\n") {
943
+ this.position++;
944
+ }
945
+ return " ";
946
+ }
947
+ if (/[A-Za-z]/.test(first)) {
948
+ const start = this.position;
949
+ while (this.position < this.source.length && /[A-Za-z]/.test(this.source[this.position] ?? "")) {
950
+ this.position++;
951
+ }
952
+ command = this.source.slice(start, this.position);
953
+ }
954
+ else {
955
+ command = first;
956
+ this.position++;
957
+ }
958
+ if (command === "\\") {
959
+ return "\n";
960
+ }
961
+ if (SPACING_COMMANDS.has(command)) {
962
+ return " ";
963
+ }
964
+ if (NEGATIVE_SPACING_COMMANDS.has(command)) {
965
+ return NEGATIVE_SPACE;
966
+ }
967
+ if (FONT_SWITCH_COMMANDS.has(command)) {
968
+ while (this.position < this.source.length && /\s/.test(this.source[this.position] ?? "")) {
969
+ this.position++;
970
+ }
971
+ return "";
972
+ }
973
+ if (IGNORED_COMMANDS.has(command)) {
974
+ return "";
975
+ }
976
+ if (command === "{" ||
977
+ command === "}" ||
978
+ command === "$" ||
979
+ command === "%" ||
980
+ command === "#" ||
981
+ command === "_" ||
982
+ command === "&") {
983
+ return command;
984
+ }
985
+ if (command === "|") {
986
+ return "‖";
987
+ }
988
+ if (command === "not") {
989
+ const value = this.parseRequiredArgument(false).trim();
990
+ const negated = NEGATED_SYMBOLS[value];
991
+ if (negated !== undefined) {
992
+ return ` ${negated} `;
993
+ }
994
+ const characters = Array.from(value);
995
+ if (characters.length === 0) {
996
+ this.supported = false;
997
+ return "";
998
+ }
999
+ return ` ${characters[0]}\u0338${characters.slice(1).join("")} `;
1000
+ }
1001
+ if (LIMIT_OPERATORS.has(command)) {
1002
+ return this.parseOperator(command, "bracket", true, true);
1003
+ }
1004
+ const symbol = SYMBOLS[command];
1005
+ if (symbol !== undefined) {
1006
+ if (DISPLAY_LIMIT_SYMBOLS.has(command)) {
1007
+ return this.parseOperator(symbol, "script", true);
1008
+ }
1009
+ return command === "cdot" || command === "times" || RELATION_COMMANDS.has(command) ? ` ${symbol} ` : symbol;
1010
+ }
1011
+ if (NAMED_OPERATORS.has(command)) {
1012
+ return `${NAMED_OPERATOR_START}${command}${NAMED_OPERATOR_END}`;
1013
+ }
1014
+ if (SIZE_COMMANDS.has(command)) {
1015
+ return "";
1016
+ }
1017
+ if (command === "left" || command === "middle" || command === "right") {
1018
+ if (this.source[this.position] === ".") {
1019
+ this.position++;
1020
+ }
1021
+ return "";
1022
+ }
1023
+ if (command === "frac" || command === "dfrac" || command === "tfrac") {
1024
+ const shouldStack = this.display && this.stackFractions && command !== "tfrac";
1025
+ const numerator = this.parseRequiredArgument(!shouldStack);
1026
+ const denominator = this.parseRequiredArgument(!shouldStack);
1027
+ if (shouldStack) {
1028
+ const index = this.layoutNodes.push({
1029
+ type: "fraction",
1030
+ numerator: normalizeOutput(numerator),
1031
+ denominator: normalizeOutput(denominator),
1032
+ }) - 1;
1033
+ return `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;
1034
+ }
1035
+ return formatFraction(numerator, denominator);
1036
+ }
1037
+ if (command === "sqrt") {
1038
+ const degree = this.parseOptionalArgument()?.trim();
1039
+ const value = this.parseRequiredArgument();
1040
+ if (degree === undefined || degree === "2") {
1041
+ return formatRoot(value);
1042
+ }
1043
+ if (degree === "3") {
1044
+ return formatRoot(value, "∛");
1045
+ }
1046
+ if (degree === "4") {
1047
+ return formatRoot(value, "∜");
1048
+ }
1049
+ return `${formatScript(degree, "sup")}${formatRoot(value)}`;
1050
+ }
1051
+ if (command === "boxed" || command === "fbox") {
1052
+ return `[${this.parseRequiredArgument().trim()}]`;
1053
+ }
1054
+ if (command === "binom" || command === "dbinom" || command === "tbinom") {
1055
+ return `(${this.parseRequiredArgument()} choose ${this.parseRequiredArgument()})`;
1056
+ }
1057
+ const accent = ACCENTS[command];
1058
+ if (accent !== undefined) {
1059
+ const value = this.parseRequiredArgument();
1060
+ return Array.from(value).length === 1 ? `${value}${accent}` : `${command}(${value})`;
1061
+ }
1062
+ if (command === "mathbb") {
1063
+ const value = this.parseRequiredArgument();
1064
+ return Array.from(value, (character) => BLACKBOARD[character] ?? character).join("");
1065
+ }
1066
+ if (command === "operatorname") {
1067
+ const starred = this.source[this.position] === "*";
1068
+ if (starred) {
1069
+ this.position++;
1070
+ }
1071
+ const operator = normalizeOutput(this.parseRequiredArgument()).trim();
1072
+ return this.parseOperator(operator, "bracket", starred, true);
1073
+ }
1074
+ if (command === "mod" || command === "bmod") {
1075
+ return " mod ";
1076
+ }
1077
+ if (command === "pmod" || command === "pod") {
1078
+ const value = this.parseRequiredArgument().trim();
1079
+ return command === "pmod" ? ` (mod ${value})` : ` (${value})`;
1080
+ }
1081
+ if (command === "overset" || command === "stackrel") {
1082
+ const upper = this.parseRequiredArgument();
1083
+ const value = this.parseRequiredArgument().trim();
1084
+ return `${value}${formatScript(upper, "sup")}`;
1085
+ }
1086
+ if (command === "underset") {
1087
+ const lower = this.parseRequiredArgument();
1088
+ const value = this.parseRequiredArgument().trim();
1089
+ return `${value}${formatScript(lower, "sub")}`;
1090
+ }
1091
+ if (PLAIN_WRAPPERS.has(command)) {
1092
+ const value = this.parseRequiredArgument();
1093
+ return command.startsWith("text") || command === "mbox" ? value : value.trim();
1094
+ }
1095
+ if (command === "begin") {
1096
+ return this.parseEnvironment();
1097
+ }
1098
+ if (command === "end") {
1099
+ this.supported = false;
1100
+ return "";
1101
+ }
1102
+ this.supported = false;
1103
+ return `\\${command}`;
1104
+ }
1105
+ parseOperator(operator, inlineLowerStyle, displayLimits, spaced = false) {
1106
+ let useDisplayLimits = displayLimits;
1107
+ let modifierPosition = this.position;
1108
+ while (modifierPosition < this.source.length && /[ \t]/.test(this.source[modifierPosition] ?? "")) {
1109
+ modifierPosition++;
1110
+ }
1111
+ const modifier = /^\\(limits|nolimits)(?![A-Za-z])/.exec(this.source.slice(modifierPosition));
1112
+ if (modifier) {
1113
+ useDisplayLimits = modifier[1] === "limits";
1114
+ this.position = modifierPosition + modifier[0].length;
1115
+ }
1116
+ let lower;
1117
+ let upper;
1118
+ while (true) {
1119
+ let scriptPosition = this.position;
1120
+ while (scriptPosition < this.source.length && /[ \t]/.test(this.source[scriptPosition] ?? "")) {
1121
+ scriptPosition++;
1122
+ }
1123
+ const kind = this.source[scriptPosition];
1124
+ if (kind !== "_" && kind !== "^") {
1125
+ break;
1126
+ }
1127
+ this.position = scriptPosition + 1;
1128
+ const value = normalizeOutput(this.parseRequiredArgument(false)).replaceAll(" ", "");
1129
+ if (kind === "_") {
1130
+ if (lower !== undefined) {
1131
+ this.supported = false;
1132
+ }
1133
+ lower = value;
1134
+ }
1135
+ else {
1136
+ if (upper !== undefined) {
1137
+ this.supported = false;
1138
+ }
1139
+ upper = value;
1140
+ }
1141
+ }
1142
+ if (this.display && useDisplayLimits && (lower !== undefined || upper !== undefined)) {
1143
+ const index = this.layoutNodes.push({ type: "operator", operator, lower, upper }) - 1;
1144
+ return `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;
1145
+ }
1146
+ let rendered = operator;
1147
+ if (lower !== undefined) {
1148
+ rendered += inlineLowerStyle === "bracket" ? `[${lower}]` : formatScript(lower, "sub");
1149
+ }
1150
+ if (upper !== undefined) {
1151
+ rendered += formatScript(upper, "sup");
1152
+ }
1153
+ return spaced ? ` ${rendered} ` : rendered;
1154
+ }
1155
+ parseRequiredArgument(stackFractions = true) {
1156
+ const previousStackFractions = this.stackFractions;
1157
+ this.stackFractions = previousStackFractions && stackFractions;
1158
+ const value = this.parseRequiredArgumentValue();
1159
+ this.stackFractions = previousStackFractions;
1160
+ return value;
1161
+ }
1162
+ parseRequiredArgumentValue() {
1163
+ while (this.position < this.source.length && /\s/.test(this.source[this.position] ?? "")) {
1164
+ this.position++;
1165
+ }
1166
+ if (this.position >= this.source.length) {
1167
+ this.supported = false;
1168
+ return "";
1169
+ }
1170
+ if (this.source[this.position] === "{") {
1171
+ this.position++;
1172
+ return this.parseSequence("}");
1173
+ }
1174
+ if (this.source[this.position] === "\\") {
1175
+ return this.parseCommand();
1176
+ }
1177
+ const value = this.source[this.position] ?? "";
1178
+ this.position++;
1179
+ return value;
1180
+ }
1181
+ parseOptionalArgument() {
1182
+ while (this.position < this.source.length && /[ \t]/.test(this.source[this.position] ?? "")) {
1183
+ this.position++;
1184
+ }
1185
+ if (this.source[this.position] !== "[") {
1186
+ return undefined;
1187
+ }
1188
+ const end = this.source.indexOf("]", this.position + 1);
1189
+ if (end < 0) {
1190
+ this.supported = false;
1191
+ return undefined;
1192
+ }
1193
+ const value = this.source.slice(this.position + 1, end);
1194
+ this.position = end + 1;
1195
+ return this.renderNested(value);
1196
+ }
1197
+ readRawGroup() {
1198
+ while (this.position < this.source.length && /[ \t]/.test(this.source[this.position] ?? "")) {
1199
+ this.position++;
1200
+ }
1201
+ if (this.source[this.position] !== "{") {
1202
+ this.supported = false;
1203
+ return undefined;
1204
+ }
1205
+ const start = ++this.position;
1206
+ let depth = 1;
1207
+ while (this.position < this.source.length) {
1208
+ const character = this.source[this.position];
1209
+ if (character === "\\") {
1210
+ this.position += 2;
1211
+ continue;
1212
+ }
1213
+ if (character === "{")
1214
+ depth++;
1215
+ if (character === "}")
1216
+ depth--;
1217
+ if (depth === 0) {
1218
+ const value = this.source.slice(start, this.position);
1219
+ this.position++;
1220
+ return value;
1221
+ }
1222
+ this.position++;
1223
+ }
1224
+ this.supported = false;
1225
+ return undefined;
1226
+ }
1227
+ splitEnvironmentRows(body) {
1228
+ return body.split(/\\\\(?:\[[^\]\n]*\])?/);
1229
+ }
1230
+ parseEnvironment() {
1231
+ const environment = this.readRawGroup();
1232
+ if (!environment) {
1233
+ return "";
1234
+ }
1235
+ const endMarker = `\\end{${environment}}`;
1236
+ const end = this.source.indexOf(endMarker, this.position);
1237
+ if (end < 0) {
1238
+ this.supported = false;
1239
+ return "";
1240
+ }
1241
+ const body = this.source.slice(this.position, end);
1242
+ this.position = end + endMarker.length;
1243
+ if (environment === "equation" || environment === "equation*" || environment === "displaymath") {
1244
+ return this.renderNested(body).trim();
1245
+ }
1246
+ if (environment === "aligned" ||
1247
+ environment === "align" ||
1248
+ environment === "align*" ||
1249
+ environment === "alignedat" ||
1250
+ environment === "alignat" ||
1251
+ environment === "alignat*" ||
1252
+ environment === "gather" ||
1253
+ environment === "gathered" ||
1254
+ environment === "multline" ||
1255
+ environment === "multline*" ||
1256
+ environment === "split") {
1257
+ const alignedAt = ["alignedat", "alignat", "alignat*"].includes(environment);
1258
+ const alignedBody = alignedAt ? body.replace(/^\s*\{[^}]*\}/, "") : body;
1259
+ return this.splitEnvironmentRows(alignedBody)
1260
+ .map((row) => {
1261
+ const cells = row.split("&");
1262
+ const source = alignedAt
1263
+ ? Array.from({ length: Math.ceil(cells.length / 2) }, (_, index) => cells.slice(index * 2, index * 2 + 2).join("")).join(" ")
1264
+ : cells.join("");
1265
+ return this.renderNested(source).trim();
1266
+ })
1267
+ .filter(Boolean)
1268
+ .join("\n");
1269
+ }
1270
+ if (environment === "cases" || environment === "cases*") {
1271
+ return this.renderCases(body);
1272
+ }
1273
+ if (["array", "matrix", "smallmatrix", "pmatrix", "bmatrix", "Bmatrix", "vmatrix", "Vmatrix"].includes(environment)) {
1274
+ const matrixBody = environment === "array" ? body.replace(/^\s*\{[^}]*\}/, "") : body;
1275
+ return this.renderMatrix(environment, matrixBody);
1276
+ }
1277
+ this.supported = false;
1278
+ return body;
1279
+ }
1280
+ renderCases(body) {
1281
+ const rows = this.splitEnvironmentRows(body)
1282
+ .map((row) => row.split("&").map((cell) => this.renderNested(cell, false).trim()))
1283
+ .filter((row) => row.some(Boolean));
1284
+ const valueWidth = Math.max(0, ...rows.map((row) => visibleWidth((row[0] ?? "").replace(/,\s*$/, ""))));
1285
+ const contents = rows.map((row) => {
1286
+ const value = (row[0] ?? "").replace(/,\s*$/, "");
1287
+ const condition = row[1] ?? "";
1288
+ if (!condition) {
1289
+ return value;
1290
+ }
1291
+ const conditionPrefix = /^(?:if|when|for|otherwise)\b/i.test(condition) ? " " : " if ";
1292
+ return `${value}${PROTECTED_SPACE.repeat(valueWidth - visibleWidth(value))}${conditionPrefix}${condition}`;
1293
+ });
1294
+ if (contents.length <= 1) {
1295
+ return contents.length === 0 ? "" : `⎧ ${contents[0]}`;
1296
+ }
1297
+ const middle = Math.floor(contents.length / 2);
1298
+ const visualRows = [...contents];
1299
+ if (contents.length % 2 === 0) {
1300
+ visualRows.splice(middle, 0, undefined);
1301
+ }
1302
+ const lines = visualRows.map((content, index) => {
1303
+ const delimiter = index === 0 ? "⎧" : index === visualRows.length - 1 ? "⎩" : "⎨";
1304
+ return content === undefined ? delimiter : `${delimiter} ${content}`;
1305
+ });
1306
+ const index = this.layoutNodes.push({ type: "matrix", lines, baseline: middle }) - 1;
1307
+ return `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;
1308
+ }
1309
+ renderMatrix(environment, body) {
1310
+ const matrix = this.splitEnvironmentRows(body)
1311
+ .map((row) => row.split("&").map((cell) => this.renderNested(cell, false).trim()))
1312
+ .filter((row) => row.some(Boolean));
1313
+ const columnCount = Math.max(0, ...matrix.map((row) => row.length));
1314
+ const columnWidths = Array.from({ length: columnCount }, (_, column) => Math.max(0, ...matrix.map((row) => visibleWidth(row[column] ?? ""))));
1315
+ const rows = matrix.map((row) => Array.from({ length: columnCount }, (_, column) => {
1316
+ const cell = row[column] ?? "";
1317
+ return `${cell}${PROTECTED_SPACE.repeat(Math.max(0, (columnWidths[column] ?? 0) - visibleWidth(cell)))}`;
1318
+ }).join(" │ "));
1319
+ let lines;
1320
+ if (environment === "array" || environment === "matrix" || environment === "smallmatrix") {
1321
+ lines = rows;
1322
+ }
1323
+ else {
1324
+ const delimiters = {
1325
+ pmatrix: ["⎛", "⎞", "⎜", "⎟", "⎝", "⎠"],
1326
+ bmatrix: ["⎡", "⎤", "⎢", "⎥", "⎣", "⎦"],
1327
+ Bmatrix: ["⎧", "⎫", "⎨", "⎬", "⎩", "⎭"],
1328
+ vmatrix: ["│", "│", "│", "│", "│", "│"],
1329
+ Vmatrix: ["║", "║", "║", "║", "║", "║"],
1330
+ };
1331
+ const delimiter = delimiters[environment];
1332
+ if (!delimiter) {
1333
+ this.supported = false;
1334
+ return rows.join("\n");
1335
+ }
1336
+ lines = rows.map((row, index) => {
1337
+ const left = index === 0 ? delimiter[0] : index === rows.length - 1 ? delimiter[4] : delimiter[2];
1338
+ const right = index === 0 ? delimiter[1] : index === rows.length - 1 ? delimiter[5] : delimiter[3];
1339
+ return `${left} ${row} ${right}`;
1340
+ });
1341
+ }
1342
+ if (lines.length <= 1) {
1343
+ return lines[0] ?? "";
1344
+ }
1345
+ const index = this.layoutNodes.push({ type: "matrix", lines, baseline: 0 }) - 1;
1346
+ return `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;
1347
+ }
1348
+ renderNested(source, stackFractions = true) {
1349
+ const rendered = new LatexParser(source, this.layoutNodes, this.display && stackFractions).render();
1350
+ if (rendered === undefined) {
1351
+ this.supported = false;
1352
+ return source;
1353
+ }
1354
+ return rendered;
1355
+ }
1356
+ }
1357
+ /**
1358
+ * Render a basic LaTeX math expression as terminal-friendly Unicode text.
1359
+ * Returns undefined when the expression contains unsupported or malformed syntax.
1360
+ */
1361
+ export function renderLatex(source, options = {}) {
1362
+ const layoutNodes = [];
1363
+ const rendered = new LatexParser(source, layoutNodes, options.display === true).render();
1364
+ if (rendered === undefined) {
1365
+ return undefined;
1366
+ }
1367
+ if (layoutNodes.length === 0) {
1368
+ return rendered.replaceAll(PROTECTED_SPACE, " ");
1369
+ }
1370
+ const lines = renderLayout(rendered, layoutNodes).lines;
1371
+ const indentation = Math.min(...lines.filter((line) => line.trim()).map((line) => line.length - line.trimStart().length));
1372
+ return lines
1373
+ .map((line) => line.slice(indentation).trimEnd())
1374
+ .join("\n")
1375
+ .trimEnd()
1376
+ .replaceAll(PROTECTED_SPACE, " ");
1377
+ }
1378
+ //# sourceMappingURL=latex.js.map