@fleetagent/pi-tui 0.1.9 → 0.2.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 (109) hide show
  1. package/README.md +47 -7
  2. package/dist/autocomplete.d.ts +17 -23
  3. package/dist/autocomplete.d.ts.map +1 -1
  4. package/dist/autocomplete.js +129 -195
  5. package/dist/autocomplete.js.map +1 -1
  6. package/dist/components/alt-screen-flash.d.ts +13 -0
  7. package/dist/components/alt-screen-flash.d.ts.map +1 -0
  8. package/dist/components/alt-screen-flash.js +37 -0
  9. package/dist/components/alt-screen-flash.js.map +1 -0
  10. package/dist/components/editor.d.ts +47 -4
  11. package/dist/components/editor.d.ts.map +1 -1
  12. package/dist/components/editor.js +615 -585
  13. package/dist/components/editor.js.map +1 -1
  14. package/dist/components/h-stack.d.ts +7 -0
  15. package/dist/components/h-stack.d.ts.map +1 -0
  16. package/dist/components/h-stack.js +43 -0
  17. package/dist/components/h-stack.js.map +1 -0
  18. package/dist/components/image.d.ts +4 -0
  19. package/dist/components/image.d.ts.map +1 -1
  20. package/dist/components/image.js +38 -51
  21. package/dist/components/image.js.map +1 -1
  22. package/dist/components/input.d.ts +9 -0
  23. package/dist/components/input.d.ts.map +1 -1
  24. package/dist/components/input.js +121 -147
  25. package/dist/components/input.js.map +1 -1
  26. package/dist/components/markdown.d.ts +34 -0
  27. package/dist/components/markdown.d.ts.map +1 -1
  28. package/dist/components/markdown.js +491 -429
  29. package/dist/components/markdown.js.map +1 -1
  30. package/dist/components/scroll-view.d.ts +53 -0
  31. package/dist/components/scroll-view.d.ts.map +1 -0
  32. package/dist/components/scroll-view.js +173 -0
  33. package/dist/components/scroll-view.js.map +1 -0
  34. package/dist/components/select-list.d.ts.map +1 -1
  35. package/dist/components/select-list.js.map +1 -1
  36. package/dist/components/settings-list.d.ts +2 -0
  37. package/dist/components/settings-list.d.ts.map +1 -1
  38. package/dist/components/settings-list.js +31 -29
  39. package/dist/components/settings-list.js.map +1 -1
  40. package/dist/components/stack.d.ts +32 -0
  41. package/dist/components/stack.d.ts.map +1 -0
  42. package/dist/components/stack.js +122 -0
  43. package/dist/components/stack.js.map +1 -0
  44. package/dist/components/v-stack.d.ts +8 -0
  45. package/dist/components/v-stack.d.ts.map +1 -0
  46. package/dist/components/v-stack.js +27 -0
  47. package/dist/components/v-stack.js.map +1 -0
  48. package/dist/fuzzy.d.ts.map +1 -1
  49. package/dist/fuzzy.js +37 -46
  50. package/dist/fuzzy.js.map +1 -1
  51. package/dist/index.d.ts +10 -3
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +11 -2
  54. package/dist/index.js.map +1 -1
  55. package/dist/keybindings.d.ts +54 -4
  56. package/dist/keybindings.d.ts.map +1 -1
  57. package/dist/keybindings.js +39 -4
  58. package/dist/keybindings.js.map +1 -1
  59. package/dist/keys.d.ts.map +1 -1
  60. package/dist/keys.js +359 -479
  61. package/dist/keys.js.map +1 -1
  62. package/dist/kill-ring.d.ts +6 -4
  63. package/dist/kill-ring.d.ts.map +1 -1
  64. package/dist/kill-ring.js +0 -7
  65. package/dist/kill-ring.js.map +1 -1
  66. package/dist/latex.d.ts +10 -0
  67. package/dist/latex.d.ts.map +1 -0
  68. package/dist/latex.js +1406 -0
  69. package/dist/latex.js.map +1 -0
  70. package/dist/layout-node.d.ts +43 -0
  71. package/dist/layout-node.d.ts.map +1 -0
  72. package/dist/layout-node.js +6 -0
  73. package/dist/layout-node.js.map +1 -0
  74. package/dist/layout.d.ts +40 -0
  75. package/dist/layout.d.ts.map +1 -0
  76. package/dist/layout.js +386 -0
  77. package/dist/layout.js.map +1 -0
  78. package/dist/stdin-buffer.d.ts +8 -0
  79. package/dist/stdin-buffer.d.ts.map +1 -1
  80. package/dist/stdin-buffer.js +116 -159
  81. package/dist/stdin-buffer.js.map +1 -1
  82. package/dist/terminal-image.d.ts +41 -19
  83. package/dist/terminal-image.d.ts.map +1 -1
  84. package/dist/terminal-image.js +171 -32
  85. package/dist/terminal-image.js.map +1 -1
  86. package/dist/terminal.d.ts +3 -0
  87. package/dist/terminal.d.ts.map +1 -1
  88. package/dist/terminal.js +27 -23
  89. package/dist/terminal.js.map +1 -1
  90. package/dist/tui-alt-screen.d.ts +114 -0
  91. package/dist/tui-alt-screen.d.ts.map +1 -0
  92. package/dist/tui-alt-screen.js +950 -0
  93. package/dist/tui-alt-screen.js.map +1 -0
  94. package/dist/tui-main-screen.d.ts +52 -0
  95. package/dist/tui-main-screen.d.ts.map +1 -0
  96. package/dist/tui-main-screen.js +511 -0
  97. package/dist/tui-main-screen.js.map +1 -0
  98. package/dist/tui.d.ts +112 -44
  99. package/dist/tui.d.ts.map +1 -1
  100. package/dist/tui.js +489 -699
  101. package/dist/tui.js.map +1 -1
  102. package/dist/utils.d.ts +29 -17
  103. package/dist/utils.d.ts.map +1 -1
  104. package/dist/utils.js +605 -528
  105. package/dist/utils.js.map +1 -1
  106. package/dist/word-navigation.d.ts.map +1 -1
  107. package/dist/word-navigation.js +37 -39
  108. package/dist/word-navigation.js.map +1 -1
  109. package/package.json +1 -1
package/dist/latex.js ADDED
@@ -0,0 +1,1406 @@
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 LITERAL_COMMANDS = new Set(["{", "}", "$", "%", "#", "_", "&"]);
525
+ const DELIMITER_COMMANDS = new Set(["left", "middle", "right"]);
526
+ const PLAIN_WRAPPERS = new Set([
527
+ "emph",
528
+ "mathcal",
529
+ "mathbf",
530
+ "mathfrak",
531
+ "mathit",
532
+ "mathrm",
533
+ "mathnormal",
534
+ "mathscr",
535
+ "mathsf",
536
+ "mathtt",
537
+ "mathup",
538
+ "mbox",
539
+ "overbrace",
540
+ "pmb",
541
+ "smash",
542
+ "substack",
543
+ "text",
544
+ "textbf",
545
+ "textit",
546
+ "textmd",
547
+ "textnormal",
548
+ "textrm",
549
+ "textsc",
550
+ "textsf",
551
+ "textsl",
552
+ "texttt",
553
+ "textup",
554
+ "underbrace",
555
+ "bm",
556
+ "boldsymbol",
557
+ ]);
558
+ const ACCENTS = {
559
+ acute: "\u0301",
560
+ bar: "\u0305",
561
+ breve: "\u0306",
562
+ check: "\u030c",
563
+ ddot: "\u0308",
564
+ dot: "\u0307",
565
+ grave: "\u0300",
566
+ hat: "\u0302",
567
+ mathring: "\u030a",
568
+ overleftarrow: "\u20d6",
569
+ overleftrightarrow: "\u20e1",
570
+ overline: "\u0305",
571
+ overrightarrow: "\u20d7",
572
+ tilde: "\u0303",
573
+ underline: "\u0332",
574
+ vec: "\u20d7",
575
+ widehat: "\u0302",
576
+ widetilde: "\u0303",
577
+ };
578
+ function replaceCharacters(value, replacements) {
579
+ let result = "";
580
+ for (const character of value) {
581
+ const replacement = replacements[character];
582
+ if (replacement === undefined) {
583
+ return undefined;
584
+ }
585
+ result += replacement;
586
+ }
587
+ return result;
588
+ }
589
+ function formatScript(value, kind) {
590
+ value = value.trim();
591
+ const replacements = kind === "sub" ? SUBSCRIPTS : SUPERSCRIPTS;
592
+ const unicode = replaceCharacters(value.replace(/\s*([=+-])\s*/g, "$1"), replacements);
593
+ if (unicode !== undefined) {
594
+ return unicode;
595
+ }
596
+ const prefix = kind === "sub" ? "_" : "^";
597
+ if (Array.from(value).length === 1 || (kind === "sub" && /^[A-Za-z]+$/.test(value))) {
598
+ return `${prefix}${value}`;
599
+ }
600
+ return `${prefix}(${value})`;
601
+ }
602
+ function formatFraction(numerator, denominator) {
603
+ numerator = numerator.trim();
604
+ denominator = denominator.trim();
605
+ const simpleNumerator = /^[\p{L}\p{N}.]+$/u.test(numerator);
606
+ const simpleDenominator = /^[\p{N}.]+$/u.test(denominator) || Array.from(denominator).length === 1;
607
+ return `${simpleNumerator ? numerator : `(${numerator})`}/${simpleDenominator ? denominator : `(${denominator})`}`;
608
+ }
609
+ function formatRoot(value, symbol = "√") {
610
+ value = value.trim();
611
+ return /^[\p{L}\p{N}.]+$/u.test(value) ? `${symbol}${value}` : `${symbol}(${value})`;
612
+ }
613
+ const NAMED_OPERATOR_START = "\u{f0004}";
614
+ const NAMED_OPERATOR_END = "\u{f0005}";
615
+ const NAMED_OPERATOR_LEFT_SPACING_PATTERN = /(?<=[\p{L}\p{N})\]}\u{f0001}])\u{f0004}/gu;
616
+ const NAMED_OPERATOR_RIGHT_SPACING_PATTERN = /\u{f0005}(?=[\p{L}\p{N}√\u{f0000}])/gu;
617
+ function normalizeOutput(value) {
618
+ return value
619
+ .replace(NAMED_OPERATOR_LEFT_SPACING_PATTERN, " ")
620
+ .replaceAll(NAMED_OPERATOR_START, "")
621
+ .replace(NAMED_OPERATOR_RIGHT_SPACING_PATTERN, " ")
622
+ .replaceAll(NAMED_OPERATOR_END, "")
623
+ .split("\n")
624
+ .map((line) => line.replace(/[ \t]+/g, " ").trim())
625
+ .filter((line, index, lines) => line.length > 0 || (index > 0 && index < lines.length - 1))
626
+ .join("\n")
627
+ .trim();
628
+ }
629
+ const LAYOUT_MARKER_START = "\u{f0000}";
630
+ const LAYOUT_MARKER_END = "\u{f0001}";
631
+ const LAYOUT_MARKER_PATTERN = /\u{f0000}(\d+)\u{f0001}/gu;
632
+ const TRAILING_LAYOUT_MARKER_PATTERN = /\u{f0000}(\d+)\u{f0001}$/u;
633
+ const PROTECTED_SPACE = "\u{f0002}";
634
+ const RESERVED_MARKER_PATTERN = /[\u{f0000}\u{f0001}\u{f0002}\u{f0004}\u{f0005}]/u;
635
+ const MAX_SOURCE_LENGTH = 16 * 1024;
636
+ const MAX_NESTING_DEPTH = 64;
637
+ const MAX_LAYOUT_NODES = 256;
638
+ const MAX_RENDERED_ROWS = 200;
639
+ const MAX_RENDERED_LINE_WIDTH = 4096;
640
+ function classifyLatexSequenceCharacter(character, endCharacter) {
641
+ if (endCharacter && character === endCharacter)
642
+ return "end";
643
+ switch (character) {
644
+ case "}":
645
+ return "unexpected-close";
646
+ case "{":
647
+ return "group";
648
+ case "\\":
649
+ return "command";
650
+ case "^":
651
+ case "_":
652
+ return "script";
653
+ case "=":
654
+ case "<":
655
+ case ">":
656
+ return "relation";
657
+ case "&":
658
+ return "alignment";
659
+ case "~":
660
+ return "space";
661
+ case ".":
662
+ return "period";
663
+ default:
664
+ return /\s/.test(character) ? "whitespace" : "literal";
665
+ }
666
+ }
667
+ function assertLayoutBounds(width, rowCount) {
668
+ if (!Number.isSafeInteger(width) ||
669
+ width < 0 ||
670
+ width > MAX_RENDERED_LINE_WIDTH ||
671
+ !Number.isSafeInteger(rowCount) ||
672
+ rowCount < 0 ||
673
+ rowCount > MAX_RENDERED_ROWS) {
674
+ throw new RangeError("LaTeX layout exceeds renderer bounds");
675
+ }
676
+ }
677
+ function padLayoutLine(line, width, centered = false) {
678
+ const padding = Math.max(0, width - visibleWidth(line));
679
+ const left = centered ? Math.floor(padding / 2) : 0;
680
+ return `${" ".repeat(left)}${line}${" ".repeat(padding - left)}`;
681
+ }
682
+ // pi-ignore noExcessiveCollectionIterations: Every output row must concatenate every layout segment; rows are capped at 200 and parsed layout nodes at 256.
683
+ function joinLayouts(layouts) {
684
+ if (layouts.length === 0) {
685
+ return { lines: [""], width: 0, baseline: 0 };
686
+ }
687
+ const baseline = Math.max(...layouts.map((layout) => layout.baseline));
688
+ const below = Math.max(...layouts.map((layout) => layout.lines.length - layout.baseline - 1));
689
+ const width = layouts.reduce((total, layout) => total + layout.width, 0);
690
+ const rowCount = baseline + below + 1;
691
+ assertLayoutBounds(width, rowCount);
692
+ const lines = [];
693
+ for (let row = 0; row < rowCount; row++) {
694
+ let line = "";
695
+ for (const layout of layouts) {
696
+ const sourceRow = row - baseline + layout.baseline;
697
+ line +=
698
+ sourceRow >= 0 && sourceRow < layout.lines.length
699
+ ? padLayoutLine(layout.lines[sourceRow] ?? "", layout.width)
700
+ : " ".repeat(layout.width);
701
+ }
702
+ lines.push(line.trimEnd());
703
+ }
704
+ return { lines, width, baseline };
705
+ }
706
+ function createTextLayout(text) {
707
+ return { lines: [text], width: visibleWidth(text), baseline: 0 };
708
+ }
709
+ function createInterNodeTextLayout(source, previousNode, nextNode) {
710
+ const trimmed = (previousNode ? source.trimStart() : source).trimEnd();
711
+ const preserveLeadingSpace = previousNode?.type === "matrix" && /^\s/.test(source);
712
+ const preserveTrailingSpace = nextNode.type === "matrix" && /\s$/.test(source);
713
+ const text = trimmed
714
+ ? `${preserveLeadingSpace ? " " : ""}${trimmed}${preserveTrailingSpace ? " " : ""}`
715
+ : preserveLeadingSpace || preserveTrailingSpace
716
+ ? " "
717
+ : "";
718
+ return createTextLayout(text);
719
+ }
720
+ function createTrailingTextLayout(source, previousNode) {
721
+ const trimmed = previousNode ? source.trimStart() : source;
722
+ const text = previousNode?.type === "matrix" && /^\s/.test(source) ? ` ${trimmed}` : trimmed;
723
+ return createTextLayout(text);
724
+ }
725
+ function renderFractionNodeLayout(node, nodes) {
726
+ const numerator = renderLayout(node.numerator, nodes);
727
+ const denominator = renderLayout(node.denominator, nodes);
728
+ const contentWidth = Math.max(numerator.width, denominator.width, 1);
729
+ const width = contentWidth + 2;
730
+ const lines = [
731
+ ...numerator.lines.map((line) => padLayoutLine(line, width, true)),
732
+ ` ${"─".repeat(contentWidth)} `,
733
+ ...denominator.lines.map((line) => padLayoutLine(line, width, true)),
734
+ ];
735
+ assertLayoutBounds(width, lines.length);
736
+ return { lines, width, baseline: numerator.lines.length };
737
+ }
738
+ function renderOperatorNodeLayout(node) {
739
+ const contentWidth = Math.max(visibleWidth(node.operator), node.lower === undefined ? 0 : visibleWidth(node.lower), node.upper === undefined ? 0 : visibleWidth(node.upper));
740
+ const lines = [];
741
+ if (node.upper !== undefined)
742
+ lines.push(`${padLayoutLine(node.upper, contentWidth, true)} `);
743
+ lines.push(`${padLayoutLine(node.operator, contentWidth, true)} `);
744
+ if (node.lower !== undefined)
745
+ lines.push(`${padLayoutLine(node.lower, contentWidth, true)} `);
746
+ assertLayoutBounds(contentWidth + 1, lines.length);
747
+ return { lines, width: contentWidth + 1, baseline: node.upper === undefined ? 0 : 1 };
748
+ }
749
+ function renderMatrixNodeLayout(node) {
750
+ const width = Math.max(0, ...node.lines.map((line) => visibleWidth(line)));
751
+ assertLayoutBounds(width, node.lines.length);
752
+ return {
753
+ lines: node.lines.map((line) => padLayoutLine(line, width)),
754
+ width,
755
+ baseline: node.baseline,
756
+ };
757
+ }
758
+ function renderLayoutNode(node, nodes) {
759
+ switch (node.type) {
760
+ case "fraction":
761
+ return renderFractionNodeLayout(node, nodes);
762
+ case "operator":
763
+ return renderOperatorNodeLayout(node);
764
+ case "matrix":
765
+ return renderMatrixNodeLayout(node);
766
+ }
767
+ }
768
+ function renderSourceLineLayout(sourceLine, nodes) {
769
+ const layouts = [];
770
+ let position = 0;
771
+ let previousNode;
772
+ for (const match of sourceLine.matchAll(LAYOUT_MARKER_PATTERN)) {
773
+ const index = match.index;
774
+ const node = nodes[Number(match[1])];
775
+ if (!node)
776
+ continue;
777
+ if (index > position) {
778
+ layouts.push(createInterNodeTextLayout(sourceLine.slice(position, index), previousNode, node));
779
+ }
780
+ layouts.push(renderLayoutNode(node, nodes));
781
+ position = index + match[0].length;
782
+ previousNode = node;
783
+ }
784
+ if (position < sourceLine.length) {
785
+ layouts.push(createTrailingTextLayout(sourceLine.slice(position), previousNode));
786
+ }
787
+ return joinLayouts(layouts);
788
+ }
789
+ function renderLayout(source, nodes) {
790
+ const renderedLines = [];
791
+ let firstBaseline = 0;
792
+ for (const sourceLine of source.split("\n")) {
793
+ const lineLayout = renderSourceLineLayout(sourceLine, nodes);
794
+ if (renderedLines.length === 0)
795
+ firstBaseline = lineLayout.baseline;
796
+ renderedLines.push(...lineLayout.lines);
797
+ assertLayoutBounds(0, renderedLines.length);
798
+ }
799
+ const width = Math.max(0, ...renderedLines.map((line) => visibleWidth(line)));
800
+ assertLayoutBounds(width, renderedLines.length);
801
+ return { lines: renderedLines, width, baseline: firstBaseline };
802
+ }
803
+ class LatexParser {
804
+ source;
805
+ layoutNodes;
806
+ display;
807
+ state;
808
+ position = 0;
809
+ supported = true;
810
+ stackFractions = true;
811
+ constructor(source, layoutNodes, display, state = { nestingDepth: 0 }) {
812
+ this.source = source;
813
+ this.layoutNodes = layoutNodes;
814
+ this.display = display;
815
+ this.state = state;
816
+ }
817
+ render() {
818
+ const rendered = this.parseSequence();
819
+ if (!this.supported || this.position !== this.source.length) {
820
+ return undefined;
821
+ }
822
+ return normalizeOutput(rendered);
823
+ }
824
+ appendParsedCommand(result) {
825
+ const command = this.parseCommand();
826
+ if (command !== NEGATIVE_SPACE)
827
+ return result + command;
828
+ const trimmed = result.trimEnd();
829
+ return trimmed.endsWith(NAMED_OPERATOR_END) ? trimmed.slice(0, -NAMED_OPERATOR_END.length) : trimmed;
830
+ }
831
+ appendParsedScript(result, character) {
832
+ this.position++;
833
+ const trimmed = result.trimEnd();
834
+ const script = formatScript(this.parseRequiredArgument(false), character === "_" ? "sub" : "sup");
835
+ return trimmed.endsWith(NAMED_OPERATOR_END)
836
+ ? `${trimmed.slice(0, -NAMED_OPERATOR_END.length)}${script}${NAMED_OPERATOR_END}`
837
+ : trimmed + script;
838
+ }
839
+ appendPeriod(result) {
840
+ const marker = TRAILING_LAYOUT_MARKER_PATTERN.exec(result);
841
+ const node = marker ? this.layoutNodes[Number(marker[1])] : undefined;
842
+ if (node?.type === "matrix") {
843
+ const lastLine = node.lines.length - 1;
844
+ node.lines[lastLine] = `${node.lines[lastLine] ?? ""}.`;
845
+ this.position++;
846
+ return result;
847
+ }
848
+ this.position++;
849
+ return `${result}.`;
850
+ }
851
+ parseSequence(endCharacter) {
852
+ let result = "";
853
+ while (this.position < this.source.length) {
854
+ const character = this.source[this.position];
855
+ switch (classifyLatexSequenceCharacter(character, endCharacter)) {
856
+ case "end":
857
+ this.position++;
858
+ return result;
859
+ case "unexpected-close":
860
+ this.supported = false;
861
+ return result;
862
+ case "group":
863
+ this.position++;
864
+ result += this.parseNestedSequence("}");
865
+ break;
866
+ case "command":
867
+ result = this.appendParsedCommand(result);
868
+ break;
869
+ case "script":
870
+ result = this.appendParsedScript(result, character);
871
+ break;
872
+ case "whitespace":
873
+ result += this.parseWhitespace();
874
+ break;
875
+ case "relation":
876
+ result = `${result.trimEnd()} ${character} `;
877
+ this.position++;
878
+ break;
879
+ case "alignment":
880
+ this.position++;
881
+ break;
882
+ case "space":
883
+ this.position++;
884
+ result += " ";
885
+ break;
886
+ case "period":
887
+ result = this.appendPeriod(result);
888
+ break;
889
+ case "literal":
890
+ result += character;
891
+ this.position++;
892
+ break;
893
+ }
894
+ }
895
+ if (endCharacter)
896
+ this.supported = false;
897
+ return result;
898
+ }
899
+ parseWhitespace() {
900
+ while (this.position < this.source.length && /\s/.test(this.source[this.position] ?? "")) {
901
+ this.position++;
902
+ }
903
+ return " ";
904
+ }
905
+ readCommandName() {
906
+ this.position++;
907
+ if (this.position >= this.source.length) {
908
+ this.supported = false;
909
+ return undefined;
910
+ }
911
+ const first = this.source[this.position] ?? "";
912
+ if (!/[A-Za-z]/.test(first)) {
913
+ this.position++;
914
+ return first;
915
+ }
916
+ const start = this.position;
917
+ while (this.position < this.source.length && /[A-Za-z]/.test(this.source[this.position] ?? "")) {
918
+ this.position++;
919
+ }
920
+ return this.source.slice(start, this.position);
921
+ }
922
+ parsePredefinedCommand(command) {
923
+ if (command === "\\")
924
+ return "\n";
925
+ if (SPACING_COMMANDS.has(command))
926
+ return " ";
927
+ if (NEGATIVE_SPACING_COMMANDS.has(command))
928
+ return NEGATIVE_SPACE;
929
+ if (IGNORED_COMMANDS.has(command))
930
+ return "";
931
+ if (LITERAL_COMMANDS.has(command))
932
+ return command;
933
+ if (command === "|")
934
+ return "‖";
935
+ return undefined;
936
+ }
937
+ parseNegatedCommand() {
938
+ const value = this.parseRequiredArgument(false).trim();
939
+ const negated = NEGATED_SYMBOLS[value];
940
+ if (negated !== undefined)
941
+ return ` ${negated} `;
942
+ const characters = Array.from(value);
943
+ if (characters.length === 0) {
944
+ this.supported = false;
945
+ return "";
946
+ }
947
+ return ` ${characters[0]}\u0338${characters.slice(1).join("")} `;
948
+ }
949
+ parseSymbolCommand(command) {
950
+ const symbol = SYMBOLS[command];
951
+ if (symbol === undefined)
952
+ return undefined;
953
+ if (DISPLAY_LIMIT_SYMBOLS.has(command))
954
+ return this.parseOperator(symbol, "script", true);
955
+ return command === "cdot" || command === "times" || RELATION_COMMANDS.has(command) ? ` ${symbol} ` : symbol;
956
+ }
957
+ parseNamedOrDelimiterCommand(command) {
958
+ if (NAMED_OPERATORS.has(command))
959
+ return `${NAMED_OPERATOR_START}${command}${NAMED_OPERATOR_END}`;
960
+ if (SIZE_COMMANDS.has(command))
961
+ return "";
962
+ if (!DELIMITER_COMMANDS.has(command))
963
+ return undefined;
964
+ if (this.source[this.position] === ".")
965
+ this.position++;
966
+ return "";
967
+ }
968
+ parseFractionCommand(command) {
969
+ const shouldStack = this.display && this.stackFractions && command !== "tfrac";
970
+ const numerator = this.parseRequiredArgument(!shouldStack);
971
+ const denominator = this.parseRequiredArgument(!shouldStack);
972
+ if (!shouldStack)
973
+ return formatFraction(numerator, denominator);
974
+ const index = this.addLayoutNode({
975
+ type: "fraction",
976
+ numerator: normalizeOutput(numerator),
977
+ denominator: normalizeOutput(denominator),
978
+ });
979
+ return index === undefined ? "" : `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;
980
+ }
981
+ parseRootCommand() {
982
+ const degree = this.parseOptionalArgument()?.trim();
983
+ const value = this.parseRequiredArgument();
984
+ if (degree === undefined || degree === "2")
985
+ return formatRoot(value);
986
+ if (degree === "3")
987
+ return formatRoot(value, "∛");
988
+ if (degree === "4")
989
+ return formatRoot(value, "∜");
990
+ return `${formatScript(degree, "sup")}${formatRoot(value)}`;
991
+ }
992
+ parseAccentCommand(command, accent) {
993
+ const value = this.parseRequiredArgument();
994
+ return Array.from(value).length === 1 ? `${value}${accent}` : `${command}(${value})`;
995
+ }
996
+ parseOperatorNameCommand() {
997
+ const starred = this.source[this.position] === "*";
998
+ if (starred)
999
+ this.position++;
1000
+ const operator = normalizeOutput(this.parseRequiredArgument()).trim();
1001
+ return this.parseOperator(operator, "bracket", starred, true);
1002
+ }
1003
+ parseArgumentCommand(command) {
1004
+ switch (command) {
1005
+ case "frac":
1006
+ case "dfrac":
1007
+ case "tfrac":
1008
+ return this.parseFractionCommand(command);
1009
+ case "sqrt":
1010
+ return this.parseRootCommand();
1011
+ case "boxed":
1012
+ case "fbox":
1013
+ return `[${this.parseRequiredArgument().trim()}]`;
1014
+ case "binom":
1015
+ case "dbinom":
1016
+ case "tbinom":
1017
+ return `(${this.parseRequiredArgument()} choose ${this.parseRequiredArgument()})`;
1018
+ case "mathbb": {
1019
+ const value = this.parseRequiredArgument();
1020
+ return Array.from(value, (character) => BLACKBOARD[character] ?? character).join("");
1021
+ }
1022
+ case "operatorname":
1023
+ return this.parseOperatorNameCommand();
1024
+ case "mod":
1025
+ case "bmod":
1026
+ return " mod ";
1027
+ case "pmod":
1028
+ case "pod": {
1029
+ const value = this.parseRequiredArgument().trim();
1030
+ return command === "pmod" ? ` (mod ${value})` : ` (${value})`;
1031
+ }
1032
+ case "overset":
1033
+ case "stackrel": {
1034
+ const upper = this.parseRequiredArgument();
1035
+ const value = this.parseRequiredArgument().trim();
1036
+ return `${value}${formatScript(upper, "sup")}`;
1037
+ }
1038
+ case "underset": {
1039
+ const lower = this.parseRequiredArgument();
1040
+ const value = this.parseRequiredArgument().trim();
1041
+ return `${value}${formatScript(lower, "sub")}`;
1042
+ }
1043
+ case "begin":
1044
+ return this.parseEnvironment();
1045
+ case "end":
1046
+ this.supported = false;
1047
+ return "";
1048
+ }
1049
+ const accent = ACCENTS[command];
1050
+ if (accent !== undefined)
1051
+ return this.parseAccentCommand(command, accent);
1052
+ if (PLAIN_WRAPPERS.has(command)) {
1053
+ const value = this.parseRequiredArgument();
1054
+ return command.startsWith("text") || command === "mbox" ? value : value.trim();
1055
+ }
1056
+ return undefined;
1057
+ }
1058
+ parseCommand() {
1059
+ const command = this.readCommandName();
1060
+ if (command === undefined)
1061
+ return "";
1062
+ const predefined = this.parsePredefinedCommand(command);
1063
+ if (predefined !== undefined)
1064
+ return predefined;
1065
+ if (command === "not")
1066
+ return this.parseNegatedCommand();
1067
+ if (LIMIT_OPERATORS.has(command))
1068
+ return this.parseOperator(command, "bracket", true, true);
1069
+ const symbol = this.parseSymbolCommand(command);
1070
+ if (symbol !== undefined)
1071
+ return symbol;
1072
+ const namedOrDelimiter = this.parseNamedOrDelimiterCommand(command);
1073
+ if (namedOrDelimiter !== undefined)
1074
+ return namedOrDelimiter;
1075
+ const argumentCommand = this.parseArgumentCommand(command);
1076
+ if (argumentCommand !== undefined)
1077
+ return argumentCommand;
1078
+ this.supported = false;
1079
+ return `\\${command}`;
1080
+ }
1081
+ assignOperatorScript(scripts, kind, value) {
1082
+ const property = kind === "_" ? "lower" : "upper";
1083
+ if (scripts[property] !== undefined)
1084
+ this.supported = false;
1085
+ scripts[property] = value;
1086
+ }
1087
+ parseOperatorDisplayLimits(displayLimits) {
1088
+ let modifierPosition = this.position;
1089
+ while (modifierPosition < this.source.length && /[ \t]/.test(this.source[modifierPosition] ?? "")) {
1090
+ modifierPosition++;
1091
+ }
1092
+ const modifier = /^\\(limits|nolimits)(?![A-Za-z])/.exec(this.source.slice(modifierPosition));
1093
+ if (!modifier)
1094
+ return displayLimits;
1095
+ this.position = modifierPosition + modifier[0].length;
1096
+ return modifier[1] === "limits";
1097
+ }
1098
+ parseOperatorScripts() {
1099
+ const scripts = {};
1100
+ while (true) {
1101
+ let scriptPosition = this.position;
1102
+ while (scriptPosition < this.source.length && /[ \t]/.test(this.source[scriptPosition] ?? "")) {
1103
+ scriptPosition++;
1104
+ }
1105
+ const kind = this.source[scriptPosition];
1106
+ if (kind !== "_" && kind !== "^")
1107
+ break;
1108
+ this.position = scriptPosition + 1;
1109
+ const value = normalizeOutput(this.parseRequiredArgument(false)).replaceAll(" ", "");
1110
+ this.assignOperatorScript(scripts, kind, value);
1111
+ }
1112
+ return scripts;
1113
+ }
1114
+ parseOperator(operator, inlineLowerStyle, displayLimits, spaced = false) {
1115
+ const useDisplayLimits = this.parseOperatorDisplayLimits(displayLimits);
1116
+ const { lower, upper } = this.parseOperatorScripts();
1117
+ if (this.display && useDisplayLimits && (lower !== undefined || upper !== undefined)) {
1118
+ const index = this.addLayoutNode({ type: "operator", operator, lower, upper });
1119
+ return index === undefined ? "" : `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;
1120
+ }
1121
+ let rendered = operator;
1122
+ if (lower !== undefined) {
1123
+ rendered += inlineLowerStyle === "bracket" ? `[${lower}]` : formatScript(lower, "sub");
1124
+ }
1125
+ if (upper !== undefined)
1126
+ rendered += formatScript(upper, "sup");
1127
+ return spaced ? ` ${rendered} ` : rendered;
1128
+ }
1129
+ parseRequiredArgument(stackFractions = true) {
1130
+ const previousStackFractions = this.stackFractions;
1131
+ this.stackFractions = previousStackFractions && stackFractions;
1132
+ const value = this.parseRequiredArgumentValue();
1133
+ this.stackFractions = previousStackFractions;
1134
+ return value;
1135
+ }
1136
+ parseRequiredArgumentValue() {
1137
+ while (this.position < this.source.length && /[ \t]/.test(this.source[this.position] ?? "")) {
1138
+ this.position++;
1139
+ }
1140
+ if (this.position >= this.source.length) {
1141
+ this.supported = false;
1142
+ return "";
1143
+ }
1144
+ if (this.source[this.position] === "{") {
1145
+ this.position++;
1146
+ return this.parseNestedSequence("}");
1147
+ }
1148
+ if (this.source[this.position] === "\\") {
1149
+ return this.parseCommand();
1150
+ }
1151
+ const value = this.source[this.position] ?? "";
1152
+ this.position++;
1153
+ return value;
1154
+ }
1155
+ parseOptionalArgument() {
1156
+ while (this.position < this.source.length && /[ \t]/.test(this.source[this.position] ?? "")) {
1157
+ this.position++;
1158
+ }
1159
+ if (this.source[this.position] !== "[") {
1160
+ return undefined;
1161
+ }
1162
+ const end = this.source.indexOf("]", this.position + 1);
1163
+ if (end < 0) {
1164
+ this.supported = false;
1165
+ return undefined;
1166
+ }
1167
+ const value = this.source.slice(this.position + 1, end);
1168
+ this.position = end + 1;
1169
+ return this.renderNested(value);
1170
+ }
1171
+ readRawGroupContents(start) {
1172
+ let depth = 1;
1173
+ while (this.position < this.source.length) {
1174
+ const character = this.source[this.position];
1175
+ if (character === "\\") {
1176
+ this.position += 2;
1177
+ continue;
1178
+ }
1179
+ if (character === "{") {
1180
+ depth++;
1181
+ if (this.state.nestingDepth + depth > MAX_NESTING_DEPTH) {
1182
+ this.supported = false;
1183
+ return undefined;
1184
+ }
1185
+ this.position++;
1186
+ continue;
1187
+ }
1188
+ if (character !== "}") {
1189
+ this.position++;
1190
+ continue;
1191
+ }
1192
+ depth--;
1193
+ if (depth > 0) {
1194
+ this.position++;
1195
+ continue;
1196
+ }
1197
+ const value = this.source.slice(start, this.position);
1198
+ this.position++;
1199
+ return value;
1200
+ }
1201
+ this.supported = false;
1202
+ return undefined;
1203
+ }
1204
+ readRawGroup() {
1205
+ while (this.position < this.source.length && /[ \t]/.test(this.source[this.position] ?? "")) {
1206
+ this.position++;
1207
+ }
1208
+ if (this.source[this.position] !== "{") {
1209
+ this.supported = false;
1210
+ return undefined;
1211
+ }
1212
+ const start = ++this.position;
1213
+ if (this.state.nestingDepth + 1 > MAX_NESTING_DEPTH) {
1214
+ this.supported = false;
1215
+ return undefined;
1216
+ }
1217
+ return this.readRawGroupContents(start);
1218
+ }
1219
+ splitEnvironmentRows(body) {
1220
+ return body.split(/\\\\(?:\[[^\]\n]*\])?/);
1221
+ }
1222
+ parseEnvironment() {
1223
+ const environment = this.readRawGroup();
1224
+ if (!environment) {
1225
+ return "";
1226
+ }
1227
+ const endMarker = `\\end{${environment}}`;
1228
+ const end = this.source.indexOf(endMarker, this.position);
1229
+ if (end < 0) {
1230
+ this.supported = false;
1231
+ return "";
1232
+ }
1233
+ const body = this.source.slice(this.position, end);
1234
+ this.position = end + endMarker.length;
1235
+ if (environment === "equation" || environment === "equation*" || environment === "displaymath") {
1236
+ return this.renderNested(body).trim();
1237
+ }
1238
+ if (environment === "aligned" ||
1239
+ environment === "align" ||
1240
+ environment === "align*" ||
1241
+ environment === "alignedat" ||
1242
+ environment === "alignat" ||
1243
+ environment === "alignat*" ||
1244
+ environment === "gather" ||
1245
+ environment === "gathered" ||
1246
+ environment === "multline" ||
1247
+ environment === "multline*" ||
1248
+ environment === "split") {
1249
+ const alignedAt = ["alignedat", "alignat", "alignat*"].includes(environment);
1250
+ const alignedBody = alignedAt ? body.replace(/^\s*\{[^}]*\}/, "") : body;
1251
+ return this.splitEnvironmentRows(alignedBody)
1252
+ .map((row) => {
1253
+ const cells = row.split("&");
1254
+ const source = alignedAt
1255
+ ? Array.from({ length: Math.ceil(cells.length / 2) }, (_, index) => cells.slice(index * 2, index * 2 + 2).join("")).join(" ")
1256
+ : cells.join("");
1257
+ return this.renderNested(source).trim();
1258
+ })
1259
+ .filter(Boolean)
1260
+ .join("\n");
1261
+ }
1262
+ if (environment === "cases" || environment === "cases*") {
1263
+ const rows = this.splitEnvironmentRows(body)
1264
+ .map((row) => row.split("&").map((cell) => this.renderNested(cell, false).trim()))
1265
+ .filter((row) => row.some(Boolean));
1266
+ return rows
1267
+ .map((row, index) => {
1268
+ const value = (row[0] ?? "").replace(/,\s*$/, "");
1269
+ const condition = row[1] ?? "";
1270
+ const delimiter = index === 0 ? "⎧" : index === rows.length - 1 ? "⎩" : "⎨";
1271
+ const conditionPrefix = /^(?:if|when|for|otherwise)\b/i.test(condition) ? " " : " if ";
1272
+ return `${delimiter} ${value}${condition ? `${conditionPrefix}${condition}` : ""}`;
1273
+ })
1274
+ .join("\n");
1275
+ }
1276
+ if (["array", "matrix", "smallmatrix", "pmatrix", "bmatrix", "Bmatrix", "vmatrix", "Vmatrix"].includes(environment)) {
1277
+ const matrixBody = environment === "array" ? body.replace(/^\s*\{[^}]*\}/, "") : body;
1278
+ return this.renderMatrix(environment, matrixBody);
1279
+ }
1280
+ this.supported = false;
1281
+ return body;
1282
+ }
1283
+ renderMatrix(environment, body) {
1284
+ const sourceRows = this.splitEnvironmentRows(body).map((row) => row.split("&"));
1285
+ const sourceColumnCount = Math.max(0, ...sourceRows.map((row) => row.length));
1286
+ if (sourceRows.length > MAX_RENDERED_ROWS || sourceRows.length * sourceColumnCount > MAX_LAYOUT_NODES) {
1287
+ this.supported = false;
1288
+ return "";
1289
+ }
1290
+ const matrix = sourceRows
1291
+ .map((row) => row.map((cell) => this.renderNested(cell, false).trim()))
1292
+ .filter((row) => row.some(Boolean));
1293
+ const columnCount = Math.max(0, ...matrix.map((row) => row.length));
1294
+ const columnWidths = Array.from({ length: columnCount }, (_, column) => Math.max(0, ...matrix.map((row) => visibleWidth(row[column] ?? ""))));
1295
+ const rows = matrix.map((row) => Array.from({ length: columnCount }, (_, column) => {
1296
+ const cell = row[column] ?? "";
1297
+ return `${cell}${PROTECTED_SPACE.repeat(Math.max(0, (columnWidths[column] ?? 0) - visibleWidth(cell)))}`;
1298
+ }).join(" │ "));
1299
+ let lines;
1300
+ if (environment === "array" || environment === "matrix" || environment === "smallmatrix") {
1301
+ lines = rows;
1302
+ }
1303
+ else {
1304
+ const delimiters = {
1305
+ pmatrix: ["⎛", "⎞", "⎜", "⎟", "⎝", "⎠"],
1306
+ bmatrix: ["⎡", "⎤", "⎢", "⎥", "⎣", "⎦"],
1307
+ Bmatrix: ["⎧", "⎫", "⎨", "⎬", "⎩", "⎭"],
1308
+ vmatrix: ["│", "│", "│", "│", "│", "│"],
1309
+ Vmatrix: ["║", "║", "║", "║", "║", "║"],
1310
+ };
1311
+ const delimiter = delimiters[environment];
1312
+ if (!delimiter) {
1313
+ this.supported = false;
1314
+ return rows.join("\n");
1315
+ }
1316
+ lines = rows.map((row, index) => {
1317
+ const left = index === 0 ? delimiter[0] : index === rows.length - 1 ? delimiter[4] : delimiter[2];
1318
+ const right = index === 0 ? delimiter[1] : index === rows.length - 1 ? delimiter[5] : delimiter[3];
1319
+ return `${left} ${row} ${right}`;
1320
+ });
1321
+ }
1322
+ if (lines.length <= 1) {
1323
+ return lines[0] ?? "";
1324
+ }
1325
+ const index = this.addLayoutNode({ type: "matrix", lines, baseline: 0 });
1326
+ return index === undefined ? "" : `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;
1327
+ }
1328
+ addLayoutNode(node) {
1329
+ if (this.layoutNodes.length >= MAX_LAYOUT_NODES) {
1330
+ this.supported = false;
1331
+ return undefined;
1332
+ }
1333
+ return this.layoutNodes.push(node) - 1;
1334
+ }
1335
+ parseNestedSequence(endCharacter) {
1336
+ if (this.state.nestingDepth >= MAX_NESTING_DEPTH) {
1337
+ this.supported = false;
1338
+ return "";
1339
+ }
1340
+ this.state.nestingDepth++;
1341
+ try {
1342
+ return this.parseSequence(endCharacter);
1343
+ }
1344
+ finally {
1345
+ this.state.nestingDepth--;
1346
+ }
1347
+ }
1348
+ renderNested(source, stackFractions = true) {
1349
+ if (this.state.nestingDepth >= MAX_NESTING_DEPTH) {
1350
+ this.supported = false;
1351
+ return source;
1352
+ }
1353
+ this.state.nestingDepth++;
1354
+ let rendered;
1355
+ try {
1356
+ rendered = new LatexParser(source, this.layoutNodes, this.display && stackFractions, this.state).render();
1357
+ }
1358
+ finally {
1359
+ this.state.nestingDepth--;
1360
+ }
1361
+ if (rendered === undefined) {
1362
+ this.supported = false;
1363
+ return source;
1364
+ }
1365
+ return rendered;
1366
+ }
1367
+ }
1368
+ /**
1369
+ * Render a basic LaTeX math expression as terminal-friendly Unicode text.
1370
+ * Returns undefined when the expression contains unsupported or malformed syntax.
1371
+ */
1372
+ export function renderLatex(source, options = {}) {
1373
+ if (source.length > MAX_SOURCE_LENGTH || RESERVED_MARKER_PATTERN.test(source)) {
1374
+ return undefined;
1375
+ }
1376
+ try {
1377
+ const layoutNodes = [];
1378
+ const rendered = new LatexParser(source, layoutNodes, options.display === true).render();
1379
+ if (rendered === undefined) {
1380
+ return undefined;
1381
+ }
1382
+ let result;
1383
+ if (layoutNodes.length === 0) {
1384
+ result = rendered.replaceAll(PROTECTED_SPACE, " ");
1385
+ }
1386
+ else {
1387
+ const lines = renderLayout(rendered, layoutNodes).lines;
1388
+ const indentation = Math.min(...lines.filter((line) => line.trim()).map((line) => line.length - line.trimStart().length));
1389
+ result = lines
1390
+ .map((line) => line.slice(indentation).trimEnd())
1391
+ .join("\n")
1392
+ .trimEnd()
1393
+ .replaceAll(PROTECTED_SPACE, " ");
1394
+ }
1395
+ const resultLines = result.split("\n");
1396
+ if (resultLines.length > MAX_RENDERED_ROWS ||
1397
+ resultLines.some((line) => visibleWidth(line) > MAX_RENDERED_LINE_WIDTH)) {
1398
+ return undefined;
1399
+ }
1400
+ return result;
1401
+ }
1402
+ catch {
1403
+ return undefined;
1404
+ }
1405
+ }
1406
+ //# sourceMappingURL=latex.js.map