@fairyhunter13/opentui-core 0.1.114 → 0.1.116

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 (591) hide show
  1. package/3d/SpriteResourceManager.d.ts +74 -0
  2. package/3d/SpriteUtils.d.ts +13 -0
  3. package/3d/TextureUtils.d.ts +24 -0
  4. package/3d/ThreeRenderable.d.ts +40 -0
  5. package/3d/WGPURenderer.d.ts +61 -0
  6. package/3d/animation/ExplodingSpriteEffect.d.ts +71 -0
  7. package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +76 -0
  8. package/3d/animation/SpriteAnimator.d.ts +124 -0
  9. package/3d/animation/SpriteParticleGenerator.d.ts +62 -0
  10. package/3d/canvas.d.ts +44 -0
  11. package/3d/index.d.ts +12 -0
  12. package/3d/physics/PlanckPhysicsAdapter.d.ts +19 -0
  13. package/3d/physics/RapierPhysicsAdapter.d.ts +19 -0
  14. package/3d/physics/physics-interface.d.ts +27 -0
  15. package/3d.d.ts +2 -0
  16. package/3d.js +34041 -0
  17. package/3d.js.map +155 -0
  18. package/LICENSE +21 -0
  19. package/NativeSpanFeed.d.ts +41 -0
  20. package/Renderable.d.ts +334 -0
  21. package/animation/Timeline.d.ts +126 -0
  22. package/ansi.d.ts +13 -0
  23. package/buffer.d.ts +111 -0
  24. package/console.d.ts +144 -0
  25. package/edit-buffer.d.ts +98 -0
  26. package/editor-view.d.ts +73 -0
  27. package/index-dcj62y8t.js +20614 -0
  28. package/index-dcj62y8t.js.map +67 -0
  29. package/index-jyrhjc34.js +411 -0
  30. package/index-jyrhjc34.js.map +10 -0
  31. package/index-wc7ae60z.js +12299 -0
  32. package/index-wc7ae60z.js.map +42 -0
  33. package/index.d.ts +23 -0
  34. package/index.js +478 -0
  35. package/index.js.map +9 -0
  36. package/lib/KeyHandler.d.ts +61 -0
  37. package/lib/RGBA.d.ts +25 -0
  38. package/lib/ascii.font.d.ts +508 -0
  39. package/lib/border.d.ts +51 -0
  40. package/lib/bunfs.d.ts +7 -0
  41. package/lib/clipboard.d.ts +17 -0
  42. package/lib/clock.d.ts +15 -0
  43. package/lib/data-paths.d.ts +26 -0
  44. package/lib/debounce.d.ts +42 -0
  45. package/lib/detect-links.d.ts +6 -0
  46. package/lib/env.d.ts +42 -0
  47. package/lib/extmarks-history.d.ts +17 -0
  48. package/lib/extmarks.d.ts +89 -0
  49. package/lib/hast-styled-text.d.ts +17 -0
  50. package/lib/index.d.ts +21 -0
  51. package/lib/keymapping.d.ts +25 -0
  52. package/lib/objects-in-viewport.d.ts +24 -0
  53. package/lib/output.capture.d.ts +24 -0
  54. package/lib/parse.keypress-kitty.d.ts +2 -0
  55. package/lib/parse.keypress.d.ts +26 -0
  56. package/lib/parse.mouse.d.ts +30 -0
  57. package/lib/paste.d.ts +7 -0
  58. package/lib/queue.d.ts +15 -0
  59. package/lib/renderable.validations.d.ts +12 -0
  60. package/lib/scroll-acceleration.d.ts +43 -0
  61. package/lib/selection.d.ts +63 -0
  62. package/lib/singleton.d.ts +7 -0
  63. package/lib/stdin-parser.d.ts +87 -0
  64. package/lib/styled-text.d.ts +63 -0
  65. package/lib/terminal-capability-detection.d.ts +30 -0
  66. package/lib/terminal-palette.d.ts +50 -0
  67. package/lib/tree-sitter/assets/update.d.ts +11 -0
  68. package/lib/tree-sitter/client.d.ts +47 -0
  69. package/lib/tree-sitter/default-parsers.d.ts +2 -0
  70. package/lib/tree-sitter/download-utils.d.ts +21 -0
  71. package/lib/tree-sitter/index.d.ts +8 -0
  72. package/lib/tree-sitter/parser.worker.d.ts +1 -0
  73. package/lib/tree-sitter/parsers-config.d.ts +53 -0
  74. package/lib/tree-sitter/resolve-ft.d.ts +5 -0
  75. package/lib/tree-sitter/types.d.ts +82 -0
  76. package/lib/tree-sitter-styled-text.d.ts +14 -0
  77. package/lib/validate-dir-name.d.ts +1 -0
  78. package/lib/yoga.options.d.ts +32 -0
  79. package/package.json +53 -62
  80. package/parser.worker.js +899 -0
  81. package/parser.worker.js.map +12 -0
  82. package/plugins/core-slot.d.ts +72 -0
  83. package/plugins/registry.d.ts +42 -0
  84. package/plugins/types.d.ts +34 -0
  85. package/post/effects.d.ts +147 -0
  86. package/post/filters.d.ts +65 -0
  87. package/post/matrices.d.ts +20 -0
  88. package/renderables/ASCIIFont.d.ts +52 -0
  89. package/renderables/Box.d.ts +81 -0
  90. package/renderables/Code.d.ts +78 -0
  91. package/renderables/Diff.d.ts +142 -0
  92. package/renderables/EditBufferRenderable.d.ts +237 -0
  93. package/renderables/FrameBuffer.d.ts +16 -0
  94. package/renderables/Input.d.ts +67 -0
  95. package/renderables/LineNumberRenderable.d.ts +78 -0
  96. package/renderables/Markdown.d.ts +185 -0
  97. package/renderables/ScrollBar.d.ts +77 -0
  98. package/renderables/ScrollBox.d.ts +124 -0
  99. package/renderables/Select.d.ts +115 -0
  100. package/renderables/Slider.d.ts +47 -0
  101. package/renderables/TabSelect.d.ts +96 -0
  102. package/renderables/Text.d.ts +36 -0
  103. package/renderables/TextBufferRenderable.d.ts +105 -0
  104. package/renderables/TextNode.d.ts +91 -0
  105. package/renderables/TextTable.d.ts +140 -0
  106. package/renderables/Textarea.d.ts +63 -0
  107. package/renderables/TimeToFirstDraw.d.ts +24 -0
  108. package/renderables/__tests__/renderable-test-utils.d.ts +12 -0
  109. package/renderables/composition/VRenderable.d.ts +16 -0
  110. package/renderables/composition/constructs.d.ts +35 -0
  111. package/renderables/composition/vnode.d.ts +46 -0
  112. package/renderables/index.d.ts +23 -0
  113. package/renderables/markdown-parser.d.ts +10 -0
  114. package/renderer.d.ts +419 -0
  115. package/runtime-plugin-support.d.ts +3 -0
  116. package/runtime-plugin-support.js +29 -0
  117. package/runtime-plugin-support.js.map +10 -0
  118. package/runtime-plugin.d.ts +16 -0
  119. package/runtime-plugin.js +16 -0
  120. package/runtime-plugin.js.map +9 -0
  121. package/syntax-style.d.ts +54 -0
  122. package/testing/manual-clock.d.ts +17 -0
  123. package/testing/mock-keys.d.ts +81 -0
  124. package/testing/mock-mouse.d.ts +38 -0
  125. package/testing/mock-tree-sitter-client.d.ts +23 -0
  126. package/testing/spy.d.ts +7 -0
  127. package/testing/test-recorder.d.ts +61 -0
  128. package/testing/test-renderer.d.ts +23 -0
  129. package/testing.d.ts +6 -0
  130. package/testing.js +697 -0
  131. package/testing.js.map +15 -0
  132. package/text-buffer-view.d.ts +42 -0
  133. package/text-buffer.d.ts +67 -0
  134. package/types.d.ts +139 -0
  135. package/utils.d.ts +14 -0
  136. package/zig-structs.d.ts +155 -0
  137. package/zig.d.ts +353 -0
  138. package/dev/keypress-debug-renderer.ts +0 -148
  139. package/dev/keypress-debug.ts +0 -43
  140. package/dev/print-env-vars.ts +0 -32
  141. package/dev/test-tmux-graphics-334.sh +0 -68
  142. package/dev/thai-debug-test.ts +0 -68
  143. package/docs/development.md +0 -144
  144. package/scripts/build.ts +0 -400
  145. package/scripts/publish.ts +0 -60
  146. package/src/3d/SpriteResourceManager.ts +0 -286
  147. package/src/3d/SpriteUtils.ts +0 -70
  148. package/src/3d/TextureUtils.ts +0 -196
  149. package/src/3d/ThreeRenderable.ts +0 -197
  150. package/src/3d/WGPURenderer.ts +0 -294
  151. package/src/3d/animation/ExplodingSpriteEffect.ts +0 -513
  152. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +0 -429
  153. package/src/3d/animation/SpriteAnimator.ts +0 -633
  154. package/src/3d/animation/SpriteParticleGenerator.ts +0 -435
  155. package/src/3d/canvas.ts +0 -464
  156. package/src/3d/index.ts +0 -12
  157. package/src/3d/physics/PlanckPhysicsAdapter.ts +0 -72
  158. package/src/3d/physics/RapierPhysicsAdapter.ts +0 -66
  159. package/src/3d/physics/physics-interface.ts +0 -31
  160. package/src/3d/shaders/supersampling.wgsl +0 -201
  161. package/src/3d.ts +0 -3
  162. package/src/NativeSpanFeed.ts +0 -300
  163. package/src/Renderable.ts +0 -1704
  164. package/src/__snapshots__/buffer.test.ts.snap +0 -28
  165. package/src/animation/Timeline.test.ts +0 -2709
  166. package/src/animation/Timeline.ts +0 -598
  167. package/src/ansi.ts +0 -18
  168. package/src/benchmark/attenuation-benchmark.ts +0 -81
  169. package/src/benchmark/colormatrix-benchmark.ts +0 -128
  170. package/src/benchmark/gain-benchmark.ts +0 -80
  171. package/src/benchmark/latest-all-bench-run.json +0 -707
  172. package/src/benchmark/latest-async-bench-run.json +0 -336
  173. package/src/benchmark/latest-default-bench-run.json +0 -657
  174. package/src/benchmark/latest-large-bench-run.json +0 -707
  175. package/src/benchmark/latest-quick-bench-run.json +0 -207
  176. package/src/benchmark/markdown-benchmark.ts +0 -1796
  177. package/src/benchmark/native-span-feed-async-benchmark.ts +0 -355
  178. package/src/benchmark/native-span-feed-benchmark.md +0 -56
  179. package/src/benchmark/native-span-feed-benchmark.ts +0 -596
  180. package/src/benchmark/native-span-feed-compare.ts +0 -280
  181. package/src/benchmark/renderer-benchmark.ts +0 -754
  182. package/src/benchmark/text-table-benchmark.ts +0 -948
  183. package/src/buffer.test.ts +0 -291
  184. package/src/buffer.ts +0 -554
  185. package/src/console.test.ts +0 -612
  186. package/src/console.ts +0 -1254
  187. package/src/edit-buffer.test.ts +0 -1769
  188. package/src/edit-buffer.ts +0 -411
  189. package/src/editor-view.test.ts +0 -1032
  190. package/src/editor-view.ts +0 -284
  191. package/src/examples/ascii-font-selection-demo.ts +0 -245
  192. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  193. package/src/examples/assets/concrete.png +0 -0
  194. package/src/examples/assets/crate.png +0 -0
  195. package/src/examples/assets/crate_emissive.png +0 -0
  196. package/src/examples/assets/forrest_background.png +0 -0
  197. package/src/examples/assets/hast-example.json +0 -1018
  198. package/src/examples/assets/heart.png +0 -0
  199. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  200. package/src/examples/assets/main_char_idle.png +0 -0
  201. package/src/examples/assets/main_char_jump_end.png +0 -0
  202. package/src/examples/assets/main_char_jump_landing.png +0 -0
  203. package/src/examples/assets/main_char_jump_start.png +0 -0
  204. package/src/examples/assets/main_char_run_loop.png +0 -0
  205. package/src/examples/assets/roughness_map.jpg +0 -0
  206. package/src/examples/build.ts +0 -115
  207. package/src/examples/code-demo.ts +0 -924
  208. package/src/examples/console-demo.ts +0 -358
  209. package/src/examples/core-plugin-slots-demo.ts +0 -759
  210. package/src/examples/diff-demo.ts +0 -701
  211. package/src/examples/draggable-three-demo.ts +0 -259
  212. package/src/examples/editor-demo.ts +0 -322
  213. package/src/examples/extmarks-demo.ts +0 -196
  214. package/src/examples/focus-restore-demo.ts +0 -310
  215. package/src/examples/fonts.ts +0 -245
  216. package/src/examples/fractal-shader-demo.ts +0 -268
  217. package/src/examples/framebuffer-demo.ts +0 -674
  218. package/src/examples/full-unicode-demo.ts +0 -241
  219. package/src/examples/golden-star-demo.ts +0 -933
  220. package/src/examples/grayscale-buffer-demo.ts +0 -249
  221. package/src/examples/hast-syntax-highlighting-demo.ts +0 -129
  222. package/src/examples/index.ts +0 -926
  223. package/src/examples/input-demo.ts +0 -377
  224. package/src/examples/input-select-layout-demo.ts +0 -425
  225. package/src/examples/install.sh +0 -143
  226. package/src/examples/keypress-debug-demo.ts +0 -452
  227. package/src/examples/lib/HexList.ts +0 -122
  228. package/src/examples/lib/PaletteGrid.ts +0 -125
  229. package/src/examples/lib/standalone-keys.ts +0 -25
  230. package/src/examples/lib/tab-controller.ts +0 -243
  231. package/src/examples/lights-phong-demo.ts +0 -290
  232. package/src/examples/link-demo.ts +0 -220
  233. package/src/examples/live-state-demo.ts +0 -480
  234. package/src/examples/markdown-demo.ts +0 -725
  235. package/src/examples/mouse-interaction-demo.ts +0 -428
  236. package/src/examples/nested-zindex-demo.ts +0 -357
  237. package/src/examples/opacity-example.ts +0 -235
  238. package/src/examples/opentui-demo.ts +0 -1057
  239. package/src/examples/physx-planck-2d-demo.ts +0 -623
  240. package/src/examples/physx-rapier-2d-demo.ts +0 -655
  241. package/src/examples/relative-positioning-demo.ts +0 -323
  242. package/src/examples/scroll-example.ts +0 -214
  243. package/src/examples/scrollbox-mouse-test.ts +0 -112
  244. package/src/examples/scrollbox-overlay-hit-test.ts +0 -206
  245. package/src/examples/select-demo.ts +0 -237
  246. package/src/examples/shader-cube-demo.ts +0 -1015
  247. package/src/examples/simple-layout-example.ts +0 -591
  248. package/src/examples/slider-demo.ts +0 -617
  249. package/src/examples/split-mode-demo.ts +0 -453
  250. package/src/examples/sprite-animation-demo.ts +0 -443
  251. package/src/examples/sprite-particle-generator-demo.ts +0 -486
  252. package/src/examples/static-sprite-demo.ts +0 -193
  253. package/src/examples/sticky-scroll-example.ts +0 -308
  254. package/src/examples/styled-text-demo.ts +0 -282
  255. package/src/examples/tab-select-demo.ts +0 -219
  256. package/src/examples/terminal-title.ts +0 -29
  257. package/src/examples/terminal.ts +0 -305
  258. package/src/examples/text-node-demo.ts +0 -416
  259. package/src/examples/text-selection-demo.ts +0 -377
  260. package/src/examples/text-table-demo.ts +0 -503
  261. package/src/examples/text-truncation-demo.ts +0 -481
  262. package/src/examples/text-wrap.ts +0 -757
  263. package/src/examples/texture-loading-demo.ts +0 -259
  264. package/src/examples/timeline-example.ts +0 -670
  265. package/src/examples/transparency-demo.ts +0 -400
  266. package/src/examples/vnode-composition-demo.ts +0 -404
  267. package/src/examples/wide-grapheme-overlay-demo.ts +0 -280
  268. package/src/index.ts +0 -24
  269. package/src/lib/KeyHandler.integration.test.ts +0 -292
  270. package/src/lib/KeyHandler.stopPropagation.test.ts +0 -289
  271. package/src/lib/KeyHandler.test.ts +0 -662
  272. package/src/lib/KeyHandler.ts +0 -222
  273. package/src/lib/RGBA.test.ts +0 -984
  274. package/src/lib/RGBA.ts +0 -204
  275. package/src/lib/ascii.font.ts +0 -330
  276. package/src/lib/border.test.ts +0 -83
  277. package/src/lib/border.ts +0 -170
  278. package/src/lib/bunfs.test.ts +0 -27
  279. package/src/lib/bunfs.ts +0 -18
  280. package/src/lib/clipboard.test.ts +0 -41
  281. package/src/lib/clipboard.ts +0 -47
  282. package/src/lib/clock.ts +0 -35
  283. package/src/lib/data-paths.test.ts +0 -133
  284. package/src/lib/data-paths.ts +0 -109
  285. package/src/lib/debounce.ts +0 -106
  286. package/src/lib/detect-links.test.ts +0 -98
  287. package/src/lib/detect-links.ts +0 -56
  288. package/src/lib/env.test.ts +0 -228
  289. package/src/lib/env.ts +0 -209
  290. package/src/lib/extmarks-history.ts +0 -51
  291. package/src/lib/extmarks-multiwidth.test.ts +0 -322
  292. package/src/lib/extmarks.test.ts +0 -3457
  293. package/src/lib/extmarks.ts +0 -843
  294. package/src/lib/fonts/block.json +0 -405
  295. package/src/lib/fonts/grid.json +0 -265
  296. package/src/lib/fonts/huge.json +0 -741
  297. package/src/lib/fonts/pallet.json +0 -314
  298. package/src/lib/fonts/shade.json +0 -591
  299. package/src/lib/fonts/slick.json +0 -321
  300. package/src/lib/fonts/tiny.json +0 -69
  301. package/src/lib/hast-styled-text.ts +0 -59
  302. package/src/lib/index.ts +0 -21
  303. package/src/lib/keymapping.test.ts +0 -317
  304. package/src/lib/keymapping.ts +0 -115
  305. package/src/lib/objects-in-viewport.test.ts +0 -787
  306. package/src/lib/objects-in-viewport.ts +0 -153
  307. package/src/lib/output.capture.ts +0 -58
  308. package/src/lib/parse.keypress-kitty.protocol.test.ts +0 -340
  309. package/src/lib/parse.keypress-kitty.test.ts +0 -663
  310. package/src/lib/parse.keypress-kitty.ts +0 -439
  311. package/src/lib/parse.keypress.test.ts +0 -1849
  312. package/src/lib/parse.keypress.ts +0 -397
  313. package/src/lib/parse.mouse.test.ts +0 -552
  314. package/src/lib/parse.mouse.ts +0 -232
  315. package/src/lib/paste.ts +0 -16
  316. package/src/lib/queue.ts +0 -65
  317. package/src/lib/renderable.validations.test.ts +0 -87
  318. package/src/lib/renderable.validations.ts +0 -83
  319. package/src/lib/scroll-acceleration.ts +0 -98
  320. package/src/lib/selection.ts +0 -240
  321. package/src/lib/singleton.ts +0 -28
  322. package/src/lib/stdin-parser.test.ts +0 -2290
  323. package/src/lib/stdin-parser.ts +0 -1810
  324. package/src/lib/styled-text.ts +0 -178
  325. package/src/lib/terminal-capability-detection.test.ts +0 -202
  326. package/src/lib/terminal-capability-detection.ts +0 -79
  327. package/src/lib/terminal-palette.test.ts +0 -878
  328. package/src/lib/terminal-palette.ts +0 -383
  329. package/src/lib/tree-sitter/assets/README.md +0 -118
  330. package/src/lib/tree-sitter/assets/update.ts +0 -334
  331. package/src/lib/tree-sitter/assets.d.ts +0 -9
  332. package/src/lib/tree-sitter/cache.test.ts +0 -273
  333. package/src/lib/tree-sitter/client.test.ts +0 -1165
  334. package/src/lib/tree-sitter/client.ts +0 -607
  335. package/src/lib/tree-sitter/default-parsers.ts +0 -86
  336. package/src/lib/tree-sitter/download-utils.ts +0 -148
  337. package/src/lib/tree-sitter/index.ts +0 -28
  338. package/src/lib/tree-sitter/parser.worker.ts +0 -1042
  339. package/src/lib/tree-sitter/parsers-config.ts +0 -81
  340. package/src/lib/tree-sitter/resolve-ft.test.ts +0 -55
  341. package/src/lib/tree-sitter/resolve-ft.ts +0 -189
  342. package/src/lib/tree-sitter/types.ts +0 -82
  343. package/src/lib/tree-sitter-styled-text.test.ts +0 -1253
  344. package/src/lib/tree-sitter-styled-text.ts +0 -306
  345. package/src/lib/validate-dir-name.ts +0 -55
  346. package/src/lib/yoga.options.test.ts +0 -628
  347. package/src/lib/yoga.options.ts +0 -346
  348. package/src/plugins/core-slot.ts +0 -579
  349. package/src/plugins/registry.ts +0 -402
  350. package/src/plugins/types.ts +0 -46
  351. package/src/post/effects.ts +0 -930
  352. package/src/post/filters.ts +0 -489
  353. package/src/post/matrices.ts +0 -288
  354. package/src/renderables/ASCIIFont.ts +0 -219
  355. package/src/renderables/Box.test.ts +0 -205
  356. package/src/renderables/Box.ts +0 -326
  357. package/src/renderables/Code.test.ts +0 -2062
  358. package/src/renderables/Code.ts +0 -357
  359. package/src/renderables/Diff.regression.test.ts +0 -226
  360. package/src/renderables/Diff.test.ts +0 -3101
  361. package/src/renderables/Diff.ts +0 -1211
  362. package/src/renderables/EditBufferRenderable.test.ts +0 -288
  363. package/src/renderables/EditBufferRenderable.ts +0 -1166
  364. package/src/renderables/FrameBuffer.ts +0 -47
  365. package/src/renderables/Input.test.ts +0 -1228
  366. package/src/renderables/Input.ts +0 -247
  367. package/src/renderables/LineNumberRenderable.ts +0 -724
  368. package/src/renderables/Markdown.ts +0 -1393
  369. package/src/renderables/ScrollBar.ts +0 -422
  370. package/src/renderables/ScrollBox.ts +0 -883
  371. package/src/renderables/Select.test.ts +0 -1033
  372. package/src/renderables/Select.ts +0 -524
  373. package/src/renderables/Slider.test.ts +0 -456
  374. package/src/renderables/Slider.ts +0 -342
  375. package/src/renderables/TabSelect.test.ts +0 -197
  376. package/src/renderables/TabSelect.ts +0 -455
  377. package/src/renderables/Text.selection-buffer.test.ts +0 -123
  378. package/src/renderables/Text.test.ts +0 -2660
  379. package/src/renderables/Text.ts +0 -147
  380. package/src/renderables/TextBufferRenderable.ts +0 -518
  381. package/src/renderables/TextNode.test.ts +0 -1058
  382. package/src/renderables/TextNode.ts +0 -325
  383. package/src/renderables/TextTable.test.ts +0 -1421
  384. package/src/renderables/TextTable.ts +0 -1344
  385. package/src/renderables/Textarea.ts +0 -430
  386. package/src/renderables/TimeToFirstDraw.ts +0 -89
  387. package/src/renderables/__snapshots__/Code.test.ts.snap +0 -13
  388. package/src/renderables/__snapshots__/Diff.test.ts.snap +0 -785
  389. package/src/renderables/__snapshots__/Text.test.ts.snap +0 -421
  390. package/src/renderables/__snapshots__/TextTable.test.ts.snap +0 -215
  391. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +0 -144
  392. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +0 -816
  393. package/src/renderables/__tests__/LineNumberRenderable.test.ts +0 -1865
  394. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +0 -85
  395. package/src/renderables/__tests__/Markdown.code-colors.test.ts +0 -242
  396. package/src/renderables/__tests__/Markdown.test.ts +0 -2518
  397. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +0 -87
  398. package/src/renderables/__tests__/Textarea.buffer.test.ts +0 -682
  399. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +0 -675
  400. package/src/renderables/__tests__/Textarea.editing.test.ts +0 -2041
  401. package/src/renderables/__tests__/Textarea.error-handling.test.ts +0 -35
  402. package/src/renderables/__tests__/Textarea.events.test.ts +0 -738
  403. package/src/renderables/__tests__/Textarea.highlights.test.ts +0 -590
  404. package/src/renderables/__tests__/Textarea.keybinding.test.ts +0 -3149
  405. package/src/renderables/__tests__/Textarea.paste.test.ts +0 -357
  406. package/src/renderables/__tests__/Textarea.rendering.test.ts +0 -1866
  407. package/src/renderables/__tests__/Textarea.scroll.test.ts +0 -733
  408. package/src/renderables/__tests__/Textarea.selection.test.ts +0 -1590
  409. package/src/renderables/__tests__/Textarea.stress.test.ts +0 -670
  410. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +0 -383
  411. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +0 -310
  412. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +0 -221
  413. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +0 -89
  414. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +0 -457
  415. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +0 -158
  416. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +0 -387
  417. package/src/renderables/__tests__/markdown-parser.test.ts +0 -217
  418. package/src/renderables/__tests__/renderable-test-utils.ts +0 -60
  419. package/src/renderables/composition/README.md +0 -8
  420. package/src/renderables/composition/VRenderable.ts +0 -32
  421. package/src/renderables/composition/constructs.ts +0 -127
  422. package/src/renderables/composition/vnode.ts +0 -289
  423. package/src/renderables/index.ts +0 -23
  424. package/src/renderables/markdown-parser.ts +0 -66
  425. package/src/renderer.ts +0 -2681
  426. package/src/runtime-plugin-support.ts +0 -39
  427. package/src/runtime-plugin.ts +0 -615
  428. package/src/syntax-style.test.ts +0 -841
  429. package/src/syntax-style.ts +0 -257
  430. package/src/testing/README.md +0 -210
  431. package/src/testing/capture-spans.test.ts +0 -194
  432. package/src/testing/integration.test.ts +0 -276
  433. package/src/testing/manual-clock.ts +0 -117
  434. package/src/testing/mock-keys.test.ts +0 -1378
  435. package/src/testing/mock-keys.ts +0 -457
  436. package/src/testing/mock-mouse.test.ts +0 -218
  437. package/src/testing/mock-mouse.ts +0 -247
  438. package/src/testing/mock-tree-sitter-client.ts +0 -73
  439. package/src/testing/spy.ts +0 -13
  440. package/src/testing/test-recorder.test.ts +0 -415
  441. package/src/testing/test-recorder.ts +0 -145
  442. package/src/testing/test-renderer.ts +0 -132
  443. package/src/testing.ts +0 -7
  444. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +0 -481
  445. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +0 -19
  446. package/src/tests/__snapshots__/scrollbox.test.ts.snap +0 -29
  447. package/src/tests/absolute-positioning.snapshot.test.ts +0 -638
  448. package/src/tests/allocator-stats.test.ts +0 -38
  449. package/src/tests/destroy-during-render.test.ts +0 -200
  450. package/src/tests/destroy-on-exit.fixture.ts +0 -36
  451. package/src/tests/destroy-on-exit.test.ts +0 -41
  452. package/src/tests/hover-cursor.test.ts +0 -98
  453. package/src/tests/native-span-feed-async.test.ts +0 -173
  454. package/src/tests/native-span-feed-close.test.ts +0 -120
  455. package/src/tests/native-span-feed-coverage.test.ts +0 -227
  456. package/src/tests/native-span-feed-edge-cases.test.ts +0 -352
  457. package/src/tests/native-span-feed-use-after-free.test.ts +0 -45
  458. package/src/tests/opacity.test.ts +0 -123
  459. package/src/tests/renderable.snapshot.test.ts +0 -524
  460. package/src/tests/renderable.test.ts +0 -1281
  461. package/src/tests/renderer.clock.test.ts +0 -158
  462. package/src/tests/renderer.console-startup.test.ts +0 -185
  463. package/src/tests/renderer.control.test.ts +0 -425
  464. package/src/tests/renderer.core-slot-binding.test.ts +0 -952
  465. package/src/tests/renderer.cursor.test.ts +0 -26
  466. package/src/tests/renderer.destroy-during-render.test.ts +0 -147
  467. package/src/tests/renderer.focus-restore.test.ts +0 -257
  468. package/src/tests/renderer.focus.test.ts +0 -294
  469. package/src/tests/renderer.idle.test.ts +0 -219
  470. package/src/tests/renderer.input.test.ts +0 -2237
  471. package/src/tests/renderer.kitty-flags.test.ts +0 -195
  472. package/src/tests/renderer.mouse.test.ts +0 -1274
  473. package/src/tests/renderer.palette.test.ts +0 -629
  474. package/src/tests/renderer.selection.test.ts +0 -49
  475. package/src/tests/renderer.slot-registry.test.ts +0 -684
  476. package/src/tests/renderer.useMouse.test.ts +0 -47
  477. package/src/tests/runtime-plugin-node-modules-cycle.fixture.ts +0 -76
  478. package/src/tests/runtime-plugin-node-modules-mjs.fixture.ts +0 -43
  479. package/src/tests/runtime-plugin-node-modules-no-bare-rewrite.fixture.ts +0 -67
  480. package/src/tests/runtime-plugin-node-modules-package-type-cache.fixture.ts +0 -72
  481. package/src/tests/runtime-plugin-node-modules-runtime-specifier.fixture.ts +0 -44
  482. package/src/tests/runtime-plugin-node-modules-scoped-package-bare-rewrite.fixture.ts +0 -85
  483. package/src/tests/runtime-plugin-path-alias.fixture.ts +0 -43
  484. package/src/tests/runtime-plugin-resolve-roots.fixture.ts +0 -65
  485. package/src/tests/runtime-plugin-support.fixture.ts +0 -11
  486. package/src/tests/runtime-plugin-support.test.ts +0 -19
  487. package/src/tests/runtime-plugin-windows-file-url.fixture.ts +0 -30
  488. package/src/tests/runtime-plugin.fixture.ts +0 -40
  489. package/src/tests/runtime-plugin.test.ts +0 -354
  490. package/src/tests/scrollbox-culling-bug.test.ts +0 -114
  491. package/src/tests/scrollbox-hitgrid-resize.test.ts +0 -136
  492. package/src/tests/scrollbox-hitgrid.test.ts +0 -909
  493. package/src/tests/scrollbox.test.ts +0 -1530
  494. package/src/tests/wrap-resize-perf.test.ts +0 -276
  495. package/src/tests/yoga-setters.test.ts +0 -921
  496. package/src/text-buffer-view.test.ts +0 -705
  497. package/src/text-buffer-view.ts +0 -189
  498. package/src/text-buffer.test.ts +0 -347
  499. package/src/text-buffer.ts +0 -250
  500. package/src/types.ts +0 -161
  501. package/src/utils.ts +0 -88
  502. package/src/zig/ansi.zig +0 -268
  503. package/src/zig/bench/README.md +0 -50
  504. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +0 -887
  505. package/src/zig/bench/edit-buffer_bench.zig +0 -476
  506. package/src/zig/bench/native-span-feed_bench.zig +0 -100
  507. package/src/zig/bench/rope-markers_bench.zig +0 -713
  508. package/src/zig/bench/rope_bench.zig +0 -514
  509. package/src/zig/bench/styled-text_bench.zig +0 -470
  510. package/src/zig/bench/text-buffer-coords_bench.zig +0 -362
  511. package/src/zig/bench/text-buffer-view_bench.zig +0 -459
  512. package/src/zig/bench/text-chunk-graphemes_bench.zig +0 -273
  513. package/src/zig/bench/utf8_bench.zig +0 -799
  514. package/src/zig/bench-utils.zig +0 -431
  515. package/src/zig/bench.zig +0 -217
  516. package/src/zig/buffer-methods.zig +0 -211
  517. package/src/zig/buffer.zig +0 -2281
  518. package/src/zig/build.zig +0 -289
  519. package/src/zig/build.zig.zon +0 -16
  520. package/src/zig/edit-buffer.zig +0 -825
  521. package/src/zig/editor-view.zig +0 -802
  522. package/src/zig/event-bus.zig +0 -13
  523. package/src/zig/event-emitter.zig +0 -65
  524. package/src/zig/file-logger.zig +0 -92
  525. package/src/zig/grapheme.zig +0 -599
  526. package/src/zig/lib.zig +0 -1854
  527. package/src/zig/link.zig +0 -333
  528. package/src/zig/logger.zig +0 -43
  529. package/src/zig/mem-registry.zig +0 -125
  530. package/src/zig/native-span-feed-bench-lib.zig +0 -7
  531. package/src/zig/native-span-feed.zig +0 -708
  532. package/src/zig/renderer.zig +0 -1393
  533. package/src/zig/rope.zig +0 -1220
  534. package/src/zig/syntax-style.zig +0 -161
  535. package/src/zig/terminal.zig +0 -987
  536. package/src/zig/test.zig +0 -72
  537. package/src/zig/tests/README.md +0 -18
  538. package/src/zig/tests/buffer-methods_test.zig +0 -1109
  539. package/src/zig/tests/buffer_test.zig +0 -2557
  540. package/src/zig/tests/edit-buffer-history_test.zig +0 -271
  541. package/src/zig/tests/edit-buffer_test.zig +0 -1689
  542. package/src/zig/tests/editor-view_test.zig +0 -3299
  543. package/src/zig/tests/event-emitter_test.zig +0 -249
  544. package/src/zig/tests/grapheme_test.zig +0 -1304
  545. package/src/zig/tests/link_test.zig +0 -190
  546. package/src/zig/tests/mem-registry_test.zig +0 -473
  547. package/src/zig/tests/memory_leak_regression_test.zig +0 -159
  548. package/src/zig/tests/native-span-feed_test.zig +0 -1264
  549. package/src/zig/tests/renderer_test.zig +0 -1017
  550. package/src/zig/tests/rope-nested_test.zig +0 -712
  551. package/src/zig/tests/rope_fuzz_test.zig +0 -238
  552. package/src/zig/tests/rope_test.zig +0 -2362
  553. package/src/zig/tests/segment-merge.test.zig +0 -148
  554. package/src/zig/tests/syntax-style_test.zig +0 -557
  555. package/src/zig/tests/terminal_test.zig +0 -754
  556. package/src/zig/tests/text-buffer-drawing_test.zig +0 -3237
  557. package/src/zig/tests/text-buffer-highlights_test.zig +0 -666
  558. package/src/zig/tests/text-buffer-iterators_test.zig +0 -776
  559. package/src/zig/tests/text-buffer-segment_test.zig +0 -320
  560. package/src/zig/tests/text-buffer-selection_test.zig +0 -1035
  561. package/src/zig/tests/text-buffer-selection_viewport_test.zig +0 -358
  562. package/src/zig/tests/text-buffer-view_test.zig +0 -3649
  563. package/src/zig/tests/text-buffer_test.zig +0 -2191
  564. package/src/zig/tests/unicode-width-map.zon +0 -3909
  565. package/src/zig/tests/utf8_no_zwj_test.zig +0 -260
  566. package/src/zig/tests/utf8_test.zig +0 -4057
  567. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +0 -267
  568. package/src/zig/tests/utf8_wcwidth_test.zig +0 -357
  569. package/src/zig/tests/word-wrap-editing_test.zig +0 -498
  570. package/src/zig/tests/wrap-cache-perf_test.zig +0 -113
  571. package/src/zig/text-buffer-iterators.zig +0 -499
  572. package/src/zig/text-buffer-segment.zig +0 -404
  573. package/src/zig/text-buffer-view.zig +0 -1371
  574. package/src/zig/text-buffer.zig +0 -1180
  575. package/src/zig/utf8.zig +0 -1948
  576. package/src/zig/utils.zig +0 -9
  577. package/src/zig-structs.ts +0 -261
  578. package/src/zig.ts +0 -3884
  579. package/tsconfig.build.json +0 -24
  580. package/tsconfig.json +0 -27
  581. /package/{src/lib/tree-sitter/assets → assets}/javascript/highlights.scm +0 -0
  582. /package/{src/lib/tree-sitter/assets → assets}/javascript/tree-sitter-javascript.wasm +0 -0
  583. /package/{src/lib/tree-sitter/assets → assets}/markdown/highlights.scm +0 -0
  584. /package/{src/lib/tree-sitter/assets → assets}/markdown/injections.scm +0 -0
  585. /package/{src/lib/tree-sitter/assets → assets}/markdown/tree-sitter-markdown.wasm +0 -0
  586. /package/{src/lib/tree-sitter/assets → assets}/markdown_inline/highlights.scm +0 -0
  587. /package/{src/lib/tree-sitter/assets → assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  588. /package/{src/lib/tree-sitter/assets → assets}/typescript/highlights.scm +0 -0
  589. /package/{src/lib/tree-sitter/assets → assets}/typescript/tree-sitter-typescript.wasm +0 -0
  590. /package/{src/lib/tree-sitter/assets → assets}/zig/highlights.scm +0 -0
  591. /package/{src/lib/tree-sitter/assets → assets}/zig/tree-sitter-zig.wasm +0 -0
@@ -1,1393 +0,0 @@
1
- import { Renderable, type RenderableOptions } from "../Renderable.js"
2
- import { type RenderContext } from "../types.js"
3
- import { SyntaxStyle, type StyleDefinition } from "../syntax-style.js"
4
- import type { TextChunk } from "../text-buffer.js"
5
- import { createTextAttributes } from "../utils.js"
6
- import type { BorderStyle } from "../lib/border.js"
7
- import { RGBA, parseColor, type ColorInput } from "../lib/RGBA.js"
8
- import { type MarkedToken, type Token, type Tokens } from "marked"
9
- import { CodeRenderable, type OnChunksCallback } from "./Code.js"
10
- import {
11
- TextTableRenderable,
12
- type TextTableCellContent,
13
- type TextTableColumnFitter,
14
- type TextTableColumnWidthMode,
15
- type TextTableContent,
16
- } from "./TextTable.js"
17
- import type { TreeSitterClient } from "../lib/tree-sitter/index.js"
18
- import { infoStringToFiletype } from "../lib/tree-sitter/resolve-ft.js"
19
- import { parseMarkdownIncremental, type ParseState } from "./markdown-parser.js"
20
- import type { OptimizedBuffer } from "../buffer.js"
21
- import { detectLinks } from "../lib/detect-links.js"
22
-
23
- export interface MarkdownTableOptions {
24
- /**
25
- * Strategy for sizing table columns.
26
- * - "content": columns fit to intrinsic content width.
27
- * - "full": columns expand to fill available width.
28
- */
29
- widthMode?: TextTableColumnWidthMode
30
- /**
31
- * Column fitting method when shrinking constrained tables.
32
- */
33
- columnFitter?: TextTableColumnFitter
34
- /**
35
- * Wrapping strategy for table cell content.
36
- */
37
- wrapMode?: "none" | "char" | "word"
38
- /**
39
- * Padding applied on all sides of each table cell.
40
- */
41
- cellPadding?: number
42
- /**
43
- * Enables/disables table border rendering.
44
- */
45
- borders?: boolean
46
- /**
47
- * Overrides outer border visibility. Defaults to `borders`.
48
- */
49
- outerBorder?: boolean
50
- /**
51
- * Border style for markdown tables.
52
- */
53
- borderStyle?: BorderStyle
54
- /**
55
- * Border color for markdown tables. Defaults to conceal style color.
56
- */
57
- borderColor?: ColorInput
58
- /**
59
- * Enables/disables selection support on markdown tables.
60
- */
61
- selectable?: boolean
62
- }
63
-
64
- export interface MarkdownOptions extends RenderableOptions<MarkdownRenderable> {
65
- content?: string
66
- syntaxStyle: SyntaxStyle
67
- fg?: ColorInput
68
- bg?: ColorInput
69
- /** Controls concealment for markdown syntax markers in markdown text blocks. */
70
- conceal?: boolean
71
- /** Controls concealment inside fenced code blocks rendered by CodeRenderable. */
72
- concealCode?: boolean
73
- treeSitterClient?: TreeSitterClient
74
- /**
75
- * Enable streaming mode for incremental content updates.
76
- *
77
- * Semantics:
78
- * - The trailing markdown block stays unstable while streaming is enabled.
79
- * - Tables render all rows produced by the markdown parser (including trailing rows).
80
- * - Incomplete table rows are normalized by the parser and rendered with empty cells
81
- * where data is missing.
82
- *
83
- * Expectations:
84
- * - Keep this true while chunks are still being appended.
85
- * - Set this to false once streaming is complete to finalize trailing token parsing.
86
- */
87
- streaming?: boolean
88
- /**
89
- * Options for internally rendered markdown tables.
90
- */
91
- tableOptions?: MarkdownTableOptions
92
- /**
93
- * Custom node renderer. Return a Renderable to override default rendering,
94
- * or undefined/null to use default rendering.
95
- */
96
- renderNode?: (token: Token, context: RenderNodeContext) => Renderable | undefined | null
97
- }
98
-
99
- export interface RenderNodeContext {
100
- syntaxStyle: SyntaxStyle
101
- conceal: boolean
102
- concealCode: boolean
103
- treeSitterClient?: TreeSitterClient
104
- /** Creates default renderable for this token */
105
- defaultRender: () => Renderable | null
106
- }
107
-
108
- interface TableContentCache {
109
- content: TextTableContent
110
- cellKeys: Uint32Array[]
111
- }
112
-
113
- interface ResolvedTableRenderableOptions {
114
- columnWidthMode: TextTableColumnWidthMode
115
- columnFitter: TextTableColumnFitter
116
- wrapMode: "none" | "char" | "word"
117
- cellPadding: number
118
- border: boolean
119
- outerBorder: boolean
120
- showBorders: boolean
121
- borderStyle: BorderStyle
122
- borderColor: ColorInput
123
- selectable: boolean
124
- }
125
-
126
- const TRAILING_MARKDOWN_BLOCK_BREAKS_RE = /(?:\r?\n)+$/
127
-
128
- function colorsEqual(left?: RGBA, right?: RGBA): boolean {
129
- if (!left || !right) return left === right
130
- return left.equals(right)
131
- }
132
-
133
- export interface BlockState {
134
- token: MarkedToken
135
- tokenRaw: string // Cache raw for comparison
136
- renderable: Renderable
137
- tableContentCache?: TableContentCache
138
- }
139
-
140
- export type { ParseState }
141
-
142
- export class MarkdownRenderable extends Renderable {
143
- private _content: string = ""
144
- private _syntaxStyle: SyntaxStyle
145
- private _fg?: RGBA
146
- private _bg?: RGBA
147
- private _conceal: boolean
148
- private _concealCode: boolean
149
- private _treeSitterClient?: TreeSitterClient
150
- private _tableOptions?: MarkdownTableOptions
151
- private _renderNode?: MarkdownOptions["renderNode"]
152
-
153
- _parseState: ParseState | null = null
154
- private _streaming: boolean = false
155
- _blockStates: BlockState[] = []
156
- private _styleDirty: boolean = false
157
- private _linkifyMarkdownChunks: OnChunksCallback = (chunks, context) =>
158
- detectLinks(chunks, {
159
- content: context.content,
160
- highlights: context.highlights,
161
- })
162
-
163
- private _inlineConcealChunks: OnChunksCallback = (chunks, context) => {
164
- return this.buildInlineConcealChunks(chunks, context)
165
- }
166
-
167
- protected _contentDefaultOptions = {
168
- content: "",
169
- conceal: true,
170
- concealCode: false,
171
- streaming: false,
172
- } satisfies Partial<MarkdownOptions>
173
-
174
- constructor(ctx: RenderContext, options: MarkdownOptions) {
175
- super(ctx, {
176
- ...options,
177
- flexDirection: "column",
178
- flexShrink: options.flexShrink ?? 0,
179
- })
180
-
181
- this._syntaxStyle = options.syntaxStyle
182
- this._fg = options.fg ? parseColor(options.fg) : undefined
183
- this._bg = options.bg ? parseColor(options.bg) : undefined
184
- this._conceal = options.conceal ?? this._contentDefaultOptions.conceal
185
- this._concealCode = options.concealCode ?? this._contentDefaultOptions.concealCode
186
- this._content = options.content ?? this._contentDefaultOptions.content
187
- this._treeSitterClient = options.treeSitterClient
188
- this._tableOptions = options.tableOptions
189
- this._renderNode = options.renderNode
190
- this._streaming = options.streaming ?? this._contentDefaultOptions.streaming
191
-
192
- this.updateBlocks()
193
- }
194
-
195
- get content(): string {
196
- return this._content
197
- }
198
-
199
- set content(value: string) {
200
- if (this.isDestroyed) return
201
- if (this._content !== value) {
202
- this._content = value
203
- this.updateBlocks()
204
- this.requestRender()
205
- }
206
- }
207
-
208
- get syntaxStyle(): SyntaxStyle {
209
- return this._syntaxStyle
210
- }
211
-
212
- set syntaxStyle(value: SyntaxStyle) {
213
- if (this._syntaxStyle !== value) {
214
- this._syntaxStyle = value
215
- // Mark dirty - actual re-render happens in renderSelf
216
- this._styleDirty = true
217
- }
218
- }
219
-
220
- get fg(): RGBA | undefined {
221
- return this._fg
222
- }
223
-
224
- set fg(value: ColorInput | undefined) {
225
- const next = value ? parseColor(value) : undefined
226
- if (!colorsEqual(this._fg, next)) {
227
- this._fg = next
228
- this._styleDirty = true
229
- }
230
- }
231
-
232
- get bg(): RGBA | undefined {
233
- return this._bg
234
- }
235
-
236
- set bg(value: ColorInput | undefined) {
237
- const next = value ? parseColor(value) : undefined
238
- if (!colorsEqual(this._bg, next)) {
239
- this._bg = next
240
- this._styleDirty = true
241
- }
242
- }
243
-
244
- get conceal(): boolean {
245
- return this._conceal
246
- }
247
-
248
- set conceal(value: boolean) {
249
- if (this._conceal !== value) {
250
- this._conceal = value
251
- // Mark dirty - actual re-render happens in renderSelf
252
- this._styleDirty = true
253
- }
254
- }
255
-
256
- get concealCode(): boolean {
257
- return this._concealCode
258
- }
259
-
260
- set concealCode(value: boolean) {
261
- if (this._concealCode !== value) {
262
- this._concealCode = value
263
- // Mark dirty - actual re-render happens in renderSelf
264
- this._styleDirty = true
265
- }
266
- }
267
-
268
- get streaming(): boolean {
269
- return this._streaming
270
- }
271
-
272
- set streaming(value: boolean) {
273
- if (this.isDestroyed) return
274
- if (this._streaming !== value) {
275
- this._streaming = value
276
- this.updateBlocks(true)
277
- }
278
- }
279
-
280
- get tableOptions(): MarkdownTableOptions | undefined {
281
- return this._tableOptions
282
- }
283
-
284
- set tableOptions(value: MarkdownTableOptions | undefined) {
285
- this._tableOptions = value
286
- this.applyTableOptionsToBlocks()
287
- }
288
-
289
- private getStyle(group: string): StyleDefinition | undefined {
290
- // The solid reconciler applies props via setters in JSX declaration order.
291
- // If `content` is set before `syntaxStyle`, updateBlocks() runs before
292
- // _syntaxStyle is initialized.
293
- if (!this._syntaxStyle) return undefined
294
- let style = this._syntaxStyle.getStyle(group)
295
- if (!style && group.includes(".")) {
296
- const baseName = group.split(".")[0]
297
- style = this._syntaxStyle.getStyle(baseName)
298
- }
299
- return style
300
- }
301
-
302
- private createChunk(text: string, group: string, link?: { url: string }): TextChunk {
303
- const style = this.getStyle(group) || this.getStyle("default")
304
- return {
305
- __isChunk: true,
306
- text,
307
- fg: style?.fg,
308
- bg: style?.bg,
309
- attributes: style
310
- ? createTextAttributes({
311
- bold: style.bold,
312
- italic: style.italic,
313
- underline: style.underline,
314
- dim: style.dim,
315
- })
316
- : 0,
317
- link,
318
- }
319
- }
320
-
321
- private createDefaultChunk(text: string): TextChunk {
322
- return this.createChunk(text, "default")
323
- }
324
-
325
- private renderInlineContent(tokens: Token[], chunks: TextChunk[]): void {
326
- for (const token of tokens) {
327
- this.renderInlineToken(token as MarkedToken, chunks)
328
- }
329
- }
330
-
331
- private renderInlineToken(token: MarkedToken, chunks: TextChunk[]): void {
332
- switch (token.type) {
333
- case "text":
334
- chunks.push(this.createDefaultChunk(token.text))
335
- break
336
-
337
- case "escape":
338
- chunks.push(this.createDefaultChunk(token.text))
339
- break
340
-
341
- case "codespan":
342
- if (this._conceal) {
343
- chunks.push(this.createChunk(token.text, "markup.raw"))
344
- } else {
345
- chunks.push(this.createChunk("`", "markup.raw"))
346
- chunks.push(this.createChunk(token.text, "markup.raw"))
347
- chunks.push(this.createChunk("`", "markup.raw"))
348
- }
349
- break
350
-
351
- case "strong":
352
- if (!this._conceal) {
353
- chunks.push(this.createChunk("**", "markup.strong"))
354
- }
355
- for (const child of token.tokens) {
356
- this.renderInlineTokenWithStyle(child as MarkedToken, chunks, "markup.strong")
357
- }
358
- if (!this._conceal) {
359
- chunks.push(this.createChunk("**", "markup.strong"))
360
- }
361
- break
362
-
363
- case "em":
364
- if (!this._conceal) {
365
- chunks.push(this.createChunk("*", "markup.italic"))
366
- }
367
- for (const child of token.tokens) {
368
- this.renderInlineTokenWithStyle(child as MarkedToken, chunks, "markup.italic")
369
- }
370
- if (!this._conceal) {
371
- chunks.push(this.createChunk("*", "markup.italic"))
372
- }
373
- break
374
-
375
- case "del":
376
- if (!this._conceal) {
377
- chunks.push(this.createChunk("~~", "markup.strikethrough"))
378
- }
379
- for (const child of token.tokens) {
380
- this.renderInlineTokenWithStyle(child as MarkedToken, chunks, "markup.strikethrough")
381
- }
382
- if (!this._conceal) {
383
- chunks.push(this.createChunk("~~", "markup.strikethrough"))
384
- }
385
- break
386
-
387
- case "link": {
388
- const linkHref = { url: token.href }
389
- if (this._conceal) {
390
- for (const child of token.tokens) {
391
- this.renderInlineTokenWithStyle(child as MarkedToken, chunks, "markup.link.label", linkHref)
392
- }
393
- chunks.push(this.createChunk(" (", "markup.link", linkHref))
394
- chunks.push(this.createChunk(token.href, "markup.link.url", linkHref))
395
- chunks.push(this.createChunk(")", "markup.link", linkHref))
396
- } else {
397
- chunks.push(this.createChunk("[", "markup.link", linkHref))
398
- for (const child of token.tokens) {
399
- this.renderInlineTokenWithStyle(child as MarkedToken, chunks, "markup.link.label", linkHref)
400
- }
401
- chunks.push(this.createChunk("](", "markup.link", linkHref))
402
- chunks.push(this.createChunk(token.href, "markup.link.url", linkHref))
403
- chunks.push(this.createChunk(")", "markup.link", linkHref))
404
- }
405
- break
406
- }
407
-
408
- case "image": {
409
- const imageHref = { url: token.href }
410
- if (this._conceal) {
411
- chunks.push(this.createChunk(token.text || "image", "markup.link.label", imageHref))
412
- } else {
413
- chunks.push(this.createChunk("![", "markup.link", imageHref))
414
- chunks.push(this.createChunk(token.text || "", "markup.link.label", imageHref))
415
- chunks.push(this.createChunk("](", "markup.link", imageHref))
416
- chunks.push(this.createChunk(token.href, "markup.link.url", imageHref))
417
- chunks.push(this.createChunk(")", "markup.link", imageHref))
418
- }
419
- break
420
- }
421
-
422
- case "br":
423
- chunks.push(this.createDefaultChunk("\n"))
424
- break
425
-
426
- default:
427
- if ("tokens" in token && Array.isArray(token.tokens)) {
428
- this.renderInlineContent(token.tokens, chunks)
429
- } else if ("text" in token && typeof token.text === "string") {
430
- chunks.push(this.createDefaultChunk(token.text))
431
- }
432
- break
433
- }
434
- }
435
-
436
- private renderInlineTokenWithStyle(
437
- token: MarkedToken,
438
- chunks: TextChunk[],
439
- styleGroup: string,
440
- link?: { url: string },
441
- ): void {
442
- switch (token.type) {
443
- case "text":
444
- chunks.push(this.createChunk(token.text, styleGroup, link))
445
- break
446
-
447
- case "escape":
448
- chunks.push(this.createChunk(token.text, styleGroup, link))
449
- break
450
-
451
- case "codespan":
452
- if (this._conceal) {
453
- chunks.push(this.createChunk(token.text, "markup.raw", link))
454
- } else {
455
- chunks.push(this.createChunk("`", "markup.raw", link))
456
- chunks.push(this.createChunk(token.text, "markup.raw", link))
457
- chunks.push(this.createChunk("`", "markup.raw", link))
458
- }
459
- break
460
-
461
- default:
462
- this.renderInlineToken(token, chunks)
463
- break
464
- }
465
- }
466
-
467
- private buildInlineConcealChunks(chunks: TextChunk[], context: { content: string; highlights: any[] }): TextChunk[] {
468
- // Re-parse with marked to get inline tokens, then render with concealment.
469
- // Falls back to original chunks if inline rendering produces nothing.
470
- const result: TextChunk[] = []
471
- try {
472
- const parsed = parseMarkdownIncremental(context.content, null, 0)
473
- const tokens = parsed.tokens
474
- for (const token of tokens) {
475
- this.renderBlockTokenInline(token, result)
476
- }
477
- } catch {
478
- return chunks
479
- }
480
-
481
- // Remove trailing newline added by renderBlockTokenInline
482
- if (result.length > 0 && result[result.length - 1].text === "\n") {
483
- result.pop()
484
- }
485
-
486
- if (result.length === 0) return chunks
487
-
488
- // Apply linkification on top of inline-rendered chunks
489
- const linked = this._linkifyMarkdownChunks(result, context as any)
490
- if (Array.isArray(linked)) return linked
491
- return result
492
- }
493
-
494
- private renderBlockTokenInline(token: MarkedToken, chunks: TextChunk[]): void {
495
- switch (token.type) {
496
- case "heading": {
497
- const headingToken = token as Tokens.Heading
498
- const style = `markup.heading.${headingToken.depth}`
499
- for (const child of headingToken.tokens) {
500
- this.renderInlineTokenWithStyle(child as MarkedToken, chunks, style)
501
- }
502
- chunks.push(this.createDefaultChunk("\n"))
503
- break
504
- }
505
- case "paragraph": {
506
- const paragraphToken = token as Tokens.Paragraph
507
- this.renderInlineContent(paragraphToken.tokens, chunks)
508
- chunks.push(this.createDefaultChunk("\n"))
509
- break
510
- }
511
- case "list": {
512
- this.renderListInline(token as Tokens.List, chunks, 0)
513
- break
514
- }
515
- case "blockquote": {
516
- const quoteToken = token as Tokens.Blockquote
517
- for (const child of quoteToken.tokens) {
518
- const markedChild = child as MarkedToken
519
- if (markedChild.type === "paragraph" && "tokens" in markedChild) {
520
- chunks.push(this.createChunk("▎ ", "markup.quote"))
521
- for (const inline of (markedChild as Tokens.Paragraph).tokens) {
522
- this.renderInlineTokenWithStyle(inline as MarkedToken, chunks, "markup.quote")
523
- }
524
- chunks.push(this.createDefaultChunk("\n"))
525
- } else if (markedChild.type === "table") {
526
- // Reconstruct pipe table from structured token data so every row
527
- // gets the blockquote ▎ prefix (tbl.raw may only have > on first line)
528
- const tbl = markedChild as Tokens.Table
529
- const headerCells = tbl.header.map((h) => h.text || " ").join(" | ")
530
- const sepCells = tbl.header.map(() => "---").join(" | ")
531
- const tableLines = [
532
- `| ${headerCells} |`,
533
- `| ${sepCells} |`,
534
- ...tbl.rows.map((row) => `| ${row.map((c) => c.text || " ").join(" | ")} |`),
535
- ]
536
- for (const line of tableLines) {
537
- chunks.push(this.createChunk("▎ ", "markup.quote"))
538
- chunks.push(this.createDefaultChunk(line + "\n"))
539
- }
540
- } else {
541
- chunks.push(this.createChunk("▎ ", "markup.quote"))
542
- this.renderBlockTokenInline(markedChild, chunks)
543
- }
544
- }
545
- break
546
- }
547
- case "code": {
548
- // Fenced code blocks that ended up in the inline path (rare — normally
549
- // handled separately by createCodeRenderable). Render as raw block.
550
- const codeToken = token as Tokens.Code
551
- const rawStyle = this.getStyle("markup.raw.block")
552
- const codeText = codeToken.text
553
- for (const line of codeText.split("\n")) {
554
- chunks.push({
555
- __isChunk: true,
556
- text: " " + line,
557
- fg: rawStyle?.fg,
558
- bg: rawStyle?.bg,
559
- attributes: rawStyle
560
- ? createTextAttributes({
561
- bold: rawStyle.bold,
562
- italic: rawStyle.italic,
563
- underline: rawStyle.underline,
564
- dim: rawStyle.dim,
565
- })
566
- : 0,
567
- })
568
- chunks.push(this.createDefaultChunk("\n"))
569
- }
570
- break
571
- }
572
- case "html": {
573
- // Inline/block HTML — render as raw text
574
- chunks.push(this.createDefaultChunk(token.text))
575
- chunks.push(this.createDefaultChunk("\n"))
576
- break
577
- }
578
- case "hr": {
579
- const hrStyle = this.getStyle("punctuation.special")
580
- chunks.push({
581
- __isChunk: true,
582
- text: "─".repeat(40),
583
- fg: hrStyle?.fg,
584
- bg: hrStyle?.bg,
585
- attributes: hrStyle
586
- ? createTextAttributes({
587
- bold: hrStyle.bold,
588
- italic: hrStyle.italic,
589
- underline: hrStyle.underline,
590
- dim: hrStyle.dim,
591
- })
592
- : 0,
593
- })
594
- chunks.push(this.createDefaultChunk("\n"))
595
- break
596
- }
597
- case "table": {
598
- // Tables that ended up in the inline path (rare — normally handled
599
- // separately by createTextTableRenderable). Render as raw text.
600
- chunks.push(this.createDefaultChunk((token as any).raw ?? ""))
601
- chunks.push(this.createDefaultChunk("\n"))
602
- break
603
- }
604
- case "def":
605
- // Link reference definitions — not rendered visually
606
- break
607
- case "space":
608
- chunks.push(this.createDefaultChunk("\n"))
609
- break
610
- default:
611
- if ("tokens" in token && Array.isArray(token.tokens)) {
612
- this.renderInlineContent(token.tokens, chunks)
613
- } else {
614
- chunks.push(this.createDefaultChunk((token as any).raw ?? ""))
615
- }
616
- chunks.push(this.createDefaultChunk("\n"))
617
- break
618
- }
619
- }
620
-
621
- private renderListInline(list: Tokens.List, chunks: TextChunk[], depth: number): void {
622
- const listStyle = this.getStyle("markup.list")
623
- const checkedStyle = this.getStyle("markup.list.checked")
624
- const uncheckedStyle = this.getStyle("markup.list.unchecked")
625
- for (let i = 0; i < list.items.length; i++) {
626
- const item = list.items[i]
627
- const indent = " ".repeat(depth)
628
- const start = typeof list.start === "number" ? list.start : 1
629
-
630
- // Task list items: show checkbox
631
- if (item.task) {
632
- const checkmark = item.checked ? "☑ " : "☐ "
633
- const checkStyle = item.checked ? checkedStyle : uncheckedStyle
634
- chunks.push({
635
- __isChunk: true,
636
- text: indent + checkmark,
637
- fg: checkStyle?.fg ?? listStyle?.fg,
638
- bg: checkStyle?.bg ?? listStyle?.bg,
639
- attributes: checkStyle
640
- ? createTextAttributes({
641
- bold: checkStyle.bold,
642
- italic: checkStyle.italic,
643
- underline: checkStyle.underline,
644
- dim: checkStyle.dim,
645
- })
646
- : 0,
647
- })
648
- } else {
649
- const bullet = list.ordered ? `${start + i}. ` : "• "
650
- chunks.push({
651
- __isChunk: true,
652
- text: indent + bullet,
653
- fg: listStyle?.fg,
654
- bg: listStyle?.bg,
655
- attributes: listStyle
656
- ? createTextAttributes({
657
- bold: listStyle.bold,
658
- italic: listStyle.italic,
659
- underline: listStyle.underline,
660
- dim: listStyle.dim,
661
- })
662
- : 0,
663
- })
664
- }
665
-
666
- for (const subToken of item.tokens) {
667
- const markedSub = subToken as MarkedToken
668
- if (markedSub.type === "text" && "tokens" in markedSub && Array.isArray(markedSub.tokens)) {
669
- this.renderInlineContent(markedSub.tokens, chunks)
670
- } else if (markedSub.type === "list") {
671
- chunks.push(this.createDefaultChunk("\n"))
672
- this.renderListInline(markedSub as Tokens.List, chunks, depth + 1)
673
- continue
674
- } else if (markedSub.type === "paragraph" && "tokens" in markedSub) {
675
- this.renderInlineContent((markedSub as Tokens.Paragraph).tokens, chunks)
676
- } else if (markedSub.type === "code") {
677
- // Render fenced code blocks inside list items on their own indented lines
678
- if (chunks.length > 0 && !chunks[chunks.length - 1].text.endsWith("\n")) {
679
- chunks[chunks.length - 1] = { ...chunks[chunks.length - 1], text: chunks[chunks.length - 1].text + "\n" }
680
- } else {
681
- chunks.push(this.createDefaultChunk("\n"))
682
- }
683
- const codeLines = (markedSub as Tokens.Code).text.split("\n")
684
- const codeStyle = this.getStyle("markup.raw") || this.getStyle("default")
685
- for (const codeLine of codeLines) {
686
- chunks.push(this.createDefaultChunk(indent + " "))
687
- chunks.push({
688
- __isChunk: true,
689
- text: codeLine,
690
- fg: codeStyle?.fg,
691
- bg: codeStyle?.bg,
692
- attributes: 0,
693
- })
694
- chunks.push(this.createDefaultChunk("\n"))
695
- }
696
- continue
697
- } else {
698
- this.renderInlineToken(markedSub, chunks)
699
- }
700
- }
701
- chunks.push(this.createDefaultChunk("\n"))
702
- }
703
- }
704
-
705
- private createMarkdownCodeRenderable(content: string, id: string, marginBottom: number = 0): CodeRenderable {
706
- return new CodeRenderable(this.ctx, {
707
- id,
708
- content,
709
- filetype: "markdown",
710
- syntaxStyle: this._syntaxStyle,
711
- fg: this._fg,
712
- bg: this._bg,
713
- conceal: this._conceal,
714
- drawUnstyledText: true,
715
- streaming: true,
716
- onChunks: this._conceal ? this._inlineConcealChunks : this._linkifyMarkdownChunks,
717
- treeSitterClient: this._treeSitterClient,
718
- width: "100%",
719
- marginBottom,
720
- })
721
- }
722
-
723
- private createCodeRenderable(token: Tokens.Code, id: string, marginBottom: number = 0): Renderable {
724
- return new CodeRenderable(this.ctx, {
725
- id,
726
- content: token.text,
727
- filetype: infoStringToFiletype(token.lang ?? ""),
728
- syntaxStyle: this._syntaxStyle,
729
- fg: this._fg,
730
- bg: this._bg,
731
- conceal: this._concealCode,
732
- drawUnstyledText: !(this._streaming && this._concealCode),
733
- streaming: this._streaming,
734
- treeSitterClient: this._treeSitterClient,
735
- width: "100%",
736
- marginBottom,
737
- })
738
- }
739
-
740
- private applyMarkdownCodeRenderable(renderable: CodeRenderable, content: string, marginBottom: number): void {
741
- renderable.content = content
742
- renderable.filetype = "markdown"
743
- renderable.syntaxStyle = this._syntaxStyle
744
- renderable.fg = this._fg
745
- renderable.bg = this._bg
746
- renderable.conceal = this._conceal
747
- renderable.drawUnstyledText = true
748
- renderable.streaming = true
749
- renderable.onChunks = this._conceal ? this._inlineConcealChunks : this._linkifyMarkdownChunks
750
- renderable.marginBottom = marginBottom
751
- }
752
-
753
- private applyCodeBlockRenderable(renderable: CodeRenderable, token: Tokens.Code, marginBottom: number): void {
754
- renderable.content = token.text
755
- renderable.filetype = infoStringToFiletype(token.lang ?? "")
756
- renderable.syntaxStyle = this._syntaxStyle
757
- renderable.fg = this._fg
758
- renderable.bg = this._bg
759
- renderable.conceal = this._concealCode
760
- renderable.drawUnstyledText = !(this._streaming && this._concealCode)
761
- renderable.streaming = this._streaming
762
- renderable.marginBottom = marginBottom
763
- }
764
-
765
- private shouldRenderSeparately(token: MarkedToken): boolean {
766
- return token.type === "code" || token.type === "table" || token.type === "blockquote"
767
- }
768
-
769
- private getInterBlockMargin(token: MarkedToken, hasNextToken: boolean): number {
770
- if (!hasNextToken) return 0
771
- return this.shouldRenderSeparately(token) ? 1 : 0
772
- }
773
-
774
- private createMarkdownBlockToken(raw: string): MarkedToken {
775
- return {
776
- type: "paragraph",
777
- raw,
778
- text: raw,
779
- tokens: [],
780
- } as MarkedToken
781
- }
782
-
783
- private normalizeMarkdownBlockRaw(raw: string): string {
784
- return raw.replace(TRAILING_MARKDOWN_BLOCK_BREAKS_RE, "")
785
- }
786
-
787
- private buildRenderableTokens(tokens: MarkedToken[]): MarkedToken[] {
788
- if (this._renderNode) {
789
- return tokens.filter((token) => token.type !== "space")
790
- }
791
-
792
- const renderTokens: MarkedToken[] = []
793
- let markdownRaw = ""
794
-
795
- const flushMarkdownRaw = (): void => {
796
- if (markdownRaw.length === 0) return
797
- const normalizedRaw = this.normalizeMarkdownBlockRaw(markdownRaw)
798
- if (normalizedRaw.length > 0) {
799
- renderTokens.push(this.createMarkdownBlockToken(normalizedRaw))
800
- }
801
- markdownRaw = ""
802
- }
803
-
804
- for (let i = 0; i < tokens.length; i += 1) {
805
- const token = tokens[i]
806
-
807
- if (token.type === "space") {
808
- if (markdownRaw.length === 0) {
809
- continue
810
- }
811
-
812
- let nextIndex = i + 1
813
- while (nextIndex < tokens.length && tokens[nextIndex].type === "space") {
814
- nextIndex += 1
815
- }
816
-
817
- const nextToken = tokens[nextIndex]
818
- if (nextToken && !this.shouldRenderSeparately(nextToken)) {
819
- markdownRaw += token.raw
820
- }
821
- continue
822
- }
823
-
824
- if (this.shouldRenderSeparately(token)) {
825
- flushMarkdownRaw()
826
- renderTokens.push(token)
827
- continue
828
- }
829
-
830
- markdownRaw += token.raw
831
- }
832
-
833
- flushMarkdownRaw()
834
-
835
- return renderTokens
836
- }
837
-
838
- private getTableRowsToRender(table: Tokens.Table): Tokens.TableCell[][] {
839
- return table.rows
840
- }
841
-
842
- private hashString(value: string, seed: number): number {
843
- let hash = seed >>> 0
844
- for (let i = 0; i < value.length; i += 1) {
845
- hash ^= value.charCodeAt(i)
846
- hash = Math.imul(hash, 16777619)
847
- }
848
- return hash >>> 0
849
- }
850
-
851
- private hashTableToken(token: MarkedToken, seed: number, depth: number = 0): number {
852
- let hash = this.hashString(token.type, seed)
853
-
854
- if ("raw" in token && typeof token.raw === "string") {
855
- return this.hashString(token.raw, hash)
856
- }
857
-
858
- if ("text" in token && typeof token.text === "string") {
859
- hash = this.hashString(token.text, hash)
860
- }
861
-
862
- if (depth < 2 && "tokens" in token && Array.isArray(token.tokens)) {
863
- for (const child of token.tokens) {
864
- hash = this.hashTableToken(child as MarkedToken, hash, depth + 1)
865
- }
866
- }
867
-
868
- return hash >>> 0
869
- }
870
-
871
- private getTableCellKey(cell: Tokens.TableCell | undefined, isHeader: boolean): number {
872
- const seed = isHeader ? 2902232141 : 1371922141
873
- if (!cell) {
874
- return seed
875
- }
876
-
877
- if (typeof cell.text === "string") {
878
- return this.hashString(cell.text, seed)
879
- }
880
-
881
- if (Array.isArray(cell.tokens) && cell.tokens.length > 0) {
882
- let hash = seed ^ cell.tokens.length
883
- for (const token of cell.tokens) {
884
- hash = this.hashTableToken(token as MarkedToken, hash)
885
- }
886
- return hash >>> 0
887
- }
888
-
889
- return (seed ^ 2654435769) >>> 0
890
- }
891
-
892
- private createTableDataCellChunks(cell: Tokens.TableCell | undefined): TextChunk[] {
893
- const chunks: TextChunk[] = []
894
- if (cell) {
895
- this.renderInlineContent(cell.tokens, chunks)
896
- }
897
- return chunks.length > 0 ? chunks : [this.createDefaultChunk(" ")]
898
- }
899
-
900
- private createTableHeaderCellChunks(cell: Tokens.TableCell): TextChunk[] {
901
- const chunks: TextChunk[] = []
902
- this.renderInlineContent(cell.tokens, chunks)
903
-
904
- const baseChunks = chunks.length > 0 ? chunks : [this.createDefaultChunk(" ")]
905
- const headingStyle = this.getStyle("markup.heading") || this.getStyle("default")
906
- if (!headingStyle) {
907
- return baseChunks
908
- }
909
-
910
- const headingAttributes = createTextAttributes({
911
- bold: headingStyle.bold,
912
- italic: headingStyle.italic,
913
- underline: headingStyle.underline,
914
- dim: headingStyle.dim,
915
- })
916
-
917
- return baseChunks.map((chunk) => ({
918
- ...chunk,
919
- fg: headingStyle.fg ?? chunk.fg,
920
- bg: headingStyle.bg ?? chunk.bg,
921
- attributes: headingAttributes,
922
- }))
923
- }
924
-
925
- private buildTableContentCache(
926
- table: Tokens.Table,
927
- previous?: TableContentCache,
928
- forceRegenerate: boolean = false,
929
- ): { cache: TableContentCache | null; changed: boolean } {
930
- const colCount = table.header.length
931
- const rowsToRender = this.getTableRowsToRender(table)
932
- if (colCount === 0 || rowsToRender.length === 0) {
933
- return { cache: null, changed: previous !== undefined }
934
- }
935
-
936
- const content: TextTableContent = []
937
- const cellKeys: Uint32Array[] = []
938
- const totalRows = rowsToRender.length + 1
939
-
940
- let changed = forceRegenerate || !previous
941
-
942
- for (let rowIndex = 0; rowIndex < totalRows; rowIndex += 1) {
943
- const rowContent: TextTableCellContent[] = []
944
- const rowKeys = new Uint32Array(colCount)
945
-
946
- for (let colIndex = 0; colIndex < colCount; colIndex += 1) {
947
- const isHeader = rowIndex === 0
948
- const cell = isHeader ? table.header[colIndex] : rowsToRender[rowIndex - 1]?.[colIndex]
949
- const cellKey = this.getTableCellKey(cell, isHeader)
950
- rowKeys[colIndex] = cellKey
951
-
952
- const previousCellKey = previous?.cellKeys[rowIndex]?.[colIndex]
953
- const previousCellContent = previous?.content[rowIndex]?.[colIndex]
954
-
955
- if (!forceRegenerate && previousCellKey === cellKey && Array.isArray(previousCellContent)) {
956
- rowContent.push(previousCellContent)
957
- continue
958
- }
959
-
960
- changed = true
961
- rowContent.push(
962
- isHeader ? this.createTableHeaderCellChunks(table.header[colIndex]) : this.createTableDataCellChunks(cell),
963
- )
964
- }
965
-
966
- content.push(rowContent)
967
- cellKeys.push(rowKeys)
968
- }
969
-
970
- if (previous && !changed) {
971
- if (previous.content.length !== content.length) {
972
- changed = true
973
- } else {
974
- for (let rowIndex = 0; rowIndex < content.length; rowIndex += 1) {
975
- if ((previous.content[rowIndex]?.length ?? 0) !== content[rowIndex].length) {
976
- changed = true
977
- break
978
- }
979
- }
980
- }
981
- }
982
-
983
- return {
984
- cache: {
985
- content,
986
- cellKeys,
987
- },
988
- changed,
989
- }
990
- }
991
-
992
- private resolveTableRenderableOptions(): ResolvedTableRenderableOptions {
993
- const borders = this._tableOptions?.borders ?? true
994
-
995
- return {
996
- columnWidthMode: this._tableOptions?.widthMode ?? "full",
997
- columnFitter: this._tableOptions?.columnFitter ?? "proportional",
998
- wrapMode: this._tableOptions?.wrapMode ?? "word",
999
- cellPadding: this._tableOptions?.cellPadding ?? 0,
1000
- border: borders,
1001
- outerBorder: this._tableOptions?.outerBorder ?? borders,
1002
- showBorders: borders,
1003
- borderStyle: this._tableOptions?.borderStyle ?? "single",
1004
- borderColor: this._tableOptions?.borderColor ?? this.getStyle("conceal")?.fg ?? "#888888",
1005
- selectable: this._tableOptions?.selectable ?? true,
1006
- }
1007
- }
1008
-
1009
- private applyTableRenderableOptions(
1010
- tableRenderable: TextTableRenderable,
1011
- options: ResolvedTableRenderableOptions,
1012
- ): void {
1013
- tableRenderable.columnWidthMode = options.columnWidthMode
1014
- tableRenderable.columnFitter = options.columnFitter
1015
- tableRenderable.wrapMode = options.wrapMode
1016
- tableRenderable.cellPadding = options.cellPadding
1017
- tableRenderable.border = options.border
1018
- tableRenderable.outerBorder = options.outerBorder
1019
- tableRenderable.showBorders = options.showBorders
1020
- tableRenderable.borderStyle = options.borderStyle
1021
- tableRenderable.borderColor = options.borderColor
1022
- tableRenderable.selectable = options.selectable
1023
- }
1024
-
1025
- private applyTableOptionsToBlocks(): void {
1026
- const options = this.resolveTableRenderableOptions()
1027
- let updated = false
1028
-
1029
- for (const state of this._blockStates) {
1030
- if (state.renderable instanceof TextTableRenderable) {
1031
- this.applyTableRenderableOptions(state.renderable, options)
1032
- updated = true
1033
- }
1034
- }
1035
-
1036
- if (updated) {
1037
- this.requestRender()
1038
- }
1039
- }
1040
-
1041
- private createTextTableRenderable(
1042
- content: TextTableContent,
1043
- id: string,
1044
- marginBottom: number = 0,
1045
- ): TextTableRenderable {
1046
- const options = this.resolveTableRenderableOptions()
1047
- return new TextTableRenderable(this.ctx, {
1048
- id,
1049
- content,
1050
- width: "100%",
1051
- marginBottom,
1052
- columnWidthMode: options.columnWidthMode,
1053
- columnFitter: options.columnFitter,
1054
- wrapMode: options.wrapMode,
1055
- cellPadding: options.cellPadding,
1056
- border: options.border,
1057
- outerBorder: options.outerBorder,
1058
- showBorders: options.showBorders,
1059
- borderStyle: options.borderStyle,
1060
- borderColor: options.borderColor,
1061
- selectable: options.selectable,
1062
- })
1063
- }
1064
-
1065
- private createTableBlock(
1066
- table: Tokens.Table,
1067
- id: string,
1068
- marginBottom: number = 0,
1069
- previousCache?: TableContentCache,
1070
- forceRegenerate: boolean = false,
1071
- ): { renderable: Renderable; tableContentCache?: TableContentCache } {
1072
- const { cache } = this.buildTableContentCache(table, previousCache, forceRegenerate)
1073
-
1074
- if (!cache) {
1075
- return {
1076
- renderable: this.createMarkdownCodeRenderable(table.raw, id, marginBottom),
1077
- }
1078
- }
1079
-
1080
- return {
1081
- renderable: this.createTextTableRenderable(cache.content, id, marginBottom),
1082
- tableContentCache: cache,
1083
- }
1084
- }
1085
-
1086
- private createDefaultRenderable(token: MarkedToken, index: number, hasNextToken: boolean = false): Renderable | null {
1087
- const id = `${this.id}-block-${index}`
1088
- const marginBottom = this.getInterBlockMargin(token, hasNextToken)
1089
-
1090
- if (token.type === "code") {
1091
- return this.createCodeRenderable(token, id, marginBottom)
1092
- }
1093
-
1094
- if (token.type === "table") {
1095
- return this.createTableBlock(token, id, marginBottom).renderable
1096
- }
1097
-
1098
- if (token.type === "space") {
1099
- return null
1100
- }
1101
-
1102
- if (!token.raw) {
1103
- return null
1104
- }
1105
-
1106
- return this.createMarkdownCodeRenderable(token.raw, id, marginBottom)
1107
- }
1108
-
1109
- private updateBlockRenderable(state: BlockState, token: MarkedToken, index: number, hasNextToken: boolean): void {
1110
- const marginBottom = this.getInterBlockMargin(token, hasNextToken)
1111
-
1112
- if (token.type === "code") {
1113
- this.applyCodeBlockRenderable(state.renderable as CodeRenderable, token as Tokens.Code, marginBottom)
1114
- return
1115
- }
1116
-
1117
- if (token.type === "table") {
1118
- const tableToken = token as Tokens.Table
1119
- const { cache, changed } = this.buildTableContentCache(tableToken, state.tableContentCache)
1120
-
1121
- if (!cache) {
1122
- if (state.renderable instanceof CodeRenderable) {
1123
- this.applyMarkdownCodeRenderable(state.renderable, tableToken.raw, marginBottom)
1124
- state.tableContentCache = undefined
1125
- return
1126
- }
1127
-
1128
- state.renderable.destroyRecursively()
1129
- const fallbackRenderable = this.createMarkdownCodeRenderable(
1130
- tableToken.raw,
1131
- `${this.id}-block-${index}`,
1132
- marginBottom,
1133
- )
1134
- this.add(fallbackRenderable)
1135
- state.renderable = fallbackRenderable
1136
- state.tableContentCache = undefined
1137
- return
1138
- }
1139
-
1140
- if (state.renderable instanceof TextTableRenderable) {
1141
- if (changed) {
1142
- state.renderable.content = cache.content
1143
- }
1144
- this.applyTableRenderableOptions(state.renderable, this.resolveTableRenderableOptions())
1145
- state.renderable.marginBottom = marginBottom
1146
- state.tableContentCache = cache
1147
- return
1148
- }
1149
-
1150
- state.renderable.destroyRecursively()
1151
- const tableRenderable = this.createTextTableRenderable(cache.content, `${this.id}-block-${index}`, marginBottom)
1152
- this.add(tableRenderable)
1153
- state.renderable = tableRenderable
1154
- state.tableContentCache = cache
1155
- return
1156
- }
1157
-
1158
- if (state.renderable instanceof CodeRenderable) {
1159
- this.applyMarkdownCodeRenderable(state.renderable, token.raw, marginBottom)
1160
- return
1161
- }
1162
-
1163
- state.renderable.destroyRecursively()
1164
- const markdownRenderable = this.createMarkdownCodeRenderable(token.raw, `${this.id}-block-${index}`, marginBottom)
1165
- this.add(markdownRenderable)
1166
- state.renderable = markdownRenderable
1167
- }
1168
-
1169
- private updateBlocks(forceTableRefresh: boolean = false): void {
1170
- if (this.isDestroyed) return
1171
- if (!this._content) {
1172
- this.clearBlockStates()
1173
- this._parseState = null
1174
- return
1175
- }
1176
-
1177
- const trailingUnstable = this._streaming ? 2 : 0
1178
- this._parseState = parseMarkdownIncremental(this._content, this._parseState, trailingUnstable)
1179
-
1180
- const tokens = this._parseState.tokens
1181
-
1182
- // Parse failure fallback
1183
- if (tokens.length === 0 && this._content.length > 0) {
1184
- this.clearBlockStates()
1185
- const fallback = this.createMarkdownCodeRenderable(this._content, `${this.id}-fallback`)
1186
- this.add(fallback)
1187
- this._blockStates = [
1188
- {
1189
- token: { type: "text", raw: this._content, text: this._content } as MarkedToken,
1190
- tokenRaw: this._content,
1191
- renderable: fallback,
1192
- },
1193
- ]
1194
- return
1195
- }
1196
-
1197
- const blockTokens = this.buildRenderableTokens(tokens)
1198
- const lastBlockIndex = blockTokens.length - 1
1199
-
1200
- let blockIndex = 0
1201
- for (let i = 0; i < blockTokens.length; i++) {
1202
- const token = blockTokens[i]
1203
- const hasNextToken = i < lastBlockIndex
1204
- const existing = this._blockStates[blockIndex]
1205
-
1206
- const shouldForceRefresh = forceTableRefresh
1207
-
1208
- // Same token object reference means unchanged
1209
- if (existing && existing.token === token) {
1210
- if (shouldForceRefresh) {
1211
- this.updateBlockRenderable(existing, token, blockIndex, hasNextToken)
1212
- existing.tokenRaw = token.raw
1213
- }
1214
- blockIndex++
1215
- continue
1216
- }
1217
-
1218
- // Same content, update reference
1219
- if (existing && existing.tokenRaw === token.raw && existing.token.type === token.type) {
1220
- existing.token = token
1221
- if (shouldForceRefresh) {
1222
- this.updateBlockRenderable(existing, token, blockIndex, hasNextToken)
1223
- existing.tokenRaw = token.raw
1224
- }
1225
- blockIndex++
1226
- continue
1227
- }
1228
-
1229
- // Same type, different content - update in place
1230
- if (existing && existing.token.type === token.type) {
1231
- this.updateBlockRenderable(existing, token, blockIndex, hasNextToken)
1232
- existing.token = token
1233
- existing.tokenRaw = token.raw
1234
- blockIndex++
1235
- continue
1236
- }
1237
-
1238
- // Different type or new block
1239
- if (existing) {
1240
- existing.renderable.destroyRecursively()
1241
- }
1242
-
1243
- let renderable: Renderable | undefined
1244
- let tableContentCache: TableContentCache | undefined
1245
-
1246
- if (this._renderNode) {
1247
- const context: RenderNodeContext = {
1248
- syntaxStyle: this._syntaxStyle,
1249
- conceal: this._conceal,
1250
- concealCode: this._concealCode,
1251
- treeSitterClient: this._treeSitterClient,
1252
- defaultRender: () => this.createDefaultRenderable(token, blockIndex, hasNextToken),
1253
- }
1254
- const custom = this._renderNode(token, context)
1255
- if (custom) {
1256
- renderable = custom
1257
- }
1258
- }
1259
-
1260
- if (!renderable) {
1261
- if (token.type === "table") {
1262
- const tableBlock = this.createTableBlock(
1263
- token,
1264
- `${this.id}-block-${blockIndex}`,
1265
- this.getInterBlockMargin(token, hasNextToken),
1266
- )
1267
- renderable = tableBlock.renderable
1268
- tableContentCache = tableBlock.tableContentCache
1269
- } else {
1270
- renderable = this.createDefaultRenderable(token, blockIndex, hasNextToken) ?? undefined
1271
- }
1272
- }
1273
-
1274
- if (token.type === "table" && !tableContentCache && renderable instanceof TextTableRenderable) {
1275
- const { cache } = this.buildTableContentCache(token as Tokens.Table)
1276
- tableContentCache = cache ?? undefined
1277
- }
1278
-
1279
- if (renderable) {
1280
- this.add(renderable)
1281
- this._blockStates[blockIndex] = {
1282
- token,
1283
- tokenRaw: token.raw,
1284
- renderable,
1285
- tableContentCache,
1286
- }
1287
- }
1288
- blockIndex++
1289
- }
1290
-
1291
- while (this._blockStates.length > blockIndex) {
1292
- const removed = this._blockStates.pop()!
1293
- removed.renderable.destroyRecursively()
1294
- }
1295
- }
1296
-
1297
- private clearBlockStates(): void {
1298
- for (const state of this._blockStates) {
1299
- state.renderable.destroyRecursively()
1300
- }
1301
- this._blockStates = []
1302
- }
1303
-
1304
- /**
1305
- * Re-render existing blocks without rebuilding the parse state or block structure.
1306
- * Used when only style/conceal changes - much faster than full rebuild.
1307
- */
1308
- private rerenderBlocks(): void {
1309
- for (let i = 0; i < this._blockStates.length; i++) {
1310
- const state = this._blockStates[i]
1311
- const hasNextToken = i < this._blockStates.length - 1
1312
- const marginBottom = this.getInterBlockMargin(state.token, hasNextToken)
1313
-
1314
- if (state.token.type === "code") {
1315
- this.applyCodeBlockRenderable(state.renderable as CodeRenderable, state.token as Tokens.Code, marginBottom)
1316
- continue
1317
- }
1318
-
1319
- if (state.token.type === "table") {
1320
- const tableToken = state.token as Tokens.Table
1321
- const { cache } = this.buildTableContentCache(tableToken, state.tableContentCache, true)
1322
-
1323
- if (!cache) {
1324
- if (state.renderable instanceof CodeRenderable) {
1325
- this.applyMarkdownCodeRenderable(state.renderable, tableToken.raw, marginBottom)
1326
- } else {
1327
- state.renderable.destroyRecursively()
1328
- const fallbackRenderable = this.createMarkdownCodeRenderable(
1329
- tableToken.raw,
1330
- `${this.id}-block-${i}`,
1331
- marginBottom,
1332
- )
1333
- this.add(fallbackRenderable)
1334
- state.renderable = fallbackRenderable
1335
- }
1336
- state.tableContentCache = undefined
1337
- continue
1338
- }
1339
-
1340
- if (state.renderable instanceof TextTableRenderable) {
1341
- state.renderable.content = cache.content
1342
- this.applyTableRenderableOptions(state.renderable, this.resolveTableRenderableOptions())
1343
- state.renderable.marginBottom = marginBottom
1344
- state.tableContentCache = cache
1345
- continue
1346
- }
1347
-
1348
- state.renderable.destroyRecursively()
1349
- const tableRenderable = this.createTextTableRenderable(cache.content, `${this.id}-block-${i}`, marginBottom)
1350
- this.add(tableRenderable)
1351
- state.renderable = tableRenderable
1352
- state.tableContentCache = cache
1353
- continue
1354
- }
1355
-
1356
- if (state.renderable instanceof CodeRenderable) {
1357
- this.applyMarkdownCodeRenderable(state.renderable, state.token.raw, marginBottom)
1358
- continue
1359
- }
1360
-
1361
- state.renderable.destroyRecursively()
1362
- const markdownRenderable = this.createMarkdownCodeRenderable(
1363
- state.token.raw,
1364
- `${this.id}-block-${i}`,
1365
- marginBottom,
1366
- )
1367
- this.add(markdownRenderable)
1368
- state.renderable = markdownRenderable
1369
- }
1370
- }
1371
-
1372
- public clearCache(): void {
1373
- this._parseState = null
1374
- this.clearBlockStates()
1375
- this.updateBlocks()
1376
- this.requestRender()
1377
- }
1378
-
1379
- public refreshStyles(): void {
1380
- this._styleDirty = false
1381
- this.rerenderBlocks()
1382
- this.requestRender()
1383
- }
1384
-
1385
- protected override renderSelf(buffer: OptimizedBuffer, deltaTime: number): void {
1386
- // Check if style/conceal changed - re-render blocks before rendering
1387
- if (this._styleDirty) {
1388
- this._styleDirty = false
1389
- this.rerenderBlocks()
1390
- }
1391
- super.renderSelf(buffer, deltaTime)
1392
- }
1393
- }