@fairyhunter13/opentui-core 0.1.89 → 0.1.91

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 (571) hide show
  1. package/README.md +2 -2
  2. package/dev/keypress-debug-renderer.ts +148 -0
  3. package/dev/keypress-debug.ts +43 -0
  4. package/dev/print-env-vars.ts +32 -0
  5. package/dev/test-tmux-graphics-334.sh +68 -0
  6. package/dev/thai-debug-test.ts +68 -0
  7. package/docs/development.md +141 -0
  8. package/docs/env-vars.md +140 -0
  9. package/docs/getting-started.md +353 -0
  10. package/docs/renderables-vs-constructs.md +159 -0
  11. package/docs/tree-sitter.md +311 -0
  12. package/package.json +61 -52
  13. package/scripts/build.ts +400 -0
  14. package/scripts/publish.ts +60 -0
  15. package/src/3d/SpriteResourceManager.ts +286 -0
  16. package/src/3d/SpriteUtils.ts +71 -0
  17. package/src/3d/TextureUtils.ts +196 -0
  18. package/src/3d/ThreeRenderable.ts +197 -0
  19. package/src/3d/WGPURenderer.ts +294 -0
  20. package/src/3d/animation/ExplodingSpriteEffect.ts +513 -0
  21. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +429 -0
  22. package/src/3d/animation/SpriteAnimator.ts +633 -0
  23. package/src/3d/animation/SpriteParticleGenerator.ts +435 -0
  24. package/src/3d/canvas.ts +464 -0
  25. package/src/3d/index.ts +12 -0
  26. package/src/3d/physics/PlanckPhysicsAdapter.ts +72 -0
  27. package/src/3d/physics/RapierPhysicsAdapter.ts +66 -0
  28. package/src/3d/physics/physics-interface.ts +31 -0
  29. package/src/3d/shaders/supersampling.wgsl +201 -0
  30. package/src/3d.ts +3 -0
  31. package/src/NativeSpanFeed.ts +300 -0
  32. package/src/Renderable.ts +1698 -0
  33. package/src/__snapshots__/buffer.test.ts.snap +28 -0
  34. package/src/animation/Timeline.test.ts +2709 -0
  35. package/src/animation/Timeline.ts +598 -0
  36. package/src/ansi.ts +18 -0
  37. package/src/benchmark/latest-all-bench-run.json +707 -0
  38. package/src/benchmark/latest-async-bench-run.json +336 -0
  39. package/src/benchmark/latest-default-bench-run.json +657 -0
  40. package/src/benchmark/latest-large-bench-run.json +707 -0
  41. package/src/benchmark/latest-quick-bench-run.json +207 -0
  42. package/src/benchmark/markdown-benchmark.ts +1804 -0
  43. package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
  44. package/src/benchmark/native-span-feed-benchmark.md +56 -0
  45. package/src/benchmark/native-span-feed-benchmark.ts +596 -0
  46. package/src/benchmark/native-span-feed-compare.ts +280 -0
  47. package/src/benchmark/renderer-benchmark.ts +754 -0
  48. package/src/benchmark/text-table-benchmark.ts +947 -0
  49. package/src/buffer.test.ts +291 -0
  50. package/src/buffer.ts +519 -0
  51. package/src/console.test.ts +612 -0
  52. package/src/console.ts +1255 -0
  53. package/src/edit-buffer.test.ts +1769 -0
  54. package/src/edit-buffer.ts +411 -0
  55. package/src/editor-view.test.ts +1032 -0
  56. package/src/editor-view.ts +284 -0
  57. package/src/examples/ascii-font-selection-demo.ts +245 -0
  58. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  59. package/src/examples/assets/concrete.png +0 -0
  60. package/src/examples/assets/crate.png +0 -0
  61. package/src/examples/assets/crate_emissive.png +0 -0
  62. package/src/examples/assets/forrest_background.png +0 -0
  63. package/src/examples/assets/hast-example.json +1018 -0
  64. package/src/examples/assets/heart.png +0 -0
  65. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  66. package/src/examples/assets/main_char_idle.png +0 -0
  67. package/src/examples/assets/main_char_jump_end.png +0 -0
  68. package/src/examples/assets/main_char_jump_landing.png +0 -0
  69. package/src/examples/assets/main_char_jump_start.png +0 -0
  70. package/src/examples/assets/main_char_run_loop.png +0 -0
  71. package/src/examples/assets/roughness_map.jpg +0 -0
  72. package/src/examples/build.ts +115 -0
  73. package/src/examples/code-demo.ts +584 -0
  74. package/src/examples/console-demo.ts +358 -0
  75. package/src/examples/core-plugin-slots-demo.ts +759 -0
  76. package/src/examples/diff-demo.ts +699 -0
  77. package/src/examples/draggable-three-demo.ts +259 -0
  78. package/src/examples/editor-demo.ts +322 -0
  79. package/src/examples/extmarks-demo.ts +204 -0
  80. package/src/examples/focus-restore-demo.ts +310 -0
  81. package/src/examples/fonts.ts +245 -0
  82. package/src/examples/fractal-shader-demo.ts +268 -0
  83. package/src/examples/framebuffer-demo.ts +674 -0
  84. package/src/examples/full-unicode-demo.ts +181 -0
  85. package/src/examples/golden-star-demo.ts +933 -0
  86. package/src/examples/grayscale-buffer-demo.ts +249 -0
  87. package/src/examples/hast-syntax-highlighting-demo.ts +129 -0
  88. package/src/examples/index.ts +925 -0
  89. package/src/examples/input-demo.ts +377 -0
  90. package/src/examples/input-select-layout-demo.ts +425 -0
  91. package/src/examples/install.sh +143 -0
  92. package/src/examples/keypress-debug-demo.ts +452 -0
  93. package/src/examples/lib/HexList.ts +122 -0
  94. package/src/examples/lib/PaletteGrid.ts +125 -0
  95. package/src/examples/lib/standalone-keys.ts +25 -0
  96. package/src/examples/lib/tab-controller.ts +243 -0
  97. package/src/examples/lights-phong-demo.ts +290 -0
  98. package/src/examples/link-demo.ts +220 -0
  99. package/src/examples/live-state-demo.ts +480 -0
  100. package/src/examples/markdown-demo.ts +620 -0
  101. package/src/examples/mouse-interaction-demo.ts +428 -0
  102. package/src/examples/nested-zindex-demo.ts +357 -0
  103. package/src/examples/opacity-example.ts +235 -0
  104. package/src/examples/opentui-demo.ts +1057 -0
  105. package/src/examples/physx-planck-2d-demo.ts +507 -0
  106. package/src/examples/physx-rapier-2d-demo.ts +526 -0
  107. package/src/examples/relative-positioning-demo.ts +323 -0
  108. package/src/examples/scroll-example.ts +214 -0
  109. package/src/examples/scrollbox-mouse-test.ts +112 -0
  110. package/src/examples/scrollbox-overlay-hit-test.ts +206 -0
  111. package/src/examples/select-demo.ts +237 -0
  112. package/src/examples/shader-cube-demo.ts +772 -0
  113. package/src/examples/simple-layout-example.ts +591 -0
  114. package/src/examples/slider-demo.ts +617 -0
  115. package/src/examples/split-mode-demo.ts +445 -0
  116. package/src/examples/sprite-animation-demo.ts +443 -0
  117. package/src/examples/sprite-particle-generator-demo.ts +486 -0
  118. package/src/examples/static-sprite-demo.ts +193 -0
  119. package/src/examples/sticky-scroll-example.ts +308 -0
  120. package/src/examples/styled-text-demo.ts +282 -0
  121. package/src/examples/tab-select-demo.ts +219 -0
  122. package/src/examples/terminal-title.ts +29 -0
  123. package/src/examples/terminal.ts +305 -0
  124. package/src/examples/text-node-demo.ts +416 -0
  125. package/src/examples/text-selection-demo.ts +377 -0
  126. package/src/examples/text-table-demo.ts +503 -0
  127. package/src/examples/text-truncation-demo.ts +481 -0
  128. package/src/examples/text-wrap.ts +757 -0
  129. package/src/examples/texture-loading-demo.ts +259 -0
  130. package/src/examples/timeline-example.ts +670 -0
  131. package/src/examples/transparency-demo.ts +241 -0
  132. package/src/examples/vnode-composition-demo.ts +404 -0
  133. package/src/index.ts +22 -0
  134. package/src/lib/KeyHandler.integration.test.ts +292 -0
  135. package/src/lib/KeyHandler.stopPropagation.test.ts +289 -0
  136. package/src/lib/KeyHandler.test.ts +662 -0
  137. package/src/lib/KeyHandler.ts +222 -0
  138. package/src/lib/RGBA.test.ts +984 -0
  139. package/src/lib/RGBA.ts +204 -0
  140. package/src/lib/ascii.font.ts +330 -0
  141. package/src/lib/border.test.ts +83 -0
  142. package/src/lib/border.ts +168 -0
  143. package/src/lib/bunfs.test.ts +27 -0
  144. package/src/lib/bunfs.ts +18 -0
  145. package/src/lib/clipboard.test.ts +41 -0
  146. package/src/lib/clipboard.ts +47 -0
  147. package/src/lib/clock.ts +31 -0
  148. package/src/lib/data-paths.test.ts +133 -0
  149. package/src/lib/data-paths.ts +109 -0
  150. package/src/lib/debounce.ts +106 -0
  151. package/src/lib/detect-links.test.ts +98 -0
  152. package/src/lib/detect-links.ts +56 -0
  153. package/src/lib/env.test.ts +228 -0
  154. package/src/lib/env.ts +209 -0
  155. package/src/lib/extmarks-history.ts +51 -0
  156. package/src/lib/extmarks-multiwidth.test.ts +322 -0
  157. package/src/lib/extmarks.test.ts +3457 -0
  158. package/src/lib/extmarks.ts +843 -0
  159. package/src/lib/fonts/block.json +405 -0
  160. package/src/lib/fonts/grid.json +265 -0
  161. package/src/lib/fonts/huge.json +741 -0
  162. package/src/lib/fonts/pallet.json +314 -0
  163. package/src/lib/fonts/shade.json +591 -0
  164. package/src/lib/fonts/slick.json +321 -0
  165. package/src/lib/fonts/tiny.json +69 -0
  166. package/src/lib/hast-styled-text.ts +59 -0
  167. package/src/lib/index.ts +21 -0
  168. package/src/lib/keymapping.test.ts +280 -0
  169. package/src/lib/keymapping.ts +87 -0
  170. package/src/lib/objects-in-viewport.test.ts +787 -0
  171. package/src/lib/objects-in-viewport.ts +153 -0
  172. package/src/lib/output.capture.ts +58 -0
  173. package/src/lib/parse.keypress-kitty.protocol.test.ts +340 -0
  174. package/src/lib/parse.keypress-kitty.test.ts +663 -0
  175. package/src/lib/parse.keypress-kitty.ts +439 -0
  176. package/src/lib/parse.keypress.test.ts +1849 -0
  177. package/src/lib/parse.keypress.ts +397 -0
  178. package/src/lib/parse.mouse.test.ts +552 -0
  179. package/src/lib/parse.mouse.ts +232 -0
  180. package/src/lib/paste.ts +16 -0
  181. package/src/lib/queue.ts +65 -0
  182. package/src/lib/renderable.validations.test.ts +87 -0
  183. package/src/lib/renderable.validations.ts +83 -0
  184. package/src/lib/scroll-acceleration.ts +98 -0
  185. package/src/lib/selection.ts +240 -0
  186. package/src/lib/singleton.ts +28 -0
  187. package/src/lib/stdin-parser.test.ts +1676 -0
  188. package/src/lib/stdin-parser.ts +1248 -0
  189. package/src/lib/styled-text.ts +178 -0
  190. package/src/lib/terminal-capability-detection.test.ts +202 -0
  191. package/src/lib/terminal-capability-detection.ts +79 -0
  192. package/src/lib/terminal-palette.test.ts +878 -0
  193. package/src/lib/terminal-palette.ts +383 -0
  194. package/src/lib/tree-sitter/assets/README.md +118 -0
  195. package/src/lib/tree-sitter/assets/update.ts +331 -0
  196. package/src/lib/tree-sitter/assets.d.ts +9 -0
  197. package/src/lib/tree-sitter/cache.test.ts +270 -0
  198. package/src/lib/tree-sitter/client.test.ts +1061 -0
  199. package/src/lib/tree-sitter/client.ts +615 -0
  200. package/src/lib/tree-sitter/default-parsers.ts +80 -0
  201. package/src/lib/tree-sitter/download-utils.ts +148 -0
  202. package/src/lib/tree-sitter/index.ts +28 -0
  203. package/src/lib/tree-sitter/parser.worker.ts +1001 -0
  204. package/src/lib/tree-sitter/parsers-config.ts +75 -0
  205. package/src/lib/tree-sitter/resolve-ft.ts +62 -0
  206. package/src/lib/tree-sitter/types.ts +81 -0
  207. package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
  208. package/src/lib/tree-sitter-styled-text.ts +306 -0
  209. package/src/lib/validate-dir-name.ts +55 -0
  210. package/src/lib/yoga.options.test.ts +628 -0
  211. package/src/lib/yoga.options.ts +346 -0
  212. package/src/plugins/core-slot.ts +579 -0
  213. package/src/plugins/registry.ts +377 -0
  214. package/src/plugins/types.ts +46 -0
  215. package/src/post/filters.ts +888 -0
  216. package/src/renderables/ASCIIFont.ts +219 -0
  217. package/src/renderables/Box.test.ts +160 -0
  218. package/src/renderables/Box.ts +295 -0
  219. package/src/renderables/Code.test.ts +2062 -0
  220. package/src/renderables/Code.ts +357 -0
  221. package/src/renderables/Diff.regression.test.ts +226 -0
  222. package/src/renderables/Diff.test.ts +3027 -0
  223. package/src/renderables/Diff.ts +1209 -0
  224. package/src/renderables/EditBufferRenderable.ts +764 -0
  225. package/src/renderables/FrameBuffer.ts +47 -0
  226. package/src/renderables/Input.test.ts +1228 -0
  227. package/src/renderables/Input.ts +245 -0
  228. package/src/renderables/LineNumberRenderable.ts +675 -0
  229. package/src/renderables/Markdown.ts +1106 -0
  230. package/src/renderables/ScrollBar.ts +422 -0
  231. package/src/renderables/ScrollBox.ts +883 -0
  232. package/src/renderables/Select.test.ts +1010 -0
  233. package/src/renderables/Select.ts +523 -0
  234. package/src/renderables/Slider.test.ts +456 -0
  235. package/src/renderables/Slider.ts +347 -0
  236. package/src/renderables/TabSelect.test.ts +197 -0
  237. package/src/renderables/TabSelect.ts +455 -0
  238. package/src/renderables/Text.selection-buffer.test.ts +123 -0
  239. package/src/renderables/Text.test.ts +2660 -0
  240. package/src/renderables/Text.ts +147 -0
  241. package/src/renderables/TextBufferRenderable.ts +518 -0
  242. package/src/renderables/TextNode.test.ts +1058 -0
  243. package/src/renderables/TextNode.ts +325 -0
  244. package/src/renderables/TextTable.test.ts +1421 -0
  245. package/src/renderables/TextTable.ts +1344 -0
  246. package/src/renderables/Textarea.ts +732 -0
  247. package/src/renderables/TimeToFirstDraw.ts +89 -0
  248. package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
  249. package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
  250. package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
  251. package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
  252. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
  253. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +816 -0
  254. package/src/renderables/__tests__/LineNumberRenderable.test.ts +1787 -0
  255. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
  256. package/src/renderables/__tests__/Markdown.test.ts +2287 -0
  257. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
  258. package/src/renderables/__tests__/Textarea.buffer.test.ts +682 -0
  259. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
  260. package/src/renderables/__tests__/Textarea.editing.test.ts +2041 -0
  261. package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
  262. package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
  263. package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
  264. package/src/renderables/__tests__/Textarea.keybinding.test.ts +3149 -0
  265. package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
  266. package/src/renderables/__tests__/Textarea.rendering.test.ts +1864 -0
  267. package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
  268. package/src/renderables/__tests__/Textarea.selection.test.ts +1590 -0
  269. package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
  270. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
  271. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
  272. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
  273. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
  274. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
  275. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
  276. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
  277. package/src/renderables/__tests__/markdown-parser.test.ts +217 -0
  278. package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
  279. package/src/renderables/composition/README.md +8 -0
  280. package/src/renderables/composition/VRenderable.ts +32 -0
  281. package/src/renderables/composition/constructs.ts +127 -0
  282. package/src/renderables/composition/vnode.ts +289 -0
  283. package/src/renderables/index.ts +22 -0
  284. package/src/renderables/markdown-parser.ts +66 -0
  285. package/src/renderer.ts +2363 -0
  286. package/src/runtime-plugin-support.ts +39 -0
  287. package/src/runtime-plugin.ts +144 -0
  288. package/src/syntax-style.test.ts +841 -0
  289. package/src/syntax-style.ts +264 -0
  290. package/src/testing/README.md +210 -0
  291. package/src/testing/capture-spans.test.ts +194 -0
  292. package/src/testing/integration.test.ts +276 -0
  293. package/src/testing/manual-clock.ts +106 -0
  294. package/src/testing/mock-keys.test.ts +1356 -0
  295. package/src/testing/mock-keys.ts +449 -0
  296. package/src/testing/mock-mouse.test.ts +218 -0
  297. package/src/testing/mock-mouse.ts +247 -0
  298. package/src/testing/mock-tree-sitter-client.ts +73 -0
  299. package/src/testing/spy.ts +13 -0
  300. package/src/testing/test-recorder.test.ts +415 -0
  301. package/src/testing/test-recorder.ts +145 -0
  302. package/src/testing/test-renderer.ts +116 -0
  303. package/src/testing.ts +7 -0
  304. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
  305. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
  306. package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
  307. package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
  308. package/src/tests/allocator-stats.test.ts +38 -0
  309. package/src/tests/destroy-during-render.test.ts +200 -0
  310. package/src/tests/hover-cursor.test.ts +98 -0
  311. package/src/tests/native-span-feed-async.test.ts +173 -0
  312. package/src/tests/native-span-feed-close.test.ts +120 -0
  313. package/src/tests/native-span-feed-coverage.test.ts +227 -0
  314. package/src/tests/native-span-feed-edge-cases.test.ts +352 -0
  315. package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
  316. package/src/tests/opacity.test.ts +123 -0
  317. package/src/tests/renderable.snapshot.test.ts +524 -0
  318. package/src/tests/renderable.test.ts +1281 -0
  319. package/src/tests/renderer.console-startup.test.ts +65 -0
  320. package/src/tests/renderer.control.test.ts +364 -0
  321. package/src/tests/renderer.core-slot-binding.test.ts +952 -0
  322. package/src/tests/renderer.cursor.test.ts +26 -0
  323. package/src/tests/renderer.destroy-during-render.test.ts +110 -0
  324. package/src/tests/renderer.focus-restore.test.ts +228 -0
  325. package/src/tests/renderer.focus.test.ts +251 -0
  326. package/src/tests/renderer.idle.test.ts +219 -0
  327. package/src/tests/renderer.input.test.ts +2145 -0
  328. package/src/tests/renderer.kitty-flags.test.ts +195 -0
  329. package/src/tests/renderer.mouse.test.ts +1269 -0
  330. package/src/tests/renderer.palette.test.ts +629 -0
  331. package/src/tests/renderer.selection.test.ts +49 -0
  332. package/src/tests/renderer.slot-registry.test.ts +649 -0
  333. package/src/tests/renderer.useMouse.test.ts +50 -0
  334. package/src/tests/runtime-plugin-support.fixture.ts +11 -0
  335. package/src/tests/runtime-plugin-support.test.ts +28 -0
  336. package/src/tests/runtime-plugin.fixture.ts +40 -0
  337. package/src/tests/runtime-plugin.test.ts +190 -0
  338. package/src/tests/scrollbox-culling-bug.test.ts +114 -0
  339. package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
  340. package/src/tests/scrollbox-hitgrid.test.ts +909 -0
  341. package/src/tests/scrollbox.test.ts +1530 -0
  342. package/src/tests/wrap-resize-perf.test.ts +229 -0
  343. package/src/tests/yoga-setters.test.ts +921 -0
  344. package/src/text-buffer-view.test.ts +705 -0
  345. package/src/text-buffer-view.ts +189 -0
  346. package/src/text-buffer.test.ts +347 -0
  347. package/src/text-buffer.ts +250 -0
  348. package/src/types.ts +152 -0
  349. package/src/utils.ts +88 -0
  350. package/src/zig/ansi.zig +268 -0
  351. package/src/zig/bench/README.md +50 -0
  352. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +887 -0
  353. package/src/zig/bench/edit-buffer_bench.zig +476 -0
  354. package/src/zig/bench/native-span-feed_bench.zig +100 -0
  355. package/src/zig/bench/rope-markers_bench.zig +713 -0
  356. package/src/zig/bench/rope_bench.zig +514 -0
  357. package/src/zig/bench/styled-text_bench.zig +470 -0
  358. package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
  359. package/src/zig/bench/text-buffer-view_bench.zig +459 -0
  360. package/src/zig/bench/text-chunk-graphemes_bench.zig +273 -0
  361. package/src/zig/bench/utf8_bench.zig +799 -0
  362. package/src/zig/bench-utils.zig +431 -0
  363. package/src/zig/bench.zig +217 -0
  364. package/src/zig/buffer.zig +2223 -0
  365. package/src/zig/build.zig +289 -0
  366. package/src/zig/build.zig.zon +16 -0
  367. package/src/zig/edit-buffer.zig +825 -0
  368. package/src/zig/editor-view.zig +802 -0
  369. package/src/zig/event-bus.zig +13 -0
  370. package/src/zig/event-emitter.zig +65 -0
  371. package/src/zig/file-logger.zig +92 -0
  372. package/src/zig/grapheme.zig +599 -0
  373. package/src/zig/lib.zig +1834 -0
  374. package/src/zig/link.zig +333 -0
  375. package/src/zig/logger.zig +43 -0
  376. package/src/zig/mem-registry.zig +125 -0
  377. package/src/zig/native-span-feed-bench-lib.zig +7 -0
  378. package/src/zig/native-span-feed.zig +708 -0
  379. package/src/zig/renderer.zig +1386 -0
  380. package/src/zig/rope.zig +1220 -0
  381. package/src/zig/syntax-style.zig +161 -0
  382. package/src/zig/terminal.zig +975 -0
  383. package/src/zig/test.zig +70 -0
  384. package/src/zig/tests/README.md +18 -0
  385. package/src/zig/tests/buffer_test.zig +2526 -0
  386. package/src/zig/tests/edit-buffer-history_test.zig +271 -0
  387. package/src/zig/tests/edit-buffer_test.zig +1689 -0
  388. package/src/zig/tests/editor-view_test.zig +3299 -0
  389. package/src/zig/tests/event-emitter_test.zig +249 -0
  390. package/src/zig/tests/grapheme_test.zig +1304 -0
  391. package/src/zig/tests/link_test.zig +190 -0
  392. package/src/zig/tests/mem-registry_test.zig +473 -0
  393. package/src/zig/tests/memory_leak_regression_test.zig +159 -0
  394. package/src/zig/tests/native-span-feed_test.zig +1264 -0
  395. package/src/zig/tests/renderer_test.zig +1010 -0
  396. package/src/zig/tests/rope-nested_test.zig +712 -0
  397. package/src/zig/tests/rope_fuzz_test.zig +238 -0
  398. package/src/zig/tests/rope_test.zig +2362 -0
  399. package/src/zig/tests/segment-merge.test.zig +148 -0
  400. package/src/zig/tests/syntax-style_test.zig +557 -0
  401. package/src/zig/tests/terminal_test.zig +719 -0
  402. package/src/zig/tests/text-buffer-drawing_test.zig +3237 -0
  403. package/src/zig/tests/text-buffer-highlights_test.zig +666 -0
  404. package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
  405. package/src/zig/tests/text-buffer-segment_test.zig +320 -0
  406. package/src/zig/tests/text-buffer-selection_test.zig +1035 -0
  407. package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
  408. package/src/zig/tests/text-buffer-view_test.zig +3649 -0
  409. package/src/zig/tests/text-buffer_test.zig +2191 -0
  410. package/src/zig/tests/unicode-width-map.zon +3909 -0
  411. package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
  412. package/src/zig/tests/utf8_test.zig +4057 -0
  413. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
  414. package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
  415. package/src/zig/tests/word-wrap-editing_test.zig +498 -0
  416. package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
  417. package/src/zig/text-buffer-iterators.zig +499 -0
  418. package/src/zig/text-buffer-segment.zig +404 -0
  419. package/src/zig/text-buffer-view.zig +1371 -0
  420. package/src/zig/text-buffer.zig +1180 -0
  421. package/src/zig/utf8.zig +1948 -0
  422. package/src/zig/utils.zig +9 -0
  423. package/src/zig-structs.ts +261 -0
  424. package/src/zig.ts +3843 -0
  425. package/tsconfig.build.json +22 -0
  426. package/tsconfig.json +28 -0
  427. package/3d/SpriteResourceManager.d.ts +0 -74
  428. package/3d/SpriteUtils.d.ts +0 -13
  429. package/3d/TextureUtils.d.ts +0 -24
  430. package/3d/ThreeRenderable.d.ts +0 -40
  431. package/3d/WGPURenderer.d.ts +0 -61
  432. package/3d/animation/ExplodingSpriteEffect.d.ts +0 -71
  433. package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +0 -76
  434. package/3d/animation/SpriteAnimator.d.ts +0 -124
  435. package/3d/animation/SpriteParticleGenerator.d.ts +0 -62
  436. package/3d/canvas.d.ts +0 -44
  437. package/3d/index.d.ts +0 -12
  438. package/3d/physics/PlanckPhysicsAdapter.d.ts +0 -19
  439. package/3d/physics/RapierPhysicsAdapter.d.ts +0 -19
  440. package/3d/physics/physics-interface.d.ts +0 -27
  441. package/3d.d.ts +0 -2
  442. package/3d.js +0 -34042
  443. package/3d.js.map +0 -155
  444. package/LICENSE +0 -21
  445. package/NativeSpanFeed.d.ts +0 -41
  446. package/Renderable.d.ts +0 -334
  447. package/animation/Timeline.d.ts +0 -126
  448. package/ansi.d.ts +0 -13
  449. package/buffer.d.ts +0 -107
  450. package/console.d.ts +0 -143
  451. package/edit-buffer.d.ts +0 -98
  452. package/editor-view.d.ts +0 -73
  453. package/index-e4hzc2j2.js +0 -113
  454. package/index-e4hzc2j2.js.map +0 -10
  455. package/index-nkrr8a4c.js +0 -18415
  456. package/index-nkrr8a4c.js.map +0 -64
  457. package/index-nyw5p3ep.js +0 -12619
  458. package/index-nyw5p3ep.js.map +0 -43
  459. package/index.d.ts +0 -21
  460. package/index.js +0 -430
  461. package/index.js.map +0 -9
  462. package/lib/KeyHandler.d.ts +0 -61
  463. package/lib/RGBA.d.ts +0 -25
  464. package/lib/ascii.font.d.ts +0 -508
  465. package/lib/border.d.ts +0 -49
  466. package/lib/bunfs.d.ts +0 -7
  467. package/lib/clipboard.d.ts +0 -17
  468. package/lib/clock.d.ts +0 -15
  469. package/lib/data-paths.d.ts +0 -26
  470. package/lib/debounce.d.ts +0 -42
  471. package/lib/detect-links.d.ts +0 -6
  472. package/lib/env.d.ts +0 -42
  473. package/lib/extmarks-history.d.ts +0 -17
  474. package/lib/extmarks.d.ts +0 -89
  475. package/lib/hast-styled-text.d.ts +0 -17
  476. package/lib/index.d.ts +0 -21
  477. package/lib/keymapping.d.ts +0 -25
  478. package/lib/objects-in-viewport.d.ts +0 -24
  479. package/lib/output.capture.d.ts +0 -24
  480. package/lib/parse.keypress-kitty.d.ts +0 -2
  481. package/lib/parse.keypress.d.ts +0 -26
  482. package/lib/parse.mouse.d.ts +0 -30
  483. package/lib/paste.d.ts +0 -7
  484. package/lib/queue.d.ts +0 -15
  485. package/lib/renderable.validations.d.ts +0 -12
  486. package/lib/scroll-acceleration.d.ts +0 -43
  487. package/lib/selection.d.ts +0 -63
  488. package/lib/singleton.d.ts +0 -7
  489. package/lib/stdin-parser.d.ts +0 -76
  490. package/lib/styled-text.d.ts +0 -63
  491. package/lib/terminal-capability-detection.d.ts +0 -30
  492. package/lib/terminal-palette.d.ts +0 -50
  493. package/lib/tree-sitter/assets/update.d.ts +0 -11
  494. package/lib/tree-sitter/client.d.ts +0 -47
  495. package/lib/tree-sitter/default-parsers.d.ts +0 -2
  496. package/lib/tree-sitter/download-utils.d.ts +0 -21
  497. package/lib/tree-sitter/index.d.ts +0 -8
  498. package/lib/tree-sitter/parser.worker.d.ts +0 -1
  499. package/lib/tree-sitter/parsers-config.d.ts +0 -38
  500. package/lib/tree-sitter/resolve-ft.d.ts +0 -2
  501. package/lib/tree-sitter/types.d.ts +0 -81
  502. package/lib/tree-sitter-styled-text.d.ts +0 -14
  503. package/lib/validate-dir-name.d.ts +0 -1
  504. package/lib/yoga.options.d.ts +0 -32
  505. package/parser.worker.js +0 -869
  506. package/parser.worker.js.map +0 -12
  507. package/plugins/core-slot.d.ts +0 -72
  508. package/plugins/registry.d.ts +0 -38
  509. package/plugins/types.d.ts +0 -34
  510. package/post/filters.d.ts +0 -105
  511. package/renderables/ASCIIFont.d.ts +0 -52
  512. package/renderables/Box.d.ts +0 -72
  513. package/renderables/Code.d.ts +0 -78
  514. package/renderables/Diff.d.ts +0 -142
  515. package/renderables/EditBufferRenderable.d.ts +0 -162
  516. package/renderables/FrameBuffer.d.ts +0 -16
  517. package/renderables/Input.d.ts +0 -67
  518. package/renderables/LineNumberRenderable.d.ts +0 -74
  519. package/renderables/Markdown.d.ts +0 -173
  520. package/renderables/ScrollBar.d.ts +0 -77
  521. package/renderables/ScrollBox.d.ts +0 -124
  522. package/renderables/Select.d.ts +0 -115
  523. package/renderables/Slider.d.ts +0 -44
  524. package/renderables/TabSelect.d.ts +0 -96
  525. package/renderables/Text.d.ts +0 -36
  526. package/renderables/TextBufferRenderable.d.ts +0 -105
  527. package/renderables/TextNode.d.ts +0 -91
  528. package/renderables/TextTable.d.ts +0 -140
  529. package/renderables/Textarea.d.ts +0 -114
  530. package/renderables/TimeToFirstDraw.d.ts +0 -24
  531. package/renderables/__tests__/renderable-test-utils.d.ts +0 -12
  532. package/renderables/composition/VRenderable.d.ts +0 -16
  533. package/renderables/composition/constructs.d.ts +0 -35
  534. package/renderables/composition/vnode.d.ts +0 -46
  535. package/renderables/index.d.ts +0 -22
  536. package/renderables/markdown-parser.d.ts +0 -10
  537. package/renderer.d.ts +0 -388
  538. package/runtime-plugin-support.d.ts +0 -3
  539. package/runtime-plugin-support.js +0 -29
  540. package/runtime-plugin-support.js.map +0 -10
  541. package/runtime-plugin.d.ts +0 -11
  542. package/runtime-plugin.js +0 -16
  543. package/runtime-plugin.js.map +0 -9
  544. package/syntax-style.d.ts +0 -54
  545. package/testing/manual-clock.d.ts +0 -16
  546. package/testing/mock-keys.d.ts +0 -81
  547. package/testing/mock-mouse.d.ts +0 -38
  548. package/testing/mock-tree-sitter-client.d.ts +0 -23
  549. package/testing/spy.d.ts +0 -7
  550. package/testing/test-recorder.d.ts +0 -61
  551. package/testing/test-renderer.d.ts +0 -23
  552. package/testing.d.ts +0 -6
  553. package/testing.js +0 -675
  554. package/testing.js.map +0 -15
  555. package/text-buffer-view.d.ts +0 -42
  556. package/text-buffer.d.ts +0 -67
  557. package/types.d.ts +0 -131
  558. package/utils.d.ts +0 -14
  559. package/zig-structs.d.ts +0 -155
  560. package/zig.d.ts +0 -351
  561. /package/{assets → src/lib/tree-sitter/assets}/javascript/highlights.scm +0 -0
  562. /package/{assets → src/lib/tree-sitter/assets}/javascript/tree-sitter-javascript.wasm +0 -0
  563. /package/{assets → src/lib/tree-sitter/assets}/markdown/highlights.scm +0 -0
  564. /package/{assets → src/lib/tree-sitter/assets}/markdown/injections.scm +0 -0
  565. /package/{assets → src/lib/tree-sitter/assets}/markdown/tree-sitter-markdown.wasm +0 -0
  566. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/highlights.scm +0 -0
  567. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  568. /package/{assets → src/lib/tree-sitter/assets}/typescript/highlights.scm +0 -0
  569. /package/{assets → src/lib/tree-sitter/assets}/typescript/tree-sitter-typescript.wasm +0 -0
  570. /package/{assets → src/lib/tree-sitter/assets}/zig/highlights.scm +0 -0
  571. /package/{assets → src/lib/tree-sitter/assets}/zig/tree-sitter-zig.wasm +0 -0
@@ -0,0 +1,947 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import {
4
+ TextTableRenderable,
5
+ type TextTableCellContent,
6
+ type TextTableColumnFitter,
7
+ type TextTableColumnWidthMode,
8
+ type TextTableContent,
9
+ type CliRenderer,
10
+ } from "../index"
11
+ import { createTestRenderer } from "../testing"
12
+ import { Command } from "commander"
13
+ import { existsSync } from "node:fs"
14
+ import { mkdir } from "node:fs/promises"
15
+ import path from "node:path"
16
+
17
+ const realStdoutWrite = process.stdout.write.bind(process.stdout)
18
+
19
+ const WORDS = [
20
+ "alpha",
21
+ "bravo",
22
+ "charlie",
23
+ "delta",
24
+ "echo",
25
+ "foxtrot",
26
+ "golf",
27
+ "hotel",
28
+ "india",
29
+ "juliet",
30
+ "kilo",
31
+ "lima",
32
+ "mango",
33
+ "nectar",
34
+ "oscar",
35
+ "papa",
36
+ "quartz",
37
+ "romeo",
38
+ "sierra",
39
+ "tango",
40
+ "uniform",
41
+ "vector",
42
+ "whiskey",
43
+ "xray",
44
+ "yankee",
45
+ "zulu",
46
+ "matrix",
47
+ "signal",
48
+ "tensor",
49
+ "render",
50
+ "schema",
51
+ "buffer",
52
+ "layout",
53
+ "stream",
54
+ "parser",
55
+ "syntax",
56
+ "viewport",
57
+ "cursor",
58
+ ]
59
+
60
+ type MemorySample = {
61
+ rss: number
62
+ heapTotal: number
63
+ heapUsed: number
64
+ external: number
65
+ arrayBuffers: number
66
+ }
67
+
68
+ type MemoryStats = {
69
+ samples: number
70
+ start: MemorySample
71
+ end: MemorySample
72
+ delta: MemorySample
73
+ peak: MemorySample
74
+ }
75
+
76
+ type TimingStats = {
77
+ count: number
78
+ averageMs: number
79
+ medianMs: number
80
+ p95Ms: number
81
+ minMs: number
82
+ maxMs: number
83
+ stdDevMs: number
84
+ }
85
+
86
+ type ScenarioResult = {
87
+ name: string
88
+ description: string
89
+ category: "replace" | "incremental" | "selection"
90
+ timingMode: "content-set-and-render" | "selection-update-and-render"
91
+ iterations: number
92
+ warmupIterations: number
93
+ elapsedMs: number
94
+ updateStats: TimingStats
95
+ memoryStats?: MemoryStats
96
+ tableStats: {
97
+ initialRows: number
98
+ finalRows: number
99
+ maxRows: number
100
+ columns: number
101
+ updates: number
102
+ datasetVariants: number
103
+ }
104
+ settings: Record<string, unknown>
105
+ }
106
+
107
+ type ReplaceScenarioPlan = {
108
+ kind: "replace"
109
+ name: string
110
+ description: string
111
+ iterations: number
112
+ warmupIterations: number
113
+ rows: number
114
+ cols: number
115
+ variants: TextTableContent[]
116
+ tableConfig: BenchmarkTableConfig
117
+ }
118
+
119
+ type IncrementalScenarioPlan = {
120
+ kind: "incremental"
121
+ name: string
122
+ description: string
123
+ iterations: number
124
+ warmupIterations: number
125
+ cols: number
126
+ header: TextTableCellContent[]
127
+ baseRows: TextTableCellContent[][]
128
+ rowPool: TextTableCellContent[][]
129
+ maxRows: number
130
+ tableConfig: BenchmarkTableConfig
131
+ }
132
+
133
+ type SelectionScenarioPlan = {
134
+ kind: "selection"
135
+ name: string
136
+ description: string
137
+ iterations: number
138
+ warmupIterations: number
139
+ rows: number
140
+ cols: number
141
+ content: TextTableContent
142
+ dragSteps: number
143
+ tableConfig: BenchmarkTableConfig
144
+ }
145
+
146
+ type ScenarioPlan = ReplaceScenarioPlan | IncrementalScenarioPlan | SelectionScenarioPlan
147
+
148
+ type BenchmarkTableConfig = {
149
+ wrapMode: "none" | "char" | "word"
150
+ columnWidthMode: TextTableColumnWidthMode
151
+ columnFitter: TextTableColumnFitter
152
+ }
153
+
154
+ type RunContext = {
155
+ renderer: CliRenderer
156
+ table: TextTableRenderable
157
+ renderOnce: () => Promise<void>
158
+ memSampleEvery: number
159
+ }
160
+
161
+ type SuiteConfig = {
162
+ iterations: number
163
+ warmupIterations: number
164
+ longIterations: number
165
+ scale: number
166
+ }
167
+
168
+ type OutputMeta = {
169
+ suiteName: string
170
+ width: number
171
+ height: number
172
+ iterations: number
173
+ warmupIterations: number
174
+ longIterations: number
175
+ scale: number
176
+ seed: number
177
+ memSampleEvery: number
178
+ }
179
+
180
+ type IncrementalState = {
181
+ rows: TextTableCellContent[][]
182
+ cursor: number
183
+ maxRowsSeen: number
184
+ }
185
+
186
+ const program = new Command()
187
+ program
188
+ .name("text-table-benchmark")
189
+ .description("TextTableRenderable benchmark scenarios")
190
+ .option("-s, --suite <name>", "benchmark suite: quick, default, long", "default")
191
+ .option("-i, --iterations <count>", "iterations per scenario", "800")
192
+ .option("--warmup-iterations <count>", "warmup iterations per scenario", "80")
193
+ .option("--long-iterations <count>", "iterations for long suite", "3000")
194
+ .option("--scale <n>", "scale rows and dataset size", "1")
195
+ .option("--seed <n>", "seed for deterministic content", "1337")
196
+ .option("--width <n>", "test renderer width", "140")
197
+ .option("--height <n>", "test renderer height", "48")
198
+ .option("--mem-sample-every <count>", "sample memory every N iterations (0 disables)", "10")
199
+ .option("--scenario <name>", "run a single scenario")
200
+ .option("--json [path]", "write JSON results to file")
201
+ .option("--no-output", "suppress stdout output")
202
+ .parse(process.argv)
203
+
204
+ const options = program.opts()
205
+
206
+ const suiteName = String(options.suite)
207
+ const iterations = Math.max(1, Math.floor(toNumber(options.iterations, 800)))
208
+ const warmupIterations = Math.max(0, Math.floor(toNumber(options.warmupIterations, 80)))
209
+ const longIterations = Math.max(iterations, Math.floor(toNumber(options.longIterations, 3000)))
210
+ const scale = Math.max(0.25, toNumber(options.scale, 1))
211
+ const seed = Math.max(1, Math.floor(toNumber(options.seed, 1337)))
212
+ const width = Math.max(40, Math.floor(toNumber(options.width, 140)))
213
+ const height = Math.max(12, Math.floor(toNumber(options.height, 48)))
214
+ const memSampleEvery = Math.max(0, Math.floor(toNumber(options.memSampleEvery, 10)))
215
+ const scenarioFilter = options.scenario ? String(options.scenario) : null
216
+ const outputEnabled = options.output !== false
217
+
218
+ const PROPORTIONAL_TABLE_CONFIG: BenchmarkTableConfig = {
219
+ wrapMode: "word",
220
+ columnWidthMode: "full",
221
+ columnFitter: "proportional",
222
+ }
223
+
224
+ const BALANCED_TABLE_CONFIG: BenchmarkTableConfig = {
225
+ wrapMode: "word",
226
+ columnWidthMode: "full",
227
+ columnFitter: "balanced",
228
+ }
229
+
230
+ const jsonArg = options.json
231
+ const jsonPath =
232
+ typeof jsonArg === "string"
233
+ ? path.resolve(process.cwd(), jsonArg)
234
+ : jsonArg
235
+ ? path.resolve(process.cwd(), "latest-text-table-bench-run.json")
236
+ : null
237
+
238
+ if (jsonPath) {
239
+ const dir = path.dirname(jsonPath)
240
+ if (!existsSync(dir)) {
241
+ await mkdir(dir, { recursive: true })
242
+ }
243
+ if (existsSync(jsonPath)) {
244
+ console.error(`Error: output file already exists: ${jsonPath}`)
245
+ process.exit(1)
246
+ }
247
+ }
248
+
249
+ const scenarios = createScenarios(
250
+ suiteName,
251
+ {
252
+ iterations,
253
+ warmupIterations,
254
+ longIterations,
255
+ scale,
256
+ },
257
+ seed,
258
+ )
259
+
260
+ if (scenarios.length === 0) {
261
+ console.error(`Unknown suite: ${suiteName}`)
262
+ process.exit(1)
263
+ }
264
+
265
+ const filteredScenarios = scenarioFilter ? scenarios.filter((scenario) => scenario.name === scenarioFilter) : scenarios
266
+
267
+ if (scenarioFilter && filteredScenarios.length === 0) {
268
+ writeLine(`Unknown scenario: ${scenarioFilter}`)
269
+ process.exit(1)
270
+ }
271
+
272
+ const { renderer, renderOnce } = await createTestRenderer({
273
+ width,
274
+ height,
275
+ useAlternateScreen: false,
276
+ useConsole: false,
277
+ })
278
+
279
+ renderer.requestRender = () => {}
280
+
281
+ const table = new TextTableRenderable(renderer, {
282
+ id: "text-table-bench",
283
+ width: "100%",
284
+ wrapMode: PROPORTIONAL_TABLE_CONFIG.wrapMode,
285
+ columnWidthMode: PROPORTIONAL_TABLE_CONFIG.columnWidthMode,
286
+ columnFitter: PROPORTIONAL_TABLE_CONFIG.columnFitter,
287
+ content: [],
288
+ })
289
+
290
+ renderer.root.add(table)
291
+ await renderOnce()
292
+
293
+ const ctx: RunContext = {
294
+ renderer,
295
+ table,
296
+ renderOnce,
297
+ memSampleEvery,
298
+ }
299
+
300
+ const results: ScenarioResult[] = []
301
+ const scenarioLines: string[] = []
302
+
303
+ try {
304
+ for (const plan of filteredScenarios) {
305
+ const result = await runScenario(plan, ctx)
306
+ results.push(result)
307
+ scenarioLines.push(formatScenarioResult(result))
308
+ }
309
+ } finally {
310
+ renderer.destroy()
311
+ }
312
+
313
+ await outputResults(
314
+ {
315
+ suiteName,
316
+ width,
317
+ height,
318
+ iterations,
319
+ warmupIterations,
320
+ longIterations,
321
+ scale,
322
+ seed,
323
+ memSampleEvery,
324
+ },
325
+ results,
326
+ scenarioLines,
327
+ outputEnabled,
328
+ jsonPath,
329
+ )
330
+
331
+ function createScenarios(suite: string, config: SuiteConfig, runSeed: number): ScenarioPlan[] {
332
+ const quick = {
333
+ replaceRows: scaled(24, config.scale),
334
+ replaceCols: 4,
335
+ replaceVariants: scaled(6, config.scale),
336
+ incrementalCols: 4,
337
+ incrementalBaseRows: scaled(8, config.scale),
338
+ incrementalPoolRows: scaled(220, config.scale),
339
+ incrementalMaxRows: scaled(120, config.scale),
340
+ }
341
+
342
+ const defaultSuite = {
343
+ replaceRows: scaled(72, config.scale),
344
+ replaceCols: 6,
345
+ replaceVariants: scaled(10, config.scale),
346
+ incrementalCols: 6,
347
+ incrementalBaseRows: scaled(16, config.scale),
348
+ incrementalPoolRows: scaled(480, config.scale),
349
+ incrementalMaxRows: scaled(320, config.scale),
350
+ }
351
+
352
+ const long = {
353
+ replaceRows: scaled(140, config.scale),
354
+ replaceCols: 8,
355
+ replaceVariants: scaled(14, config.scale),
356
+ incrementalCols: 8,
357
+ incrementalBaseRows: scaled(24, config.scale),
358
+ incrementalPoolRows: scaled(960, config.scale),
359
+ incrementalMaxRows: scaled(720, config.scale),
360
+ }
361
+
362
+ let shape: typeof quick
363
+ let runIterations = config.iterations
364
+
365
+ if (suite === "quick") {
366
+ shape = quick
367
+ } else if (suite === "default") {
368
+ shape = defaultSuite
369
+ } else if (suite === "long") {
370
+ shape = long
371
+ runIterations = config.longIterations
372
+ } else {
373
+ return []
374
+ }
375
+
376
+ const replaceRng = createRng((runSeed ^ 0x9e3779b9) >>> 0)
377
+ const variants: TextTableContent[] = []
378
+ for (let i = 0; i < shape.replaceVariants; i += 1) {
379
+ variants.push(buildTableContent(replaceRng, shape.replaceRows, shape.replaceCols))
380
+ }
381
+
382
+ const incrementalRng = createRng((runSeed ^ 0x85ebca6b) >>> 0)
383
+ const header = makeHeader(shape.incrementalCols)
384
+ const baseRows = buildRows(incrementalRng, shape.incrementalBaseRows, shape.incrementalCols, 0)
385
+ const rowPool = buildRows(
386
+ incrementalRng,
387
+ Math.max(shape.incrementalPoolRows, shape.incrementalBaseRows + 1),
388
+ shape.incrementalCols,
389
+ shape.incrementalBaseRows,
390
+ )
391
+
392
+ const replaceScenario: ReplaceScenarioPlan = {
393
+ kind: "replace",
394
+ name: "replace_tables",
395
+ description: "Replace full table content with prebuilt variants",
396
+ iterations: runIterations,
397
+ warmupIterations: config.warmupIterations,
398
+ rows: shape.replaceRows,
399
+ cols: shape.replaceCols,
400
+ variants,
401
+ tableConfig: PROPORTIONAL_TABLE_CONFIG,
402
+ }
403
+
404
+ const balancedFitterReplaceScenario: ReplaceScenarioPlan = {
405
+ kind: "replace",
406
+ name: "replace_tables_balanced_fitter",
407
+ description: "Replace full table content with prebuilt variants (balanced fitter)",
408
+ iterations: runIterations,
409
+ warmupIterations: config.warmupIterations,
410
+ rows: shape.replaceRows,
411
+ cols: shape.replaceCols,
412
+ variants,
413
+ tableConfig: BALANCED_TABLE_CONFIG,
414
+ }
415
+
416
+ const incrementalScenario: IncrementalScenarioPlan = {
417
+ kind: "incremental",
418
+ name: "incremental_table_rows",
419
+ description: "Append table rows and periodically reset to base size",
420
+ iterations: runIterations,
421
+ warmupIterations: config.warmupIterations,
422
+ cols: shape.incrementalCols,
423
+ header,
424
+ baseRows,
425
+ rowPool,
426
+ maxRows: Math.max(shape.incrementalMaxRows, shape.incrementalBaseRows + 1),
427
+ tableConfig: PROPORTIONAL_TABLE_CONFIG,
428
+ }
429
+
430
+ const balancedFitterIncrementalScenario: IncrementalScenarioPlan = {
431
+ kind: "incremental",
432
+ name: "incremental_table_rows_balanced_fitter",
433
+ description: "Append table rows and periodically reset to base size (balanced fitter)",
434
+ iterations: runIterations,
435
+ warmupIterations: config.warmupIterations,
436
+ cols: shape.incrementalCols,
437
+ header,
438
+ baseRows,
439
+ rowPool,
440
+ maxRows: Math.max(shape.incrementalMaxRows, shape.incrementalBaseRows + 1),
441
+ tableConfig: BALANCED_TABLE_CONFIG,
442
+ }
443
+
444
+ const selectionRng = createRng((runSeed ^ 0xa2f9c6d1) >>> 0)
445
+ const selectionContent = buildTableContent(selectionRng, shape.replaceRows, shape.replaceCols)
446
+
447
+ const selectionScenario: SelectionScenarioPlan = {
448
+ kind: "selection",
449
+ name: "selection_update",
450
+ description: "Update selection focus across rows and render",
451
+ iterations: runIterations,
452
+ warmupIterations: config.warmupIterations,
453
+ rows: shape.replaceRows,
454
+ cols: shape.replaceCols,
455
+ content: selectionContent,
456
+ dragSteps: 5,
457
+ tableConfig: PROPORTIONAL_TABLE_CONFIG,
458
+ }
459
+
460
+ const balancedFitterSelectionScenario: SelectionScenarioPlan = {
461
+ kind: "selection",
462
+ name: "selection_update_balanced_fitter",
463
+ description: "Update selection focus across rows and render (balanced fitter)",
464
+ iterations: runIterations,
465
+ warmupIterations: config.warmupIterations,
466
+ rows: shape.replaceRows,
467
+ cols: shape.replaceCols,
468
+ content: selectionContent,
469
+ dragSteps: 5,
470
+ tableConfig: BALANCED_TABLE_CONFIG,
471
+ }
472
+
473
+ return [
474
+ replaceScenario,
475
+ balancedFitterReplaceScenario,
476
+ incrementalScenario,
477
+ balancedFitterIncrementalScenario,
478
+ selectionScenario,
479
+ balancedFitterSelectionScenario,
480
+ ]
481
+ }
482
+
483
+ async function runScenario(plan: ScenarioPlan, ctx: RunContext): Promise<ScenarioResult> {
484
+ if (plan.kind === "replace") {
485
+ return runReplaceScenario(plan, ctx)
486
+ }
487
+ if (plan.kind === "incremental") {
488
+ return runIncrementalScenario(plan, ctx)
489
+ }
490
+ return runSelectionScenario(plan, ctx)
491
+ }
492
+
493
+ function applyTableConfig(table: TextTableRenderable, config: BenchmarkTableConfig): void {
494
+ table.wrapMode = config.wrapMode
495
+ table.columnWidthMode = config.columnWidthMode
496
+ table.columnFitter = config.columnFitter
497
+ }
498
+
499
+ async function runReplaceScenario(plan: ReplaceScenarioPlan, ctx: RunContext): Promise<ScenarioResult> {
500
+ applyTableConfig(ctx.table, plan.tableConfig)
501
+
502
+ for (let i = 0; i < plan.warmupIterations; i += 1) {
503
+ const variant = plan.variants[i % plan.variants.length]
504
+ ctx.table.content = variant
505
+ await ctx.renderOnce()
506
+ }
507
+
508
+ const durations: number[] = []
509
+ const measurementStart = Date.now()
510
+ const memStart = shouldSampleMemory(ctx.memSampleEvery) ? readMemorySample() : null
511
+ const memSamples: MemorySample[] = []
512
+
513
+ for (let i = 0; i < plan.iterations; i += 1) {
514
+ const variant = plan.variants[i % plan.variants.length]
515
+ const start = performance.now()
516
+ ctx.table.content = variant
517
+ await ctx.renderOnce()
518
+ durations.push(performance.now() - start)
519
+
520
+ if (ctx.memSampleEvery > 0 && (i + 1) % ctx.memSampleEvery === 0) {
521
+ memSamples.push(readMemorySample())
522
+ }
523
+ }
524
+
525
+ const elapsedMs = Date.now() - measurementStart
526
+ const memEnd = shouldSampleMemory(ctx.memSampleEvery) ? readMemorySample() : null
527
+
528
+ return {
529
+ name: plan.name,
530
+ description: plan.description,
531
+ category: "replace",
532
+ timingMode: "content-set-and-render",
533
+ iterations: plan.iterations,
534
+ warmupIterations: plan.warmupIterations,
535
+ elapsedMs,
536
+ updateStats: computeTimingStats(durations),
537
+ memoryStats: memStart && memEnd ? computeMemoryStats(memSamples, memStart, memEnd) : undefined,
538
+ tableStats: {
539
+ initialRows: plan.rows,
540
+ finalRows: plan.rows,
541
+ maxRows: plan.rows,
542
+ columns: plan.cols,
543
+ updates: plan.iterations,
544
+ datasetVariants: plan.variants.length,
545
+ },
546
+ settings: {
547
+ rows: plan.rows,
548
+ cols: plan.cols,
549
+ variants: plan.variants.length,
550
+ mode: "replace",
551
+ wrapMode: plan.tableConfig.wrapMode,
552
+ columnWidthMode: plan.tableConfig.columnWidthMode,
553
+ columnFitter: plan.tableConfig.columnFitter,
554
+ },
555
+ }
556
+ }
557
+
558
+ async function runIncrementalScenario(plan: IncrementalScenarioPlan, ctx: RunContext): Promise<ScenarioResult> {
559
+ applyTableConfig(ctx.table, plan.tableConfig)
560
+
561
+ const state: IncrementalState = {
562
+ rows: [...plan.baseRows],
563
+ cursor: 0,
564
+ maxRowsSeen: plan.baseRows.length,
565
+ }
566
+
567
+ ctx.table.content = [plan.header, ...state.rows]
568
+ await ctx.renderOnce()
569
+
570
+ for (let i = 0; i < plan.warmupIterations; i += 1) {
571
+ const next = nextIncrementalContent(plan, state)
572
+ ctx.table.content = next
573
+ await ctx.renderOnce()
574
+ }
575
+
576
+ const durations: number[] = []
577
+ const measurementStart = Date.now()
578
+ const memStart = shouldSampleMemory(ctx.memSampleEvery) ? readMemorySample() : null
579
+ const memSamples: MemorySample[] = []
580
+
581
+ for (let i = 0; i < plan.iterations; i += 1) {
582
+ const next = nextIncrementalContent(plan, state)
583
+
584
+ const start = performance.now()
585
+ ctx.table.content = next
586
+ await ctx.renderOnce()
587
+ durations.push(performance.now() - start)
588
+
589
+ if (ctx.memSampleEvery > 0 && (i + 1) % ctx.memSampleEvery === 0) {
590
+ memSamples.push(readMemorySample())
591
+ }
592
+ }
593
+
594
+ const elapsedMs = Date.now() - measurementStart
595
+ const memEnd = shouldSampleMemory(ctx.memSampleEvery) ? readMemorySample() : null
596
+
597
+ return {
598
+ name: plan.name,
599
+ description: plan.description,
600
+ category: "incremental",
601
+ timingMode: "content-set-and-render",
602
+ iterations: plan.iterations,
603
+ warmupIterations: plan.warmupIterations,
604
+ elapsedMs,
605
+ updateStats: computeTimingStats(durations),
606
+ memoryStats: memStart && memEnd ? computeMemoryStats(memSamples, memStart, memEnd) : undefined,
607
+ tableStats: {
608
+ initialRows: plan.baseRows.length,
609
+ finalRows: state.rows.length,
610
+ maxRows: state.maxRowsSeen,
611
+ columns: plan.cols,
612
+ updates: plan.iterations,
613
+ datasetVariants: plan.rowPool.length,
614
+ },
615
+ settings: {
616
+ cols: plan.cols,
617
+ baseRows: plan.baseRows.length,
618
+ rowPool: plan.rowPool.length,
619
+ maxRows: plan.maxRows,
620
+ mode: "incremental",
621
+ wrapMode: plan.tableConfig.wrapMode,
622
+ columnWidthMode: plan.tableConfig.columnWidthMode,
623
+ columnFitter: plan.tableConfig.columnFitter,
624
+ },
625
+ }
626
+ }
627
+
628
+ async function runSelectionScenario(plan: SelectionScenarioPlan, ctx: RunContext): Promise<ScenarioResult> {
629
+ applyTableConfig(ctx.table, plan.tableConfig)
630
+ ctx.table.content = plan.content
631
+ await ctx.renderOnce()
632
+
633
+ const tableX = ctx.table.x
634
+ const tableY = ctx.table.y
635
+ const tableH = ctx.table.height
636
+
637
+ const anchorX = tableX + 2
638
+ const anchorY = tableY + 2
639
+
640
+ const maxFocusY = tableY + tableH - 2
641
+ const focusRange = Math.max(1, maxFocusY - anchorY)
642
+
643
+ for (let i = 0; i < plan.warmupIterations; i += 1) {
644
+ const focusY = anchorY + (i % focusRange)
645
+ ctx.renderer.startSelection(ctx.table, anchorX, anchorY)
646
+ for (let step = 1; step <= plan.dragSteps; step += 1) {
647
+ const stepY = anchorY + Math.round(((focusY - anchorY) * step) / plan.dragSteps)
648
+ ctx.renderer.updateSelection(ctx.table, anchorX + 4, stepY)
649
+ }
650
+ await ctx.renderOnce()
651
+ ctx.renderer.clearSelection()
652
+ await ctx.renderOnce()
653
+ }
654
+
655
+ const durations: number[] = []
656
+ const measurementStart = Date.now()
657
+ const memStart = shouldSampleMemory(ctx.memSampleEvery) ? readMemorySample() : null
658
+ const memSamples: MemorySample[] = []
659
+
660
+ for (let i = 0; i < plan.iterations; i += 1) {
661
+ const focusY = anchorY + (i % focusRange)
662
+
663
+ const start = performance.now()
664
+
665
+ ctx.renderer.startSelection(ctx.table, anchorX, anchorY)
666
+ for (let step = 1; step <= plan.dragSteps; step += 1) {
667
+ const stepY = anchorY + Math.round(((focusY - anchorY) * step) / plan.dragSteps)
668
+ ctx.renderer.updateSelection(ctx.table, anchorX + 4, stepY)
669
+ }
670
+ await ctx.renderOnce()
671
+ ctx.renderer.clearSelection()
672
+ await ctx.renderOnce()
673
+
674
+ durations.push(performance.now() - start)
675
+
676
+ if (ctx.memSampleEvery > 0 && (i + 1) % ctx.memSampleEvery === 0) {
677
+ memSamples.push(readMemorySample())
678
+ }
679
+ }
680
+
681
+ const elapsedMs = Date.now() - measurementStart
682
+ const memEnd = shouldSampleMemory(ctx.memSampleEvery) ? readMemorySample() : null
683
+
684
+ return {
685
+ name: plan.name,
686
+ description: plan.description,
687
+ category: "selection",
688
+ timingMode: "selection-update-and-render",
689
+ iterations: plan.iterations,
690
+ warmupIterations: plan.warmupIterations,
691
+ elapsedMs,
692
+ updateStats: computeTimingStats(durations),
693
+ memoryStats: memStart && memEnd ? computeMemoryStats(memSamples, memStart, memEnd) : undefined,
694
+ tableStats: {
695
+ initialRows: plan.rows,
696
+ finalRows: plan.rows,
697
+ maxRows: plan.rows,
698
+ columns: plan.cols,
699
+ updates: plan.iterations * (plan.dragSteps + 1),
700
+ datasetVariants: 1,
701
+ },
702
+ settings: {
703
+ rows: plan.rows,
704
+ cols: plan.cols,
705
+ dragSteps: plan.dragSteps,
706
+ mode: "selection",
707
+ wrapMode: plan.tableConfig.wrapMode,
708
+ columnWidthMode: plan.tableConfig.columnWidthMode,
709
+ columnFitter: plan.tableConfig.columnFitter,
710
+ },
711
+ }
712
+ }
713
+
714
+ function nextIncrementalContent(plan: IncrementalScenarioPlan, state: IncrementalState): TextTableContent {
715
+ if (state.rows.length >= plan.maxRows) {
716
+ state.rows = [...plan.baseRows]
717
+ }
718
+
719
+ const fallbackRow = plan.rowPool[0] ?? makeDataRow(createRng(1), 0, plan.cols)
720
+ const nextRow = plan.rowPool[state.cursor] ?? fallbackRow
721
+
722
+ state.cursor += 1
723
+ if (state.cursor >= plan.rowPool.length) {
724
+ state.cursor = 0
725
+ }
726
+
727
+ state.rows = [...state.rows, nextRow]
728
+ state.maxRowsSeen = Math.max(state.maxRowsSeen, state.rows.length)
729
+
730
+ return [plan.header, ...state.rows]
731
+ }
732
+
733
+ function makeHeader(cols: number): TextTableCellContent[] {
734
+ const header: TextTableCellContent[] = []
735
+ for (let c = 0; c < cols; c += 1) {
736
+ header.push(chunkCell(`Column ${c + 1}`))
737
+ }
738
+ return header
739
+ }
740
+
741
+ function buildTableContent(rng: () => number, rows: number, cols: number): TextTableContent {
742
+ return [makeHeader(cols), ...buildRows(rng, rows, cols, 0)]
743
+ }
744
+
745
+ function buildRows(rng: () => number, rows: number, cols: number, rowOffset: number): TextTableCellContent[][] {
746
+ const out: TextTableCellContent[][] = []
747
+ for (let r = 0; r < rows; r += 1) {
748
+ out.push(makeDataRow(rng, rowOffset + r, cols))
749
+ }
750
+ return out
751
+ }
752
+
753
+ function makeDataRow(rng: () => number, rowIndex: number, cols: number): TextTableCellContent[] {
754
+ const row: TextTableCellContent[] = []
755
+ for (let c = 0; c < cols; c += 1) {
756
+ row.push(chunkCell(makeCellText(rng, rowIndex, c)))
757
+ }
758
+ return row
759
+ }
760
+
761
+ function chunkCell(text: string): TextTableCellContent {
762
+ return [
763
+ {
764
+ __isChunk: true,
765
+ text,
766
+ },
767
+ ]
768
+ }
769
+
770
+ function makeCellText(rng: () => number, row: number, col: number): string {
771
+ const a = pick(rng, WORDS)
772
+ const b = pick(rng, WORDS)
773
+ const roll = rng()
774
+
775
+ if (roll < 0.2) {
776
+ return `${a}-${b}-${row + col}`
777
+ }
778
+ if (roll < 0.4) {
779
+ return `${a} ${Math.floor(rng() * 1000)}`
780
+ }
781
+ if (roll < 0.6) {
782
+ return `${a} ${b} ${pick(rng, WORDS)}`
783
+ }
784
+ if (roll < 0.8) {
785
+ return `${a}_${b}_${Math.floor(rng() * 100)}`
786
+ }
787
+ return `${a} ${b} r${row}c${col}`
788
+ }
789
+
790
+ function pick<T>(rng: () => number, list: T[]): T {
791
+ return list[Math.floor(rng() * list.length)]
792
+ }
793
+
794
+ function createRng(initialSeed: number): () => number {
795
+ let state = initialSeed >>> 0
796
+ return () => {
797
+ state = (state * 1664525 + 1013904223) >>> 0
798
+ return state / 0x100000000
799
+ }
800
+ }
801
+
802
+ function scaled(value: number, scaleValue: number): number {
803
+ return Math.max(1, Math.round(value * scaleValue))
804
+ }
805
+
806
+ function toNumber(value: unknown, fallback: number): number {
807
+ if (typeof value === "number" && Number.isFinite(value)) return value
808
+ if (typeof value === "string") {
809
+ const parsed = Number(value)
810
+ if (Number.isFinite(parsed)) return parsed
811
+ }
812
+ return fallback
813
+ }
814
+
815
+ function shouldSampleMemory(memSampleEvery: number): boolean {
816
+ return memSampleEvery > 0
817
+ }
818
+
819
+ function readMemorySample(): MemorySample {
820
+ const usage = process.memoryUsage()
821
+ return {
822
+ rss: usage.rss ?? 0,
823
+ heapTotal: usage.heapTotal ?? 0,
824
+ heapUsed: usage.heapUsed ?? 0,
825
+ external: usage.external ?? 0,
826
+ arrayBuffers: usage.arrayBuffers ?? 0,
827
+ }
828
+ }
829
+
830
+ function computeMemoryStats(samples: MemorySample[], start: MemorySample, end: MemorySample): MemoryStats {
831
+ const all = [start, ...samples, end]
832
+ const peak = { ...start }
833
+
834
+ for (const sample of all) {
835
+ peak.rss = Math.max(peak.rss, sample.rss)
836
+ peak.heapTotal = Math.max(peak.heapTotal, sample.heapTotal)
837
+ peak.heapUsed = Math.max(peak.heapUsed, sample.heapUsed)
838
+ peak.external = Math.max(peak.external, sample.external)
839
+ peak.arrayBuffers = Math.max(peak.arrayBuffers, sample.arrayBuffers)
840
+ }
841
+
842
+ return {
843
+ samples: all.length,
844
+ start,
845
+ end,
846
+ delta: diffMemory(start, end),
847
+ peak,
848
+ }
849
+ }
850
+
851
+ function diffMemory(start: MemorySample, end: MemorySample): MemorySample {
852
+ return {
853
+ rss: end.rss - start.rss,
854
+ heapTotal: end.heapTotal - start.heapTotal,
855
+ heapUsed: end.heapUsed - start.heapUsed,
856
+ external: end.external - start.external,
857
+ arrayBuffers: end.arrayBuffers - start.arrayBuffers,
858
+ }
859
+ }
860
+
861
+ function computeTimingStats(durations: number[]): TimingStats {
862
+ const sorted = [...durations].sort((a, b) => a - b)
863
+ const count = sorted.length
864
+ const sum = sorted.reduce((acc, value) => acc + value, 0)
865
+ const average = count > 0 ? sum / count : 0
866
+ const min = sorted[0] ?? 0
867
+ const max = sorted[count - 1] ?? 0
868
+ const median = count > 0 ? (sorted[Math.floor(count / 2)] ?? 0) : 0
869
+ const p95 = count > 0 ? (sorted[Math.floor(count * 0.95)] ?? 0) : 0
870
+ const stdDev = count > 0 ? Math.sqrt(sorted.reduce((acc, v) => acc + Math.pow(v - average, 2), 0) / count) : 0
871
+
872
+ return {
873
+ count,
874
+ averageMs: average,
875
+ medianMs: median,
876
+ p95Ms: p95,
877
+ minMs: min,
878
+ maxMs: max,
879
+ stdDevMs: stdDev,
880
+ }
881
+ }
882
+
883
+ async function outputResults(
884
+ meta: OutputMeta,
885
+ results: ScenarioResult[],
886
+ scenarioLines: string[],
887
+ outputEnabled: boolean,
888
+ outputPath: string | null,
889
+ ): Promise<void> {
890
+ const runId = new Date().toISOString()
891
+ const payload = {
892
+ runId,
893
+ suite: meta.suiteName,
894
+ config: {
895
+ width: meta.width,
896
+ height: meta.height,
897
+ iterations: meta.iterations,
898
+ warmupIterations: meta.warmupIterations,
899
+ longIterations: meta.longIterations,
900
+ scale: meta.scale,
901
+ seed: meta.seed,
902
+ memSampleEvery: meta.memSampleEvery,
903
+ },
904
+ results,
905
+ }
906
+
907
+ if (outputEnabled) {
908
+ writeLine(
909
+ `text-table-benchmark suite=${meta.suiteName} mode=content-set-and-render iters=${meta.iterations} warmup=${meta.warmupIterations}`,
910
+ )
911
+ for (const line of scenarioLines) {
912
+ writeLine(line)
913
+ }
914
+ }
915
+
916
+ if (outputPath) {
917
+ try {
918
+ const json = JSON.stringify(payload, null, 2)
919
+ await Bun.write(outputPath, json)
920
+ } catch (error: any) {
921
+ writeLine(`Error writing results to ${outputPath}: ${error.message}`)
922
+ }
923
+ }
924
+ }
925
+
926
+ function formatBytes(value: number): string {
927
+ return `${(value / (1024 * 1024)).toFixed(2)}MB`
928
+ }
929
+
930
+ function formatScenarioResult(result: ScenarioResult): string {
931
+ const mem = result.memoryStats
932
+ const memSummary = mem
933
+ ? ` memDeltaRss=${formatBytes(mem.delta.rss)}` +
934
+ ` memDeltaHeap=${formatBytes(mem.delta.heapUsed)}` +
935
+ ` memDeltaExt=${formatBytes(mem.delta.external)}` +
936
+ ` memDeltaAB=${formatBytes(mem.delta.arrayBuffers)}` +
937
+ ` memPeakRss=${formatBytes(mem.peak.rss)}`
938
+ : ""
939
+
940
+ const fitter = typeof result.settings.columnFitter === "string" ? result.settings.columnFitter : "unknown"
941
+
942
+ return `scenario=${result.name} category=${result.category} mode=${result.timingMode} fitter=${fitter} iters=${result.updateStats.count} elapsedMs=${result.elapsedMs} avgMs=${result.updateStats.averageMs.toFixed(3)} medianMs=${result.updateStats.medianMs.toFixed(3)} p95Ms=${result.updateStats.p95Ms.toFixed(3)} minMs=${result.updateStats.minMs.toFixed(3)} maxMs=${result.updateStats.maxMs.toFixed(3)} rows=${result.tableStats.finalRows} maxRows=${result.tableStats.maxRows} cols=${result.tableStats.columns}${memSummary}`
943
+ }
944
+
945
+ function writeLine(line: string): void {
946
+ realStdoutWrite(`${line}\n`)
947
+ }