@dsh-cc/pi-tui 0.5.0

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