@fleetagent/pi-tui 0.1.8 → 0.2.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 (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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latex.d.ts","sourceRoot":"","sources":["../src/latex.ts"],"names":[],"mappings":"AA+8CA,MAAM,WAAW,kBAAkB;IAClC,wFAAwF;IACxF,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,MAAM,GAAG,SAAS,CAsChG","sourcesContent":["import { visibleWidth } from \"./utils.ts\";\n\nconst SYMBOLS: Readonly<Record<string, string>> = {\n\talpha: \"α\",\n\tbeta: \"β\",\n\tgamma: \"γ\",\n\tdelta: \"δ\",\n\tepsilon: \"ϵ\",\n\tvarepsilon: \"ε\",\n\tzeta: \"ζ\",\n\teta: \"η\",\n\ttheta: \"θ\",\n\tvartheta: \"ϑ\",\n\tiota: \"ι\",\n\tkappa: \"κ\",\n\tvarkappa: \"ϰ\",\n\tlambda: \"λ\",\n\tmu: \"μ\",\n\tnu: \"ν\",\n\txi: \"ξ\",\n\tpi: \"π\",\n\tvarpi: \"ϖ\",\n\trho: \"ρ\",\n\tvarrho: \"ϱ\",\n\tsigma: \"σ\",\n\tvarsigma: \"ς\",\n\ttau: \"τ\",\n\tupsilon: \"υ\",\n\tphi: \"ϕ\",\n\tvarphi: \"φ\",\n\tchi: \"χ\",\n\tpsi: \"ψ\",\n\tomega: \"ω\",\n\tGamma: \"Γ\",\n\tDelta: \"Δ\",\n\tTheta: \"Θ\",\n\tLambda: \"Λ\",\n\tXi: \"Ξ\",\n\tPi: \"Π\",\n\tSigma: \"Σ\",\n\tUpsilon: \"Υ\",\n\tPhi: \"Φ\",\n\tPsi: \"Ψ\",\n\tOmega: \"Ω\",\n\tpm: \"±\",\n\tmp: \"∓\",\n\ttimes: \"×\",\n\tdiv: \"÷\",\n\tcdot: \"·\",\n\tast: \"∗\",\n\tstar: \"⋆\",\n\tcirc: \"∘\",\n\tbullet: \"•\",\n\toplus: \"⊕\",\n\tominus: \"⊖\",\n\totimes: \"⊗\",\n\toslash: \"⊘\",\n\todot: \"⊙\",\n\tbigcirc: \"○\",\n\tdagger: \"†\",\n\tddagger: \"‡\",\n\tamalg: \"⨿\",\n\tuplus: \"⊎\",\n\tsqcap: \"⊓\",\n\tsqcup: \"⊔\",\n\ttriangleleft: \"◁\",\n\ttriangleright: \"▷\",\n\twr: \"≀\",\n\tcap: \"∩\",\n\tcup: \"∪\",\n\tbigcap: \"⋂\",\n\tbigcup: \"⋃\",\n\tbigwedge: \"⋀\",\n\tbigvee: \"⋁\",\n\tbigsqcup: \"⨆\",\n\tbiguplus: \"⨄\",\n\tbigoplus: \"⨁\",\n\tbigotimes: \"⨂\",\n\tbigodot: \"⨀\",\n\tsetminus: \"∖\",\n\tin: \"∈\",\n\tnotin: \"∉\",\n\tni: \"∋\",\n\tsubset: \"⊂\",\n\tsupset: \"⊃\",\n\tsubseteq: \"⊆\",\n\tsupseteq: \"⊇\",\n\tsqsubset: \"⊏\",\n\tsqsupset: \"⊐\",\n\tsqsubseteq: \"⊑\",\n\tsqsupseteq: \"⊒\",\n\tprec: \"≺\",\n\tpreceq: \"≼\",\n\tsucc: \"≻\",\n\tsucceq: \"≽\",\n\tll: \"≪\",\n\tgg: \"≫\",\n\tle: \"≤\",\n\tleq: \"≤\",\n\tleqslant: \"≤\",\n\tge: \"≥\",\n\tgeq: \"≥\",\n\tgeqslant: \"≥\",\n\tne: \"≠\",\n\tneq: \"≠\",\n\tequiv: \"≡\",\n\tapprox: \"≈\",\n\tsim: \"∼\",\n\tsimeq: \"≃\",\n\tcong: \"≅\",\n\tasymp: \"≍\",\n\tdoteq: \"≐\",\n\tpropto: \"∝\",\n\tparallel: \"∥\",\n\tperp: \"⊥\",\n\tmid: \"∣\",\n\tvdash: \"⊢\",\n\tdashv: \"⊣\",\n\tmodels: \"⊨\",\n\tVdash: \"⊩\",\n\tVvdash: \"⊪\",\n\tnvdash: \"⊬\",\n\tnvDash: \"⊭\",\n\tforall: \"∀\",\n\texists: \"∃\",\n\tnexists: \"∄\",\n\tneg: \"¬\",\n\tland: \"∧\",\n\twedge: \"∧\",\n\tlor: \"∨\",\n\tvee: \"∨\",\n\tto: \"→\",\n\trightarrow: \"→\",\n\tlongrightarrow: \"→\",\n\tleftarrow: \"←\",\n\tlongleftarrow: \"←\",\n\tgets: \"←\",\n\tleftrightarrow: \"↔\",\n\tlongleftrightarrow: \"↔\",\n\thookleftarrow: \"↩\",\n\thookrightarrow: \"↪\",\n\ttwoheadleftarrow: \"↞\",\n\ttwoheadrightarrow: \"↠\",\n\tleftharpoonup: \"↼\",\n\tleftharpoondown: \"↽\",\n\trightharpoonup: \"⇀\",\n\trightharpoondown: \"⇁\",\n\trightleftharpoons: \"⇌\",\n\tleftrightharpoons: \"⇋\",\n\tnearrow: \"↗\",\n\tsearrow: \"↘\",\n\tswarrow: \"↙\",\n\tnwarrow: \"↖\",\n\trightsquigarrow: \"⇝\",\n\tleadsto: \"⇝\",\n\tRightarrow: \"⇒\",\n\tLongrightarrow: \"⇒\",\n\tLeftarrow: \"⇐\",\n\tLongleftarrow: \"⇐\",\n\tLeftrightarrow: \"⇔\",\n\tLongleftrightarrow: \"⇔\",\n\timplies: \"⇒\",\n\tiff: \"⇔\",\n\tmapsto: \"↦\",\n\tlongmapsto: \"↦\",\n\tuparrow: \"↑\",\n\tdownarrow: \"↓\",\n\tpartial: \"∂\",\n\tnabla: \"∇\",\n\tint: \"∫\",\n\tiint: \"∬\",\n\tiiint: \"∭\",\n\toint: \"∮\",\n\tsum: \"∑\",\n\tprod: \"∏\",\n\tcoprod: \"∐\",\n\tinfty: \"∞\",\n\temptyset: \"∅\",\n\tvarnothing: \"∅\",\n\tangle: \"∠\",\n\ttherefore: \"∴\",\n\tbecause: \"∵\",\n\taleph: \"ℵ\",\n\tbeth: \"ℶ\",\n\tgimel: \"ℷ\",\n\tdaleth: \"ℸ\",\n\ttop: \"⊤\",\n\tbot: \"⊥\",\n\ttriangle: \"△\",\n\tsquare: \"□\",\n\tlozenge: \"◊\",\n\tcheckmark: \"✓\",\n\tcomplement: \"∁\",\n\twp: \"℘\",\n\tprime: \"′\",\n\tldots: \"…\",\n\tdots: \"…\",\n\tcdots: \"⋯\",\n\tvdots: \"⋮\",\n\tddots: \"⋱\",\n\tell: \"ℓ\",\n\thbar: \"ℏ\",\n\tIm: \"ℑ\",\n\tRe: \"ℜ\",\n\tlangle: \"⟨\",\n\trangle: \"⟩\",\n\tvert: \"|\",\n\tlvert: \"|\",\n\trvert: \"|\",\n\tVert: \"‖\",\n\tlVert: \"‖\",\n\trVert: \"‖\",\n\tlbrace: \"{\",\n\trbrace: \"}\",\n\tbackslash: \"\\\\\",\n\tlfloor: \"⌊\",\n\trfloor: \"⌋\",\n\tlceil: \"⌈\",\n\trceil: \"⌉\",\n\tcolon: \":\",\n};\n\nconst NAMED_OPERATORS = new Set([\n\t\"arccos\",\n\t\"arcsin\",\n\t\"arctan\",\n\t\"arg\",\n\t\"cos\",\n\t\"cosh\",\n\t\"cot\",\n\t\"coth\",\n\t\"csc\",\n\t\"deg\",\n\t\"det\",\n\t\"dim\",\n\t\"exp\",\n\t\"gcd\",\n\t\"hom\",\n\t\"inf\",\n\t\"ker\",\n\t\"lg\",\n\t\"lim\",\n\t\"liminf\",\n\t\"limsup\",\n\t\"ln\",\n\t\"log\",\n\t\"max\",\n\t\"min\",\n\t\"Pr\",\n\t\"sec\",\n\t\"sin\",\n\t\"sinh\",\n\t\"sup\",\n\t\"tan\",\n\t\"tanh\",\n]);\n\nconst LIMIT_OPERATORS = new Set([\n\t\"argmax\",\n\t\"argmin\",\n\t\"inf\",\n\t\"injlim\",\n\t\"lim\",\n\t\"liminf\",\n\t\"limsup\",\n\t\"max\",\n\t\"min\",\n\t\"projlim\",\n\t\"sup\",\n]);\n\nconst DISPLAY_LIMIT_SYMBOLS = new Set([\n\t\"bigcap\",\n\t\"bigcup\",\n\t\"bigodot\",\n\t\"bigoplus\",\n\t\"bigotimes\",\n\t\"bigsqcup\",\n\t\"biguplus\",\n\t\"bigvee\",\n\t\"bigwedge\",\n\t\"coprod\",\n\t\"int\",\n\t\"iint\",\n\t\"iiint\",\n\t\"oint\",\n\t\"prod\",\n\t\"sum\",\n]);\n\nconst RELATION_COMMANDS = new Set([\n\t\"Leftarrow\",\n\t\"Leftrightarrow\",\n\t\"Longleftarrow\",\n\t\"Longleftrightarrow\",\n\t\"Longrightarrow\",\n\t\"Rightarrow\",\n\t\"Vdash\",\n\t\"Vvdash\",\n\t\"approx\",\n\t\"asymp\",\n\t\"cong\",\n\t\"dashv\",\n\t\"doteq\",\n\t\"downarrow\",\n\t\"equiv\",\n\t\"ge\",\n\t\"geq\",\n\t\"geqslant\",\n\t\"gets\",\n\t\"gg\",\n\t\"hookleftarrow\",\n\t\"hookrightarrow\",\n\t\"iff\",\n\t\"implies\",\n\t\"in\",\n\t\"leadsto\",\n\t\"le\",\n\t\"leftarrow\",\n\t\"leftharpoondown\",\n\t\"leftharpoonup\",\n\t\"leftrightarrow\",\n\t\"leftrightharpoons\",\n\t\"leq\",\n\t\"leqslant\",\n\t\"ll\",\n\t\"longleftarrow\",\n\t\"longleftrightarrow\",\n\t\"longmapsto\",\n\t\"longrightarrow\",\n\t\"mapsto\",\n\t\"mid\",\n\t\"models\",\n\t\"ne\",\n\t\"nearrow\",\n\t\"neq\",\n\t\"ni\",\n\t\"notin\",\n\t\"nvdash\",\n\t\"nvDash\",\n\t\"nwarrow\",\n\t\"parallel\",\n\t\"perp\",\n\t\"prec\",\n\t\"preceq\",\n\t\"propto\",\n\t\"rightharpoondown\",\n\t\"rightharpoonup\",\n\t\"rightleftharpoons\",\n\t\"rightarrow\",\n\t\"rightsquigarrow\",\n\t\"searrow\",\n\t\"sim\",\n\t\"simeq\",\n\t\"sqsubset\",\n\t\"sqsubseteq\",\n\t\"sqsupset\",\n\t\"sqsupseteq\",\n\t\"subset\",\n\t\"subseteq\",\n\t\"succ\",\n\t\"succeq\",\n\t\"supset\",\n\t\"supseteq\",\n\t\"swarrow\",\n\t\"to\",\n\t\"triangleleft\",\n\t\"triangleright\",\n\t\"twoheadleftarrow\",\n\t\"twoheadrightarrow\",\n\t\"uparrow\",\n\t\"vdash\",\n]);\n\nconst NEGATED_SYMBOLS: Readonly<Record<string, string>> = {\n\t\"<\": \"≮\",\n\t\">\": \"≯\",\n\t\"=\": \"≠\",\n\t\"∈\": \"∉\",\n\t\"∋\": \"∌\",\n\t\"∣\": \"∤\",\n\t\"∥\": \"∦\",\n\t\"∼\": \"≁\",\n\t\"≃\": \"≄\",\n\t\"≅\": \"≇\",\n\t\"≈\": \"≉\",\n\t\"≡\": \"≢\",\n\t\"≤\": \"≰\",\n\t\"≥\": \"≱\",\n\t\"≺\": \"⊀\",\n\t\"≻\": \"⊁\",\n\t\"⊂\": \"⊄\",\n\t\"⊃\": \"⊅\",\n\t\"⊆\": \"⊈\",\n\t\"⊇\": \"⊉\",\n\t\"⊢\": \"⊬\",\n\t\"⊨\": \"⊭\",\n\t\"↔\": \"↮\",\n\t\"←\": \"↚\",\n\t\"→\": \"↛\",\n\t\"⇒\": \"⇏\",\n\t\"⇐\": \"⇍\",\n\t\"⇔\": \"⇎\",\n\t\"≼\": \"⋠\",\n\t\"≽\": \"⋡\",\n};\n\nconst BLACKBOARD: Readonly<Record<string, string>> = {\n\tC: \"ℂ\",\n\tH: \"ℍ\",\n\tN: \"ℕ\",\n\tP: \"ℙ\",\n\tQ: \"ℚ\",\n\tR: \"ℝ\",\n\tZ: \"ℤ\",\n};\n\nconst SUPERSCRIPTS: Readonly<Record<string, string>> = {\n\t\"0\": \"⁰\",\n\t\"1\": \"¹\",\n\t\"2\": \"²\",\n\t\"3\": \"³\",\n\t\"4\": \"⁴\",\n\t\"5\": \"⁵\",\n\t\"6\": \"⁶\",\n\t\"7\": \"⁷\",\n\t\"8\": \"⁸\",\n\t\"9\": \"⁹\",\n\t\"+\": \"⁺\",\n\t\"-\": \"⁻\",\n\t\"=\": \"⁼\",\n\t\"(\": \"⁽\",\n\t\")\": \"⁾\",\n\ta: \"ᵃ\",\n\tb: \"ᵇ\",\n\tc: \"ᶜ\",\n\td: \"ᵈ\",\n\te: \"ᵉ\",\n\tf: \"ᶠ\",\n\tg: \"ᵍ\",\n\th: \"ʰ\",\n\ti: \"ⁱ\",\n\tj: \"ʲ\",\n\tk: \"ᵏ\",\n\tl: \"ˡ\",\n\tm: \"ᵐ\",\n\tn: \"ⁿ\",\n\to: \"ᵒ\",\n\tp: \"ᵖ\",\n\tr: \"ʳ\",\n\ts: \"ˢ\",\n\tt: \"ᵗ\",\n\tu: \"ᵘ\",\n\tv: \"ᵛ\",\n\tw: \"ʷ\",\n\tx: \"ˣ\",\n\ty: \"ʸ\",\n\tz: \"ᶻ\",\n};\n\nconst SUBSCRIPTS: Readonly<Record<string, string>> = {\n\t\"0\": \"₀\",\n\t\"1\": \"₁\",\n\t\"2\": \"₂\",\n\t\"3\": \"₃\",\n\t\"4\": \"₄\",\n\t\"5\": \"₅\",\n\t\"6\": \"₆\",\n\t\"7\": \"₇\",\n\t\"8\": \"₈\",\n\t\"9\": \"₉\",\n\t\"+\": \"₊\",\n\t\"-\": \"₋\",\n\t\"=\": \"₌\",\n\t\"(\": \"₍\",\n\t\")\": \"₎\",\n\ta: \"ₐ\",\n\te: \"ₑ\",\n\th: \"ₕ\",\n\ti: \"ᵢ\",\n\tj: \"ⱼ\",\n\tk: \"ₖ\",\n\tl: \"ₗ\",\n\tm: \"ₘ\",\n\tn: \"ₙ\",\n\to: \"ₒ\",\n\tp: \"ₚ\",\n\tr: \"ᵣ\",\n\ts: \"ₛ\",\n\tt: \"ₜ\",\n\tu: \"ᵤ\",\n\tv: \"ᵥ\",\n\tx: \"ₓ\",\n};\n\nconst SPACING_COMMANDS = new Set([\n\t\",\",\n\t\":\",\n\t\";\",\n\t\" \",\n\t\">\",\n\t\"enspace\",\n\t\"enskip\",\n\t\"medspace\",\n\t\"quad\",\n\t\"qquad\",\n\t\"thickspace\",\n\t\"thinspace\",\n]);\nconst NEGATIVE_SPACING_COMMANDS = new Set([\"!\", \"negmedspace\", \"negthickspace\", \"negthinspace\"]);\nconst NEGATIVE_SPACE = \"\\u0000\";\nconst IGNORED_COMMANDS = new Set([\n\t\"displaystyle\",\n\t\"limits\",\n\t\"nolimits\",\n\t\"scriptstyle\",\n\t\"scriptscriptstyle\",\n\t\"textstyle\",\n]);\nconst SIZE_COMMANDS = new Set([\n\t\"big\",\n\t\"Big\",\n\t\"bigg\",\n\t\"Bigg\",\n\t\"bigl\",\n\t\"Bigl\",\n\t\"biggl\",\n\t\"Biggl\",\n\t\"bigr\",\n\t\"Bigr\",\n\t\"biggr\",\n\t\"Biggr\",\n]);\nconst LITERAL_COMMANDS = new Set([\"{\", \"}\", \"$\", \"%\", \"#\", \"_\", \"&\"]);\nconst DELIMITER_COMMANDS = new Set([\"left\", \"middle\", \"right\"]);\nconst PLAIN_WRAPPERS = new Set([\n\t\"emph\",\n\t\"mathcal\",\n\t\"mathbf\",\n\t\"mathfrak\",\n\t\"mathit\",\n\t\"mathrm\",\n\t\"mathnormal\",\n\t\"mathscr\",\n\t\"mathsf\",\n\t\"mathtt\",\n\t\"mathup\",\n\t\"mbox\",\n\t\"overbrace\",\n\t\"pmb\",\n\t\"smash\",\n\t\"substack\",\n\t\"text\",\n\t\"textbf\",\n\t\"textit\",\n\t\"textmd\",\n\t\"textnormal\",\n\t\"textrm\",\n\t\"textsc\",\n\t\"textsf\",\n\t\"textsl\",\n\t\"texttt\",\n\t\"textup\",\n\t\"underbrace\",\n\t\"bm\",\n\t\"boldsymbol\",\n]);\nconst ACCENTS: Readonly<Record<string, string>> = {\n\tacute: \"\\u0301\",\n\tbar: \"\\u0305\",\n\tbreve: \"\\u0306\",\n\tcheck: \"\\u030c\",\n\tddot: \"\\u0308\",\n\tdot: \"\\u0307\",\n\tgrave: \"\\u0300\",\n\that: \"\\u0302\",\n\tmathring: \"\\u030a\",\n\toverleftarrow: \"\\u20d6\",\n\toverleftrightarrow: \"\\u20e1\",\n\toverline: \"\\u0305\",\n\toverrightarrow: \"\\u20d7\",\n\ttilde: \"\\u0303\",\n\tunderline: \"\\u0332\",\n\tvec: \"\\u20d7\",\n\twidehat: \"\\u0302\",\n\twidetilde: \"\\u0303\",\n};\n\ntype MathScriptKind = \"sub\" | \"sup\";\ntype OperatorScriptMarker = \"_\" | \"^\";\ntype InlineOperatorLowerStyle = \"bracket\" | \"script\";\n\nfunction replaceCharacters(value: string, replacements: Readonly<Record<string, string>>): string | undefined {\n\tlet result = \"\";\n\tfor (const character of value) {\n\t\tconst replacement = replacements[character];\n\t\tif (replacement === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tresult += replacement;\n\t}\n\treturn result;\n}\n\nfunction formatScript(value: string, kind: MathScriptKind): string {\n\tvalue = value.trim();\n\tconst replacements = kind === \"sub\" ? SUBSCRIPTS : SUPERSCRIPTS;\n\tconst unicode = replaceCharacters(value.replace(/\\s*([=+-])\\s*/g, \"$1\"), replacements);\n\tif (unicode !== undefined) {\n\t\treturn unicode;\n\t}\n\n\tconst prefix = kind === \"sub\" ? \"_\" : \"^\";\n\tif (Array.from(value).length === 1 || (kind === \"sub\" && /^[A-Za-z]+$/.test(value))) {\n\t\treturn `${prefix}${value}`;\n\t}\n\treturn `${prefix}(${value})`;\n}\n\nfunction formatFraction(numerator: string, denominator: string): string {\n\tnumerator = numerator.trim();\n\tdenominator = denominator.trim();\n\tconst simpleNumerator = /^[\\p{L}\\p{N}.]+$/u.test(numerator);\n\tconst simpleDenominator = /^[\\p{N}.]+$/u.test(denominator) || Array.from(denominator).length === 1;\n\treturn `${simpleNumerator ? numerator : `(${numerator})`}/${simpleDenominator ? denominator : `(${denominator})`}`;\n}\n\nfunction formatRoot(value: string, symbol = \"√\"): string {\n\tvalue = value.trim();\n\treturn /^[\\p{L}\\p{N}.]+$/u.test(value) ? `${symbol}${value}` : `${symbol}(${value})`;\n}\n\nconst NAMED_OPERATOR_START = \"\\u{f0004}\";\nconst NAMED_OPERATOR_END = \"\\u{f0005}\";\nconst NAMED_OPERATOR_LEFT_SPACING_PATTERN = /(?<=[\\p{L}\\p{N})\\]}\\u{f0001}])\\u{f0004}/gu;\nconst NAMED_OPERATOR_RIGHT_SPACING_PATTERN = /\\u{f0005}(?=[\\p{L}\\p{N}√\\u{f0000}])/gu;\n\nfunction normalizeOutput(value: string): string {\n\treturn value\n\t\t.replace(NAMED_OPERATOR_LEFT_SPACING_PATTERN, \" \")\n\t\t.replaceAll(NAMED_OPERATOR_START, \"\")\n\t\t.replace(NAMED_OPERATOR_RIGHT_SPACING_PATTERN, \" \")\n\t\t.replaceAll(NAMED_OPERATOR_END, \"\")\n\t\t.split(\"\\n\")\n\t\t.map((line) => line.replace(/[ \\t]+/g, \" \").trim())\n\t\t.filter((line, index, lines) => line.length > 0 || (index > 0 && index < lines.length - 1))\n\t\t.join(\"\\n\")\n\t\t.trim();\n}\n\ninterface FractionNode {\n\ttype: \"fraction\";\n\tnumerator: string;\n\tdenominator: string;\n}\n\ninterface OperatorNode {\n\ttype: \"operator\";\n\toperator: string;\n\tlower?: string;\n\tupper?: string;\n}\n\ninterface ParsedOperatorScripts {\n\tlower?: string;\n\tupper?: string;\n}\n\ninterface MatrixNode {\n\ttype: \"matrix\";\n\tlines: string[];\n\tbaseline: number;\n}\n\ntype LayoutNode = FractionNode | OperatorNode | MatrixNode;\n\ninterface Layout {\n\tlines: string[];\n\twidth: number;\n\tbaseline: number;\n}\n\nconst LAYOUT_MARKER_START = \"\\u{f0000}\";\nconst LAYOUT_MARKER_END = \"\\u{f0001}\";\nconst LAYOUT_MARKER_PATTERN = /\\u{f0000}(\\d+)\\u{f0001}/gu;\nconst TRAILING_LAYOUT_MARKER_PATTERN = /\\u{f0000}(\\d+)\\u{f0001}$/u;\nconst PROTECTED_SPACE = \"\\u{f0002}\";\nconst RESERVED_MARKER_PATTERN = /[\\u{f0000}\\u{f0001}\\u{f0002}\\u{f0004}\\u{f0005}]/u;\nconst MAX_SOURCE_LENGTH = 16 * 1024;\nconst MAX_NESTING_DEPTH = 64;\nconst MAX_LAYOUT_NODES = 256;\nconst MAX_RENDERED_ROWS = 200;\nconst MAX_RENDERED_LINE_WIDTH = 4096;\n\ninterface LatexParseState {\n\tnestingDepth: number;\n}\n\ntype LatexSequenceCharacterKind =\n\t| \"end\"\n\t| \"unexpected-close\"\n\t| \"group\"\n\t| \"command\"\n\t| \"script\"\n\t| \"whitespace\"\n\t| \"relation\"\n\t| \"alignment\"\n\t| \"space\"\n\t| \"period\"\n\t| \"literal\";\n\nfunction classifyLatexSequenceCharacter(character: string, endCharacter?: string): LatexSequenceCharacterKind {\n\tif (endCharacter && character === endCharacter) return \"end\";\n\tswitch (character) {\n\t\tcase \"}\":\n\t\t\treturn \"unexpected-close\";\n\t\tcase \"{\":\n\t\t\treturn \"group\";\n\t\tcase \"\\\\\":\n\t\t\treturn \"command\";\n\t\tcase \"^\":\n\t\tcase \"_\":\n\t\t\treturn \"script\";\n\t\tcase \"=\":\n\t\tcase \"<\":\n\t\tcase \">\":\n\t\t\treturn \"relation\";\n\t\tcase \"&\":\n\t\t\treturn \"alignment\";\n\t\tcase \"~\":\n\t\t\treturn \"space\";\n\t\tcase \".\":\n\t\t\treturn \"period\";\n\t\tdefault:\n\t\t\treturn /\\s/.test(character) ? \"whitespace\" : \"literal\";\n\t}\n}\n\nfunction assertLayoutBounds(width: number, rowCount: number): void {\n\tif (\n\t\t!Number.isSafeInteger(width) ||\n\t\twidth < 0 ||\n\t\twidth > MAX_RENDERED_LINE_WIDTH ||\n\t\t!Number.isSafeInteger(rowCount) ||\n\t\trowCount < 0 ||\n\t\trowCount > MAX_RENDERED_ROWS\n\t) {\n\t\tthrow new RangeError(\"LaTeX layout exceeds renderer bounds\");\n\t}\n}\n\nfunction padLayoutLine(line: string, width: number, centered = false): string {\n\tconst padding = Math.max(0, width - visibleWidth(line));\n\tconst left = centered ? Math.floor(padding / 2) : 0;\n\treturn `${\" \".repeat(left)}${line}${\" \".repeat(padding - left)}`;\n}\n\n// pi-ignore noExcessiveCollectionIterations: Every output row must concatenate every layout segment; rows are capped at 200 and parsed layout nodes at 256.\nfunction joinLayouts(layouts: readonly Layout[]): Layout {\n\tif (layouts.length === 0) {\n\t\treturn { lines: [\"\"], width: 0, baseline: 0 };\n\t}\n\tconst baseline = Math.max(...layouts.map((layout) => layout.baseline));\n\tconst below = Math.max(...layouts.map((layout) => layout.lines.length - layout.baseline - 1));\n\tconst width = layouts.reduce((total, layout) => total + layout.width, 0);\n\tconst rowCount = baseline + below + 1;\n\tassertLayoutBounds(width, rowCount);\n\tconst lines: string[] = [];\n\tfor (let row = 0; row < rowCount; row++) {\n\t\tlet line = \"\";\n\t\tfor (const layout of layouts) {\n\t\t\tconst sourceRow = row - baseline + layout.baseline;\n\t\t\tline +=\n\t\t\t\tsourceRow >= 0 && sourceRow < layout.lines.length\n\t\t\t\t\t? padLayoutLine(layout.lines[sourceRow] ?? \"\", layout.width)\n\t\t\t\t\t: \" \".repeat(layout.width);\n\t\t}\n\t\tlines.push(line.trimEnd());\n\t}\n\treturn { lines, width, baseline };\n}\n\nfunction createTextLayout(text: string): Layout {\n\treturn { lines: [text], width: visibleWidth(text), baseline: 0 };\n}\n\nfunction createInterNodeTextLayout(source: string, previousNode: LayoutNode | undefined, nextNode: LayoutNode): Layout {\n\tconst trimmed = (previousNode ? source.trimStart() : source).trimEnd();\n\tconst preserveLeadingSpace = previousNode?.type === \"matrix\" && /^\\s/.test(source);\n\tconst preserveTrailingSpace = nextNode.type === \"matrix\" && /\\s$/.test(source);\n\tconst text = trimmed\n\t\t? `${preserveLeadingSpace ? \" \" : \"\"}${trimmed}${preserveTrailingSpace ? \" \" : \"\"}`\n\t\t: preserveLeadingSpace || preserveTrailingSpace\n\t\t\t? \" \"\n\t\t\t: \"\";\n\treturn createTextLayout(text);\n}\n\nfunction createTrailingTextLayout(source: string, previousNode: LayoutNode | undefined): Layout {\n\tconst trimmed = previousNode ? source.trimStart() : source;\n\tconst text = previousNode?.type === \"matrix\" && /^\\s/.test(source) ? ` ${trimmed}` : trimmed;\n\treturn createTextLayout(text);\n}\n\nfunction renderFractionNodeLayout(node: FractionNode, nodes: readonly LayoutNode[]): Layout {\n\tconst numerator = renderLayout(node.numerator, nodes);\n\tconst denominator = renderLayout(node.denominator, nodes);\n\tconst contentWidth = Math.max(numerator.width, denominator.width, 1);\n\tconst width = contentWidth + 2;\n\tconst lines = [\n\t\t...numerator.lines.map((line) => padLayoutLine(line, width, true)),\n\t\t` ${\"─\".repeat(contentWidth)} `,\n\t\t...denominator.lines.map((line) => padLayoutLine(line, width, true)),\n\t];\n\tassertLayoutBounds(width, lines.length);\n\treturn { lines, width, baseline: numerator.lines.length };\n}\n\nfunction renderOperatorNodeLayout(node: OperatorNode): Layout {\n\tconst contentWidth = Math.max(\n\t\tvisibleWidth(node.operator),\n\t\tnode.lower === undefined ? 0 : visibleWidth(node.lower),\n\t\tnode.upper === undefined ? 0 : visibleWidth(node.upper),\n\t);\n\tconst lines: string[] = [];\n\tif (node.upper !== undefined) lines.push(`${padLayoutLine(node.upper, contentWidth, true)} `);\n\tlines.push(`${padLayoutLine(node.operator, contentWidth, true)} `);\n\tif (node.lower !== undefined) lines.push(`${padLayoutLine(node.lower, contentWidth, true)} `);\n\tassertLayoutBounds(contentWidth + 1, lines.length);\n\treturn { lines, width: contentWidth + 1, baseline: node.upper === undefined ? 0 : 1 };\n}\n\nfunction renderMatrixNodeLayout(node: MatrixNode): Layout {\n\tconst width = Math.max(0, ...node.lines.map((line) => visibleWidth(line)));\n\tassertLayoutBounds(width, node.lines.length);\n\treturn {\n\t\tlines: node.lines.map((line) => padLayoutLine(line, width)),\n\t\twidth,\n\t\tbaseline: node.baseline,\n\t};\n}\n\nfunction renderLayoutNode(node: LayoutNode, nodes: readonly LayoutNode[]): Layout {\n\tswitch (node.type) {\n\t\tcase \"fraction\":\n\t\t\treturn renderFractionNodeLayout(node, nodes);\n\t\tcase \"operator\":\n\t\t\treturn renderOperatorNodeLayout(node);\n\t\tcase \"matrix\":\n\t\t\treturn renderMatrixNodeLayout(node);\n\t}\n}\n\nfunction renderSourceLineLayout(sourceLine: string, nodes: readonly LayoutNode[]): Layout {\n\tconst layouts: Layout[] = [];\n\tlet position = 0;\n\tlet previousNode: LayoutNode | undefined;\n\tfor (const match of sourceLine.matchAll(LAYOUT_MARKER_PATTERN)) {\n\t\tconst index = match.index;\n\t\tconst node = nodes[Number(match[1])];\n\t\tif (!node) continue;\n\t\tif (index > position) {\n\t\t\tlayouts.push(createInterNodeTextLayout(sourceLine.slice(position, index), previousNode, node));\n\t\t}\n\t\tlayouts.push(renderLayoutNode(node, nodes));\n\t\tposition = index + match[0].length;\n\t\tpreviousNode = node;\n\t}\n\tif (position < sourceLine.length) {\n\t\tlayouts.push(createTrailingTextLayout(sourceLine.slice(position), previousNode));\n\t}\n\treturn joinLayouts(layouts);\n}\n\nfunction renderLayout(source: string, nodes: readonly LayoutNode[]): Layout {\n\tconst renderedLines: string[] = [];\n\tlet firstBaseline = 0;\n\tfor (const sourceLine of source.split(\"\\n\")) {\n\t\tconst lineLayout = renderSourceLineLayout(sourceLine, nodes);\n\t\tif (renderedLines.length === 0) firstBaseline = lineLayout.baseline;\n\t\trenderedLines.push(...lineLayout.lines);\n\t\tassertLayoutBounds(0, renderedLines.length);\n\t}\n\tconst width = Math.max(0, ...renderedLines.map((line) => visibleWidth(line)));\n\tassertLayoutBounds(width, renderedLines.length);\n\treturn { lines: renderedLines, width, baseline: firstBaseline };\n}\n\nclass LatexParser {\n\tprivate readonly source: string;\n\tprivate readonly layoutNodes: LayoutNode[];\n\tprivate readonly display: boolean;\n\tprivate readonly state: LatexParseState;\n\tprivate position = 0;\n\tprivate supported = true;\n\tprivate stackFractions = true;\n\n\tconstructor(\n\t\tsource: string,\n\t\tlayoutNodes: LayoutNode[],\n\t\tdisplay: boolean,\n\t\tstate: LatexParseState = { nestingDepth: 0 },\n\t) {\n\t\tthis.source = source;\n\t\tthis.layoutNodes = layoutNodes;\n\t\tthis.display = display;\n\t\tthis.state = state;\n\t}\n\n\trender(): string | undefined {\n\t\tconst rendered = this.parseSequence();\n\t\tif (!this.supported || this.position !== this.source.length) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn normalizeOutput(rendered);\n\t}\n\n\tprivate appendParsedCommand(result: string): string {\n\t\tconst command = this.parseCommand();\n\t\tif (command !== NEGATIVE_SPACE) return result + command;\n\t\tconst trimmed = result.trimEnd();\n\t\treturn trimmed.endsWith(NAMED_OPERATOR_END) ? trimmed.slice(0, -NAMED_OPERATOR_END.length) : trimmed;\n\t}\n\n\tprivate appendParsedScript(result: string, character: string): string {\n\t\tthis.position++;\n\t\tconst trimmed = result.trimEnd();\n\t\tconst script = formatScript(this.parseRequiredArgument(false), character === \"_\" ? \"sub\" : \"sup\");\n\t\treturn trimmed.endsWith(NAMED_OPERATOR_END)\n\t\t\t? `${trimmed.slice(0, -NAMED_OPERATOR_END.length)}${script}${NAMED_OPERATOR_END}`\n\t\t\t: trimmed + script;\n\t}\n\n\tprivate appendPeriod(result: string): string {\n\t\tconst marker = TRAILING_LAYOUT_MARKER_PATTERN.exec(result);\n\t\tconst node = marker ? this.layoutNodes[Number(marker[1])] : undefined;\n\t\tif (node?.type === \"matrix\") {\n\t\t\tconst lastLine = node.lines.length - 1;\n\t\t\tnode.lines[lastLine] = `${node.lines[lastLine] ?? \"\"}.`;\n\t\t\tthis.position++;\n\t\t\treturn result;\n\t\t}\n\t\tthis.position++;\n\t\treturn `${result}.`;\n\t}\n\n\tprivate parseSequence(endCharacter?: string): string {\n\t\tlet result = \"\";\n\t\twhile (this.position < this.source.length) {\n\t\t\tconst character = this.source[this.position];\n\t\t\tswitch (classifyLatexSequenceCharacter(character, endCharacter)) {\n\t\t\t\tcase \"end\":\n\t\t\t\t\tthis.position++;\n\t\t\t\t\treturn result;\n\t\t\t\tcase \"unexpected-close\":\n\t\t\t\t\tthis.supported = false;\n\t\t\t\t\treturn result;\n\t\t\t\tcase \"group\":\n\t\t\t\t\tthis.position++;\n\t\t\t\t\tresult += this.parseNestedSequence(\"}\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"command\":\n\t\t\t\t\tresult = this.appendParsedCommand(result);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"script\":\n\t\t\t\t\tresult = this.appendParsedScript(result, character);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"whitespace\":\n\t\t\t\t\tresult += this.parseWhitespace();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"relation\":\n\t\t\t\t\tresult = `${result.trimEnd()} ${character} `;\n\t\t\t\t\tthis.position++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"alignment\":\n\t\t\t\t\tthis.position++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"space\":\n\t\t\t\t\tthis.position++;\n\t\t\t\t\tresult += \" \";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"period\":\n\t\t\t\t\tresult = this.appendPeriod(result);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"literal\":\n\t\t\t\t\tresult += character;\n\t\t\t\t\tthis.position++;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (endCharacter) this.supported = false;\n\t\treturn result;\n\t}\n\n\tprivate parseWhitespace(): string {\n\t\twhile (this.position < this.source.length && /\\s/.test(this.source[this.position] ?? \"\")) {\n\t\t\tthis.position++;\n\t\t}\n\t\treturn \" \";\n\t}\n\n\tprivate readCommandName(): string | undefined {\n\t\tthis.position++;\n\t\tif (this.position >= this.source.length) {\n\t\t\tthis.supported = false;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst first = this.source[this.position] ?? \"\";\n\t\tif (!/[A-Za-z]/.test(first)) {\n\t\t\tthis.position++;\n\t\t\treturn first;\n\t\t}\n\t\tconst start = this.position;\n\t\twhile (this.position < this.source.length && /[A-Za-z]/.test(this.source[this.position] ?? \"\")) {\n\t\t\tthis.position++;\n\t\t}\n\t\treturn this.source.slice(start, this.position);\n\t}\n\n\tprivate parsePredefinedCommand(command: string): string | undefined {\n\t\tif (command === \"\\\\\") return \"\\n\";\n\t\tif (SPACING_COMMANDS.has(command)) return \" \";\n\t\tif (NEGATIVE_SPACING_COMMANDS.has(command)) return NEGATIVE_SPACE;\n\t\tif (IGNORED_COMMANDS.has(command)) return \"\";\n\t\tif (LITERAL_COMMANDS.has(command)) return command;\n\t\tif (command === \"|\") return \"‖\";\n\t\treturn undefined;\n\t}\n\n\tprivate parseNegatedCommand(): string {\n\t\tconst value = this.parseRequiredArgument(false).trim();\n\t\tconst negated = NEGATED_SYMBOLS[value];\n\t\tif (negated !== undefined) return ` ${negated} `;\n\n\t\tconst characters = Array.from(value);\n\t\tif (characters.length === 0) {\n\t\t\tthis.supported = false;\n\t\t\treturn \"\";\n\t\t}\n\t\treturn ` ${characters[0]}\\u0338${characters.slice(1).join(\"\")} `;\n\t}\n\n\tprivate parseSymbolCommand(command: string): string | undefined {\n\t\tconst symbol = SYMBOLS[command];\n\t\tif (symbol === undefined) return undefined;\n\t\tif (DISPLAY_LIMIT_SYMBOLS.has(command)) return this.parseOperator(symbol, \"script\", true);\n\t\treturn command === \"cdot\" || command === \"times\" || RELATION_COMMANDS.has(command) ? ` ${symbol} ` : symbol;\n\t}\n\n\tprivate parseNamedOrDelimiterCommand(command: string): string | undefined {\n\t\tif (NAMED_OPERATORS.has(command)) return `${NAMED_OPERATOR_START}${command}${NAMED_OPERATOR_END}`;\n\t\tif (SIZE_COMMANDS.has(command)) return \"\";\n\t\tif (!DELIMITER_COMMANDS.has(command)) return undefined;\n\t\tif (this.source[this.position] === \".\") this.position++;\n\t\treturn \"\";\n\t}\n\n\tprivate parseFractionCommand(command: string): string {\n\t\tconst shouldStack = this.display && this.stackFractions && command !== \"tfrac\";\n\t\tconst numerator = this.parseRequiredArgument(!shouldStack);\n\t\tconst denominator = this.parseRequiredArgument(!shouldStack);\n\t\tif (!shouldStack) return formatFraction(numerator, denominator);\n\n\t\tconst index = this.addLayoutNode({\n\t\t\ttype: \"fraction\",\n\t\t\tnumerator: normalizeOutput(numerator),\n\t\t\tdenominator: normalizeOutput(denominator),\n\t\t});\n\t\treturn index === undefined ? \"\" : `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;\n\t}\n\n\tprivate parseRootCommand(): string {\n\t\tconst degree = this.parseOptionalArgument()?.trim();\n\t\tconst value = this.parseRequiredArgument();\n\t\tif (degree === undefined || degree === \"2\") return formatRoot(value);\n\t\tif (degree === \"3\") return formatRoot(value, \"∛\");\n\t\tif (degree === \"4\") return formatRoot(value, \"∜\");\n\t\treturn `${formatScript(degree, \"sup\")}${formatRoot(value)}`;\n\t}\n\n\tprivate parseAccentCommand(command: string, accent: string): string {\n\t\tconst value = this.parseRequiredArgument();\n\t\treturn Array.from(value).length === 1 ? `${value}${accent}` : `${command}(${value})`;\n\t}\n\n\tprivate parseOperatorNameCommand(): string {\n\t\tconst starred = this.source[this.position] === \"*\";\n\t\tif (starred) this.position++;\n\t\tconst operator = normalizeOutput(this.parseRequiredArgument()).trim();\n\t\treturn this.parseOperator(operator, \"bracket\", starred, true);\n\t}\n\n\tprivate parseArgumentCommand(command: string): string | undefined {\n\t\tswitch (command) {\n\t\t\tcase \"frac\":\n\t\t\tcase \"dfrac\":\n\t\t\tcase \"tfrac\":\n\t\t\t\treturn this.parseFractionCommand(command);\n\t\t\tcase \"sqrt\":\n\t\t\t\treturn this.parseRootCommand();\n\t\t\tcase \"boxed\":\n\t\t\tcase \"fbox\":\n\t\t\t\treturn `[${this.parseRequiredArgument().trim()}]`;\n\t\t\tcase \"binom\":\n\t\t\tcase \"dbinom\":\n\t\t\tcase \"tbinom\":\n\t\t\t\treturn `(${this.parseRequiredArgument()} choose ${this.parseRequiredArgument()})`;\n\t\t\tcase \"mathbb\": {\n\t\t\t\tconst value = this.parseRequiredArgument();\n\t\t\t\treturn Array.from(value, (character) => BLACKBOARD[character] ?? character).join(\"\");\n\t\t\t}\n\t\t\tcase \"operatorname\":\n\t\t\t\treturn this.parseOperatorNameCommand();\n\t\t\tcase \"mod\":\n\t\t\tcase \"bmod\":\n\t\t\t\treturn \" mod \";\n\t\t\tcase \"pmod\":\n\t\t\tcase \"pod\": {\n\t\t\t\tconst value = this.parseRequiredArgument().trim();\n\t\t\t\treturn command === \"pmod\" ? ` (mod ${value})` : ` (${value})`;\n\t\t\t}\n\t\t\tcase \"overset\":\n\t\t\tcase \"stackrel\": {\n\t\t\t\tconst upper = this.parseRequiredArgument();\n\t\t\t\tconst value = this.parseRequiredArgument().trim();\n\t\t\t\treturn `${value}${formatScript(upper, \"sup\")}`;\n\t\t\t}\n\t\t\tcase \"underset\": {\n\t\t\t\tconst lower = this.parseRequiredArgument();\n\t\t\t\tconst value = this.parseRequiredArgument().trim();\n\t\t\t\treturn `${value}${formatScript(lower, \"sub\")}`;\n\t\t\t}\n\t\t\tcase \"begin\":\n\t\t\t\treturn this.parseEnvironment();\n\t\t\tcase \"end\":\n\t\t\t\tthis.supported = false;\n\t\t\t\treturn \"\";\n\t\t}\n\n\t\tconst accent = ACCENTS[command];\n\t\tif (accent !== undefined) return this.parseAccentCommand(command, accent);\n\t\tif (PLAIN_WRAPPERS.has(command)) {\n\t\t\tconst value = this.parseRequiredArgument();\n\t\t\treturn command.startsWith(\"text\") || command === \"mbox\" ? value : value.trim();\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate parseCommand(): string {\n\t\tconst command = this.readCommandName();\n\t\tif (command === undefined) return \"\";\n\n\t\tconst predefined = this.parsePredefinedCommand(command);\n\t\tif (predefined !== undefined) return predefined;\n\t\tif (command === \"not\") return this.parseNegatedCommand();\n\t\tif (LIMIT_OPERATORS.has(command)) return this.parseOperator(command, \"bracket\", true, true);\n\n\t\tconst symbol = this.parseSymbolCommand(command);\n\t\tif (symbol !== undefined) return symbol;\n\t\tconst namedOrDelimiter = this.parseNamedOrDelimiterCommand(command);\n\t\tif (namedOrDelimiter !== undefined) return namedOrDelimiter;\n\t\tconst argumentCommand = this.parseArgumentCommand(command);\n\t\tif (argumentCommand !== undefined) return argumentCommand;\n\n\t\tthis.supported = false;\n\t\treturn `\\\\${command}`;\n\t}\n\n\tprivate assignOperatorScript(scripts: ParsedOperatorScripts, kind: OperatorScriptMarker, value: string): void {\n\t\tconst property = kind === \"_\" ? \"lower\" : \"upper\";\n\t\tif (scripts[property] !== undefined) this.supported = false;\n\t\tscripts[property] = value;\n\t}\n\n\tprivate parseOperatorDisplayLimits(displayLimits: boolean): boolean {\n\t\tlet modifierPosition = this.position;\n\t\twhile (modifierPosition < this.source.length && /[ \\t]/.test(this.source[modifierPosition] ?? \"\")) {\n\t\t\tmodifierPosition++;\n\t\t}\n\t\tconst modifier = /^\\\\(limits|nolimits)(?![A-Za-z])/.exec(this.source.slice(modifierPosition));\n\t\tif (!modifier) return displayLimits;\n\t\tthis.position = modifierPosition + modifier[0].length;\n\t\treturn modifier[1] === \"limits\";\n\t}\n\n\tprivate parseOperatorScripts(): ParsedOperatorScripts {\n\t\tconst scripts: ParsedOperatorScripts = {};\n\t\twhile (true) {\n\t\t\tlet scriptPosition = this.position;\n\t\t\twhile (scriptPosition < this.source.length && /[ \\t]/.test(this.source[scriptPosition] ?? \"\")) {\n\t\t\t\tscriptPosition++;\n\t\t\t}\n\t\t\tconst kind = this.source[scriptPosition];\n\t\t\tif (kind !== \"_\" && kind !== \"^\") break;\n\t\t\tthis.position = scriptPosition + 1;\n\t\t\tconst value = normalizeOutput(this.parseRequiredArgument(false)).replaceAll(\" \", \"\");\n\t\t\tthis.assignOperatorScript(scripts, kind, value);\n\t\t}\n\t\treturn scripts;\n\t}\n\n\tprivate parseOperator(\n\t\toperator: string,\n\t\tinlineLowerStyle: InlineOperatorLowerStyle,\n\t\tdisplayLimits: boolean,\n\t\tspaced = false,\n\t): string {\n\t\tconst useDisplayLimits = this.parseOperatorDisplayLimits(displayLimits);\n\t\tconst { lower, upper } = this.parseOperatorScripts();\n\t\tif (this.display && useDisplayLimits && (lower !== undefined || upper !== undefined)) {\n\t\t\tconst index = this.addLayoutNode({ type: \"operator\", operator, lower, upper });\n\t\t\treturn index === undefined ? \"\" : `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;\n\t\t}\n\n\t\tlet rendered = operator;\n\t\tif (lower !== undefined) {\n\t\t\trendered += inlineLowerStyle === \"bracket\" ? `[${lower}]` : formatScript(lower, \"sub\");\n\t\t}\n\t\tif (upper !== undefined) rendered += formatScript(upper, \"sup\");\n\t\treturn spaced ? ` ${rendered} ` : rendered;\n\t}\n\n\tprivate parseRequiredArgument(stackFractions = true): string {\n\t\tconst previousStackFractions = this.stackFractions;\n\t\tthis.stackFractions = previousStackFractions && stackFractions;\n\t\tconst value = this.parseRequiredArgumentValue();\n\t\tthis.stackFractions = previousStackFractions;\n\t\treturn value;\n\t}\n\n\tprivate parseRequiredArgumentValue(): string {\n\t\twhile (this.position < this.source.length && /[ \\t]/.test(this.source[this.position] ?? \"\")) {\n\t\t\tthis.position++;\n\t\t}\n\t\tif (this.position >= this.source.length) {\n\t\t\tthis.supported = false;\n\t\t\treturn \"\";\n\t\t}\n\t\tif (this.source[this.position] === \"{\") {\n\t\t\tthis.position++;\n\t\t\treturn this.parseNestedSequence(\"}\");\n\t\t}\n\t\tif (this.source[this.position] === \"\\\\\") {\n\t\t\treturn this.parseCommand();\n\t\t}\n\t\tconst value = this.source[this.position] ?? \"\";\n\t\tthis.position++;\n\t\treturn value;\n\t}\n\n\tprivate parseOptionalArgument(): string | undefined {\n\t\twhile (this.position < this.source.length && /[ \\t]/.test(this.source[this.position] ?? \"\")) {\n\t\t\tthis.position++;\n\t\t}\n\t\tif (this.source[this.position] !== \"[\") {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst end = this.source.indexOf(\"]\", this.position + 1);\n\t\tif (end < 0) {\n\t\t\tthis.supported = false;\n\t\t\treturn undefined;\n\t\t}\n\t\tconst value = this.source.slice(this.position + 1, end);\n\t\tthis.position = end + 1;\n\t\treturn this.renderNested(value);\n\t}\n\n\tprivate readRawGroupContents(start: number): string | undefined {\n\t\tlet depth = 1;\n\t\twhile (this.position < this.source.length) {\n\t\t\tconst character = this.source[this.position];\n\t\t\tif (character === \"\\\\\") {\n\t\t\t\tthis.position += 2;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (character === \"{\") {\n\t\t\t\tdepth++;\n\t\t\t\tif (this.state.nestingDepth + depth > MAX_NESTING_DEPTH) {\n\t\t\t\t\tthis.supported = false;\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tthis.position++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (character !== \"}\") {\n\t\t\t\tthis.position++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tdepth--;\n\t\t\tif (depth > 0) {\n\t\t\t\tthis.position++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst value = this.source.slice(start, this.position);\n\t\t\tthis.position++;\n\t\t\treturn value;\n\t\t}\n\t\tthis.supported = false;\n\t\treturn undefined;\n\t}\n\n\tprivate readRawGroup(): string | undefined {\n\t\twhile (this.position < this.source.length && /[ \\t]/.test(this.source[this.position] ?? \"\")) {\n\t\t\tthis.position++;\n\t\t}\n\t\tif (this.source[this.position] !== \"{\") {\n\t\t\tthis.supported = false;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst start = ++this.position;\n\t\tif (this.state.nestingDepth + 1 > MAX_NESTING_DEPTH) {\n\t\t\tthis.supported = false;\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.readRawGroupContents(start);\n\t}\n\n\tprivate splitEnvironmentRows(body: string): string[] {\n\t\treturn body.split(/\\\\\\\\(?:\\[[^\\]\\n]*\\])?/);\n\t}\n\n\tprivate parseEnvironment(): string {\n\t\tconst environment = this.readRawGroup();\n\t\tif (!environment) {\n\t\t\treturn \"\";\n\t\t}\n\t\tconst endMarker = `\\\\end{${environment}}`;\n\t\tconst end = this.source.indexOf(endMarker, this.position);\n\t\tif (end < 0) {\n\t\t\tthis.supported = false;\n\t\t\treturn \"\";\n\t\t}\n\t\tconst body = this.source.slice(this.position, end);\n\t\tthis.position = end + endMarker.length;\n\n\t\tif (environment === \"equation\" || environment === \"equation*\" || environment === \"displaymath\") {\n\t\t\treturn this.renderNested(body).trim();\n\t\t}\n\n\t\tif (\n\t\t\tenvironment === \"aligned\" ||\n\t\t\tenvironment === \"align\" ||\n\t\t\tenvironment === \"align*\" ||\n\t\t\tenvironment === \"alignedat\" ||\n\t\t\tenvironment === \"alignat\" ||\n\t\t\tenvironment === \"alignat*\" ||\n\t\t\tenvironment === \"gather\" ||\n\t\t\tenvironment === \"gathered\" ||\n\t\t\tenvironment === \"multline\" ||\n\t\t\tenvironment === \"multline*\" ||\n\t\t\tenvironment === \"split\"\n\t\t) {\n\t\t\tconst alignedAt = [\"alignedat\", \"alignat\", \"alignat*\"].includes(environment);\n\t\t\tconst alignedBody = alignedAt ? body.replace(/^\\s*\\{[^}]*\\}/, \"\") : body;\n\t\t\treturn this.splitEnvironmentRows(alignedBody)\n\t\t\t\t.map((row) => {\n\t\t\t\t\tconst cells = row.split(\"&\");\n\t\t\t\t\tconst source = alignedAt\n\t\t\t\t\t\t? Array.from({ length: Math.ceil(cells.length / 2) }, (_, index) =>\n\t\t\t\t\t\t\t\tcells.slice(index * 2, index * 2 + 2).join(\"\"),\n\t\t\t\t\t\t\t).join(\" \")\n\t\t\t\t\t\t: cells.join(\"\");\n\t\t\t\t\treturn this.renderNested(source).trim();\n\t\t\t\t})\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join(\"\\n\");\n\t\t}\n\n\t\tif (environment === \"cases\" || environment === \"cases*\") {\n\t\t\tconst rows = this.splitEnvironmentRows(body)\n\t\t\t\t.map((row) => row.split(\"&\").map((cell) => this.renderNested(cell, false).trim()))\n\t\t\t\t.filter((row) => row.some(Boolean));\n\t\t\treturn rows\n\t\t\t\t.map((row, index) => {\n\t\t\t\t\tconst value = (row[0] ?? \"\").replace(/,\\s*$/, \"\");\n\t\t\t\t\tconst condition = row[1] ?? \"\";\n\t\t\t\t\tconst delimiter = index === 0 ? \"⎧\" : index === rows.length - 1 ? \"⎩\" : \"⎨\";\n\t\t\t\t\tconst conditionPrefix = /^(?:if|when|for|otherwise)\\b/i.test(condition) ? \" \" : \" if \";\n\t\t\t\t\treturn `${delimiter} ${value}${condition ? `${conditionPrefix}${condition}` : \"\"}`;\n\t\t\t\t})\n\t\t\t\t.join(\"\\n\");\n\t\t}\n\n\t\tif (\n\t\t\t[\"array\", \"matrix\", \"smallmatrix\", \"pmatrix\", \"bmatrix\", \"Bmatrix\", \"vmatrix\", \"Vmatrix\"].includes(environment)\n\t\t) {\n\t\t\tconst matrixBody = environment === \"array\" ? body.replace(/^\\s*\\{[^}]*\\}/, \"\") : body;\n\t\t\treturn this.renderMatrix(environment, matrixBody);\n\t\t}\n\n\t\tthis.supported = false;\n\t\treturn body;\n\t}\n\n\tprivate renderMatrix(environment: string, body: string): string {\n\t\tconst sourceRows = this.splitEnvironmentRows(body).map((row) => row.split(\"&\"));\n\t\tconst sourceColumnCount = Math.max(0, ...sourceRows.map((row) => row.length));\n\t\tif (sourceRows.length > MAX_RENDERED_ROWS || sourceRows.length * sourceColumnCount > MAX_LAYOUT_NODES) {\n\t\t\tthis.supported = false;\n\t\t\treturn \"\";\n\t\t}\n\t\tconst matrix = sourceRows\n\t\t\t.map((row) => row.map((cell) => this.renderNested(cell, false).trim()))\n\t\t\t.filter((row) => row.some(Boolean));\n\t\tconst columnCount = Math.max(0, ...matrix.map((row) => row.length));\n\t\tconst columnWidths = Array.from({ length: columnCount }, (_, column) =>\n\t\t\tMath.max(0, ...matrix.map((row) => visibleWidth(row[column] ?? \"\"))),\n\t\t);\n\t\tconst rows = matrix.map((row) =>\n\t\t\tArray.from({ length: columnCount }, (_, column) => {\n\t\t\t\tconst cell = row[column] ?? \"\";\n\t\t\t\treturn `${cell}${PROTECTED_SPACE.repeat(Math.max(0, (columnWidths[column] ?? 0) - visibleWidth(cell)))}`;\n\t\t\t}).join(\" │ \"),\n\t\t);\n\t\tlet lines: string[];\n\t\tif (environment === \"array\" || environment === \"matrix\" || environment === \"smallmatrix\") {\n\t\t\tlines = rows;\n\t\t} else {\n\t\t\tconst delimiters: Readonly<Record<string, readonly [string, string, string, string, string, string]>> = {\n\t\t\t\tpmatrix: [\"⎛\", \"⎞\", \"⎜\", \"⎟\", \"⎝\", \"⎠\"],\n\t\t\t\tbmatrix: [\"⎡\", \"⎤\", \"⎢\", \"⎥\", \"⎣\", \"⎦\"],\n\t\t\t\tBmatrix: [\"⎧\", \"⎫\", \"⎨\", \"⎬\", \"⎩\", \"⎭\"],\n\t\t\t\tvmatrix: [\"│\", \"│\", \"│\", \"│\", \"│\", \"│\"],\n\t\t\t\tVmatrix: [\"║\", \"║\", \"║\", \"║\", \"║\", \"║\"],\n\t\t\t};\n\t\t\tconst delimiter = delimiters[environment];\n\t\t\tif (!delimiter) {\n\t\t\t\tthis.supported = false;\n\t\t\t\treturn rows.join(\"\\n\");\n\t\t\t}\n\t\t\tlines = rows.map((row, index) => {\n\t\t\t\tconst left = index === 0 ? delimiter[0] : index === rows.length - 1 ? delimiter[4] : delimiter[2];\n\t\t\t\tconst right = index === 0 ? delimiter[1] : index === rows.length - 1 ? delimiter[5] : delimiter[3];\n\t\t\t\treturn `${left} ${row} ${right}`;\n\t\t\t});\n\t\t}\n\n\t\tif (lines.length <= 1) {\n\t\t\treturn lines[0] ?? \"\";\n\t\t}\n\t\tconst index = this.addLayoutNode({ type: \"matrix\", lines, baseline: 0 });\n\t\treturn index === undefined ? \"\" : `${LAYOUT_MARKER_START}${index}${LAYOUT_MARKER_END}`;\n\t}\n\n\tprivate addLayoutNode(node: LayoutNode): number | undefined {\n\t\tif (this.layoutNodes.length >= MAX_LAYOUT_NODES) {\n\t\t\tthis.supported = false;\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.layoutNodes.push(node) - 1;\n\t}\n\n\tprivate parseNestedSequence(endCharacter: string): string {\n\t\tif (this.state.nestingDepth >= MAX_NESTING_DEPTH) {\n\t\t\tthis.supported = false;\n\t\t\treturn \"\";\n\t\t}\n\t\tthis.state.nestingDepth++;\n\t\ttry {\n\t\t\treturn this.parseSequence(endCharacter);\n\t\t} finally {\n\t\t\tthis.state.nestingDepth--;\n\t\t}\n\t}\n\n\tprivate renderNested(source: string, stackFractions = true): string {\n\t\tif (this.state.nestingDepth >= MAX_NESTING_DEPTH) {\n\t\t\tthis.supported = false;\n\t\t\treturn source;\n\t\t}\n\t\tthis.state.nestingDepth++;\n\t\tlet rendered: string | undefined;\n\t\ttry {\n\t\t\trendered = new LatexParser(source, this.layoutNodes, this.display && stackFractions, this.state).render();\n\t\t} finally {\n\t\t\tthis.state.nestingDepth--;\n\t\t}\n\t\tif (rendered === undefined) {\n\t\t\tthis.supported = false;\n\t\t\treturn source;\n\t\t}\n\t\treturn rendered;\n\t}\n}\n\nexport interface RenderLatexOptions {\n\t/** Stack fractions and operator limits vertically for display math (default: false). */\n\tdisplay?: boolean;\n}\n\n/**\n * Render a basic LaTeX math expression as terminal-friendly Unicode text.\n * Returns undefined when the expression contains unsupported or malformed syntax.\n */\nexport function renderLatex(source: string, options: RenderLatexOptions = {}): string | undefined {\n\tif (source.length > MAX_SOURCE_LENGTH || RESERVED_MARKER_PATTERN.test(source)) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\tconst layoutNodes: LayoutNode[] = [];\n\t\tconst rendered = new LatexParser(source, layoutNodes, options.display === true).render();\n\t\tif (rendered === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet result: string;\n\t\tif (layoutNodes.length === 0) {\n\t\t\tresult = rendered.replaceAll(PROTECTED_SPACE, \" \");\n\t\t} else {\n\t\t\tconst lines = renderLayout(rendered, layoutNodes).lines;\n\t\t\tconst indentation = Math.min(\n\t\t\t\t...lines.filter((line) => line.trim()).map((line) => line.length - line.trimStart().length),\n\t\t\t);\n\t\t\tresult = lines\n\t\t\t\t.map((line) => line.slice(indentation).trimEnd())\n\t\t\t\t.join(\"\\n\")\n\t\t\t\t.trimEnd()\n\t\t\t\t.replaceAll(PROTECTED_SPACE, \" \");\n\t\t}\n\n\t\tconst resultLines = result.split(\"\\n\");\n\t\tif (\n\t\t\tresultLines.length > MAX_RENDERED_ROWS ||\n\t\t\tresultLines.some((line) => visibleWidth(line) > MAX_RENDERED_LINE_WIDTH)\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn result;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}