@fairyhunter13/opentui-core 0.1.112 → 0.1.114

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/dev/keypress-debug-renderer.ts +148 -0
  2. package/dev/keypress-debug.ts +43 -0
  3. package/dev/print-env-vars.ts +32 -0
  4. package/dev/test-tmux-graphics-334.sh +68 -0
  5. package/dev/thai-debug-test.ts +68 -0
  6. package/docs/development.md +144 -0
  7. package/package.json +63 -51
  8. package/scripts/build.ts +400 -0
  9. package/scripts/publish.ts +60 -0
  10. package/src/3d/SpriteResourceManager.ts +286 -0
  11. package/src/3d/SpriteUtils.ts +70 -0
  12. package/src/3d/TextureUtils.ts +196 -0
  13. package/src/3d/ThreeRenderable.ts +197 -0
  14. package/src/3d/WGPURenderer.ts +294 -0
  15. package/src/3d/animation/ExplodingSpriteEffect.ts +513 -0
  16. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +429 -0
  17. package/src/3d/animation/SpriteAnimator.ts +633 -0
  18. package/src/3d/animation/SpriteParticleGenerator.ts +435 -0
  19. package/src/3d/canvas.ts +464 -0
  20. package/src/3d/index.ts +12 -0
  21. package/src/3d/physics/PlanckPhysicsAdapter.ts +72 -0
  22. package/src/3d/physics/RapierPhysicsAdapter.ts +66 -0
  23. package/src/3d/physics/physics-interface.ts +31 -0
  24. package/src/3d/shaders/supersampling.wgsl +201 -0
  25. package/src/3d.ts +3 -0
  26. package/src/NativeSpanFeed.ts +300 -0
  27. package/src/Renderable.ts +1704 -0
  28. package/src/__snapshots__/buffer.test.ts.snap +28 -0
  29. package/src/animation/Timeline.test.ts +2709 -0
  30. package/src/animation/Timeline.ts +598 -0
  31. package/src/ansi.ts +18 -0
  32. package/src/benchmark/attenuation-benchmark.ts +81 -0
  33. package/src/benchmark/colormatrix-benchmark.ts +128 -0
  34. package/src/benchmark/gain-benchmark.ts +80 -0
  35. package/src/benchmark/latest-all-bench-run.json +707 -0
  36. package/src/benchmark/latest-async-bench-run.json +336 -0
  37. package/src/benchmark/latest-default-bench-run.json +657 -0
  38. package/src/benchmark/latest-large-bench-run.json +707 -0
  39. package/src/benchmark/latest-quick-bench-run.json +207 -0
  40. package/src/benchmark/markdown-benchmark.ts +1796 -0
  41. package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
  42. package/src/benchmark/native-span-feed-benchmark.md +56 -0
  43. package/src/benchmark/native-span-feed-benchmark.ts +596 -0
  44. package/src/benchmark/native-span-feed-compare.ts +280 -0
  45. package/src/benchmark/renderer-benchmark.ts +754 -0
  46. package/src/benchmark/text-table-benchmark.ts +948 -0
  47. package/src/buffer.test.ts +291 -0
  48. package/src/buffer.ts +554 -0
  49. package/src/console.test.ts +612 -0
  50. package/src/console.ts +1254 -0
  51. package/src/edit-buffer.test.ts +1769 -0
  52. package/src/edit-buffer.ts +411 -0
  53. package/src/editor-view.test.ts +1032 -0
  54. package/src/editor-view.ts +284 -0
  55. package/src/examples/ascii-font-selection-demo.ts +245 -0
  56. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  57. package/src/examples/assets/concrete.png +0 -0
  58. package/src/examples/assets/crate.png +0 -0
  59. package/src/examples/assets/crate_emissive.png +0 -0
  60. package/src/examples/assets/forrest_background.png +0 -0
  61. package/src/examples/assets/hast-example.json +1018 -0
  62. package/src/examples/assets/heart.png +0 -0
  63. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  64. package/src/examples/assets/main_char_idle.png +0 -0
  65. package/src/examples/assets/main_char_jump_end.png +0 -0
  66. package/src/examples/assets/main_char_jump_landing.png +0 -0
  67. package/src/examples/assets/main_char_jump_start.png +0 -0
  68. package/src/examples/assets/main_char_run_loop.png +0 -0
  69. package/src/examples/assets/roughness_map.jpg +0 -0
  70. package/src/examples/build.ts +115 -0
  71. package/src/examples/code-demo.ts +924 -0
  72. package/src/examples/console-demo.ts +358 -0
  73. package/src/examples/core-plugin-slots-demo.ts +759 -0
  74. package/src/examples/diff-demo.ts +701 -0
  75. package/src/examples/draggable-three-demo.ts +259 -0
  76. package/src/examples/editor-demo.ts +322 -0
  77. package/src/examples/extmarks-demo.ts +196 -0
  78. package/src/examples/focus-restore-demo.ts +310 -0
  79. package/src/examples/fonts.ts +245 -0
  80. package/src/examples/fractal-shader-demo.ts +268 -0
  81. package/src/examples/framebuffer-demo.ts +674 -0
  82. package/src/examples/full-unicode-demo.ts +241 -0
  83. package/src/examples/golden-star-demo.ts +933 -0
  84. package/src/examples/grayscale-buffer-demo.ts +249 -0
  85. package/src/examples/hast-syntax-highlighting-demo.ts +129 -0
  86. package/src/examples/index.ts +926 -0
  87. package/src/examples/input-demo.ts +377 -0
  88. package/src/examples/input-select-layout-demo.ts +425 -0
  89. package/src/examples/install.sh +143 -0
  90. package/src/examples/keypress-debug-demo.ts +452 -0
  91. package/src/examples/lib/HexList.ts +122 -0
  92. package/src/examples/lib/PaletteGrid.ts +125 -0
  93. package/src/examples/lib/standalone-keys.ts +25 -0
  94. package/src/examples/lib/tab-controller.ts +243 -0
  95. package/src/examples/lights-phong-demo.ts +290 -0
  96. package/src/examples/link-demo.ts +220 -0
  97. package/src/examples/live-state-demo.ts +480 -0
  98. package/src/examples/markdown-demo.ts +725 -0
  99. package/src/examples/mouse-interaction-demo.ts +428 -0
  100. package/src/examples/nested-zindex-demo.ts +357 -0
  101. package/src/examples/opacity-example.ts +235 -0
  102. package/src/examples/opentui-demo.ts +1057 -0
  103. package/src/examples/physx-planck-2d-demo.ts +623 -0
  104. package/src/examples/physx-rapier-2d-demo.ts +655 -0
  105. package/src/examples/relative-positioning-demo.ts +323 -0
  106. package/src/examples/scroll-example.ts +214 -0
  107. package/src/examples/scrollbox-mouse-test.ts +112 -0
  108. package/src/examples/scrollbox-overlay-hit-test.ts +206 -0
  109. package/src/examples/select-demo.ts +237 -0
  110. package/src/examples/shader-cube-demo.ts +1015 -0
  111. package/src/examples/simple-layout-example.ts +591 -0
  112. package/src/examples/slider-demo.ts +617 -0
  113. package/src/examples/split-mode-demo.ts +453 -0
  114. package/src/examples/sprite-animation-demo.ts +443 -0
  115. package/src/examples/sprite-particle-generator-demo.ts +486 -0
  116. package/src/examples/static-sprite-demo.ts +193 -0
  117. package/src/examples/sticky-scroll-example.ts +308 -0
  118. package/src/examples/styled-text-demo.ts +282 -0
  119. package/src/examples/tab-select-demo.ts +219 -0
  120. package/src/examples/terminal-title.ts +29 -0
  121. package/src/examples/terminal.ts +305 -0
  122. package/src/examples/text-node-demo.ts +416 -0
  123. package/src/examples/text-selection-demo.ts +377 -0
  124. package/src/examples/text-table-demo.ts +503 -0
  125. package/src/examples/text-truncation-demo.ts +481 -0
  126. package/src/examples/text-wrap.ts +757 -0
  127. package/src/examples/texture-loading-demo.ts +259 -0
  128. package/src/examples/timeline-example.ts +670 -0
  129. package/src/examples/transparency-demo.ts +400 -0
  130. package/src/examples/vnode-composition-demo.ts +404 -0
  131. package/src/examples/wide-grapheme-overlay-demo.ts +280 -0
  132. package/src/index.ts +24 -0
  133. package/src/lib/KeyHandler.integration.test.ts +292 -0
  134. package/src/lib/KeyHandler.stopPropagation.test.ts +289 -0
  135. package/src/lib/KeyHandler.test.ts +662 -0
  136. package/src/lib/KeyHandler.ts +222 -0
  137. package/src/lib/RGBA.test.ts +984 -0
  138. package/src/lib/RGBA.ts +204 -0
  139. package/src/lib/ascii.font.ts +330 -0
  140. package/src/lib/border.test.ts +83 -0
  141. package/src/lib/border.ts +170 -0
  142. package/src/lib/bunfs.test.ts +27 -0
  143. package/src/lib/bunfs.ts +18 -0
  144. package/src/lib/clipboard.test.ts +41 -0
  145. package/src/lib/clipboard.ts +47 -0
  146. package/src/lib/clock.ts +35 -0
  147. package/src/lib/data-paths.test.ts +133 -0
  148. package/src/lib/data-paths.ts +109 -0
  149. package/src/lib/debounce.ts +106 -0
  150. package/src/lib/detect-links.test.ts +98 -0
  151. package/src/lib/detect-links.ts +56 -0
  152. package/src/lib/env.test.ts +228 -0
  153. package/src/lib/env.ts +209 -0
  154. package/src/lib/extmarks-history.ts +51 -0
  155. package/src/lib/extmarks-multiwidth.test.ts +322 -0
  156. package/src/lib/extmarks.test.ts +3457 -0
  157. package/src/lib/extmarks.ts +843 -0
  158. package/src/lib/fonts/block.json +405 -0
  159. package/src/lib/fonts/grid.json +265 -0
  160. package/src/lib/fonts/huge.json +741 -0
  161. package/src/lib/fonts/pallet.json +314 -0
  162. package/src/lib/fonts/shade.json +591 -0
  163. package/src/lib/fonts/slick.json +321 -0
  164. package/src/lib/fonts/tiny.json +69 -0
  165. package/src/lib/hast-styled-text.ts +59 -0
  166. package/src/lib/index.ts +21 -0
  167. package/src/lib/keymapping.test.ts +317 -0
  168. package/src/lib/keymapping.ts +115 -0
  169. package/src/lib/objects-in-viewport.test.ts +787 -0
  170. package/src/lib/objects-in-viewport.ts +153 -0
  171. package/src/lib/output.capture.ts +58 -0
  172. package/src/lib/parse.keypress-kitty.protocol.test.ts +340 -0
  173. package/src/lib/parse.keypress-kitty.test.ts +663 -0
  174. package/src/lib/parse.keypress-kitty.ts +439 -0
  175. package/src/lib/parse.keypress.test.ts +1849 -0
  176. package/src/lib/parse.keypress.ts +397 -0
  177. package/src/lib/parse.mouse.test.ts +552 -0
  178. package/src/lib/parse.mouse.ts +232 -0
  179. package/src/lib/paste.ts +16 -0
  180. package/src/lib/queue.ts +65 -0
  181. package/src/lib/renderable.validations.test.ts +87 -0
  182. package/src/lib/renderable.validations.ts +83 -0
  183. package/src/lib/scroll-acceleration.ts +98 -0
  184. package/src/lib/selection.ts +240 -0
  185. package/src/lib/singleton.ts +28 -0
  186. package/src/lib/stdin-parser.test.ts +2290 -0
  187. package/src/lib/stdin-parser.ts +1810 -0
  188. package/src/lib/styled-text.ts +178 -0
  189. package/src/lib/terminal-capability-detection.test.ts +202 -0
  190. package/src/lib/terminal-capability-detection.ts +79 -0
  191. package/src/lib/terminal-palette.test.ts +878 -0
  192. package/src/lib/terminal-palette.ts +383 -0
  193. package/src/lib/tree-sitter/assets/README.md +118 -0
  194. package/src/lib/tree-sitter/assets/update.ts +334 -0
  195. package/src/lib/tree-sitter/assets.d.ts +9 -0
  196. package/src/lib/tree-sitter/cache.test.ts +273 -0
  197. package/src/lib/tree-sitter/client.test.ts +1165 -0
  198. package/src/lib/tree-sitter/client.ts +607 -0
  199. package/src/lib/tree-sitter/default-parsers.ts +86 -0
  200. package/src/lib/tree-sitter/download-utils.ts +148 -0
  201. package/src/lib/tree-sitter/index.ts +28 -0
  202. package/src/lib/tree-sitter/parser.worker.ts +1042 -0
  203. package/src/lib/tree-sitter/parsers-config.ts +81 -0
  204. package/src/lib/tree-sitter/resolve-ft.test.ts +55 -0
  205. package/src/lib/tree-sitter/resolve-ft.ts +189 -0
  206. package/src/lib/tree-sitter/types.ts +82 -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 +402 -0
  214. package/src/plugins/types.ts +46 -0
  215. package/src/post/effects.ts +930 -0
  216. package/src/post/filters.ts +489 -0
  217. package/src/post/matrices.ts +288 -0
  218. package/src/renderables/ASCIIFont.ts +219 -0
  219. package/src/renderables/Box.test.ts +205 -0
  220. package/src/renderables/Box.ts +326 -0
  221. package/src/renderables/Code.test.ts +2062 -0
  222. package/src/renderables/Code.ts +357 -0
  223. package/src/renderables/Diff.regression.test.ts +226 -0
  224. package/src/renderables/Diff.test.ts +3101 -0
  225. package/src/renderables/Diff.ts +1211 -0
  226. package/src/renderables/EditBufferRenderable.test.ts +288 -0
  227. package/src/renderables/EditBufferRenderable.ts +1166 -0
  228. package/src/renderables/FrameBuffer.ts +47 -0
  229. package/src/renderables/Input.test.ts +1228 -0
  230. package/src/renderables/Input.ts +247 -0
  231. package/src/renderables/LineNumberRenderable.ts +724 -0
  232. package/src/renderables/Markdown.ts +1393 -0
  233. package/src/renderables/ScrollBar.ts +422 -0
  234. package/src/renderables/ScrollBox.ts +883 -0
  235. package/src/renderables/Select.test.ts +1033 -0
  236. package/src/renderables/Select.ts +524 -0
  237. package/src/renderables/Slider.test.ts +456 -0
  238. package/src/renderables/Slider.ts +342 -0
  239. package/src/renderables/TabSelect.test.ts +197 -0
  240. package/src/renderables/TabSelect.ts +455 -0
  241. package/src/renderables/Text.selection-buffer.test.ts +123 -0
  242. package/src/renderables/Text.test.ts +2660 -0
  243. package/src/renderables/Text.ts +147 -0
  244. package/src/renderables/TextBufferRenderable.ts +518 -0
  245. package/src/renderables/TextNode.test.ts +1058 -0
  246. package/src/renderables/TextNode.ts +325 -0
  247. package/src/renderables/TextTable.test.ts +1421 -0
  248. package/src/renderables/TextTable.ts +1344 -0
  249. package/src/renderables/Textarea.ts +430 -0
  250. package/src/renderables/TimeToFirstDraw.ts +89 -0
  251. package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
  252. package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
  253. package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
  254. package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
  255. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
  256. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +816 -0
  257. package/src/renderables/__tests__/LineNumberRenderable.test.ts +1865 -0
  258. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
  259. package/src/renderables/__tests__/Markdown.code-colors.test.ts +242 -0
  260. package/src/renderables/__tests__/Markdown.test.ts +2518 -0
  261. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
  262. package/src/renderables/__tests__/Textarea.buffer.test.ts +682 -0
  263. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
  264. package/src/renderables/__tests__/Textarea.editing.test.ts +2041 -0
  265. package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
  266. package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
  267. package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
  268. package/src/renderables/__tests__/Textarea.keybinding.test.ts +3149 -0
  269. package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
  270. package/src/renderables/__tests__/Textarea.rendering.test.ts +1866 -0
  271. package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
  272. package/src/renderables/__tests__/Textarea.selection.test.ts +1590 -0
  273. package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
  274. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
  275. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
  276. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
  277. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
  278. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
  279. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
  280. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
  281. package/src/renderables/__tests__/markdown-parser.test.ts +217 -0
  282. package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
  283. package/src/renderables/composition/README.md +8 -0
  284. package/src/renderables/composition/VRenderable.ts +32 -0
  285. package/src/renderables/composition/constructs.ts +127 -0
  286. package/src/renderables/composition/vnode.ts +289 -0
  287. package/src/renderables/index.ts +23 -0
  288. package/src/renderables/markdown-parser.ts +66 -0
  289. package/src/renderer.ts +2681 -0
  290. package/src/runtime-plugin-support.ts +39 -0
  291. package/src/runtime-plugin.ts +615 -0
  292. package/src/syntax-style.test.ts +841 -0
  293. package/src/syntax-style.ts +257 -0
  294. package/src/testing/README.md +210 -0
  295. package/src/testing/capture-spans.test.ts +194 -0
  296. package/src/testing/integration.test.ts +276 -0
  297. package/src/testing/manual-clock.ts +117 -0
  298. package/src/testing/mock-keys.test.ts +1378 -0
  299. package/src/testing/mock-keys.ts +457 -0
  300. package/src/testing/mock-mouse.test.ts +218 -0
  301. package/src/testing/mock-mouse.ts +247 -0
  302. package/src/testing/mock-tree-sitter-client.ts +73 -0
  303. package/src/testing/spy.ts +13 -0
  304. package/src/testing/test-recorder.test.ts +415 -0
  305. package/src/testing/test-recorder.ts +145 -0
  306. package/src/testing/test-renderer.ts +132 -0
  307. package/src/testing.ts +7 -0
  308. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
  309. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
  310. package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
  311. package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
  312. package/src/tests/allocator-stats.test.ts +38 -0
  313. package/src/tests/destroy-during-render.test.ts +200 -0
  314. package/src/tests/destroy-on-exit.fixture.ts +36 -0
  315. package/src/tests/destroy-on-exit.test.ts +41 -0
  316. package/src/tests/hover-cursor.test.ts +98 -0
  317. package/src/tests/native-span-feed-async.test.ts +173 -0
  318. package/src/tests/native-span-feed-close.test.ts +120 -0
  319. package/src/tests/native-span-feed-coverage.test.ts +227 -0
  320. package/src/tests/native-span-feed-edge-cases.test.ts +352 -0
  321. package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
  322. package/src/tests/opacity.test.ts +123 -0
  323. package/src/tests/renderable.snapshot.test.ts +524 -0
  324. package/src/tests/renderable.test.ts +1281 -0
  325. package/src/tests/renderer.clock.test.ts +158 -0
  326. package/src/tests/renderer.console-startup.test.ts +185 -0
  327. package/src/tests/renderer.control.test.ts +425 -0
  328. package/src/tests/renderer.core-slot-binding.test.ts +952 -0
  329. package/src/tests/renderer.cursor.test.ts +26 -0
  330. package/src/tests/renderer.destroy-during-render.test.ts +147 -0
  331. package/src/tests/renderer.focus-restore.test.ts +257 -0
  332. package/src/tests/renderer.focus.test.ts +294 -0
  333. package/src/tests/renderer.idle.test.ts +219 -0
  334. package/src/tests/renderer.input.test.ts +2237 -0
  335. package/src/tests/renderer.kitty-flags.test.ts +195 -0
  336. package/src/tests/renderer.mouse.test.ts +1274 -0
  337. package/src/tests/renderer.palette.test.ts +629 -0
  338. package/src/tests/renderer.selection.test.ts +49 -0
  339. package/src/tests/renderer.slot-registry.test.ts +684 -0
  340. package/src/tests/renderer.useMouse.test.ts +47 -0
  341. package/src/tests/runtime-plugin-node-modules-cycle.fixture.ts +76 -0
  342. package/src/tests/runtime-plugin-node-modules-mjs.fixture.ts +43 -0
  343. package/src/tests/runtime-plugin-node-modules-no-bare-rewrite.fixture.ts +67 -0
  344. package/src/tests/runtime-plugin-node-modules-package-type-cache.fixture.ts +72 -0
  345. package/src/tests/runtime-plugin-node-modules-runtime-specifier.fixture.ts +44 -0
  346. package/src/tests/runtime-plugin-node-modules-scoped-package-bare-rewrite.fixture.ts +85 -0
  347. package/src/tests/runtime-plugin-path-alias.fixture.ts +43 -0
  348. package/src/tests/runtime-plugin-resolve-roots.fixture.ts +65 -0
  349. package/src/tests/runtime-plugin-support.fixture.ts +11 -0
  350. package/src/tests/runtime-plugin-support.test.ts +19 -0
  351. package/src/tests/runtime-plugin-windows-file-url.fixture.ts +30 -0
  352. package/src/tests/runtime-plugin.fixture.ts +40 -0
  353. package/src/tests/runtime-plugin.test.ts +354 -0
  354. package/src/tests/scrollbox-culling-bug.test.ts +114 -0
  355. package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
  356. package/src/tests/scrollbox-hitgrid.test.ts +909 -0
  357. package/src/tests/scrollbox.test.ts +1530 -0
  358. package/src/tests/wrap-resize-perf.test.ts +276 -0
  359. package/src/tests/yoga-setters.test.ts +921 -0
  360. package/src/text-buffer-view.test.ts +705 -0
  361. package/src/text-buffer-view.ts +189 -0
  362. package/src/text-buffer.test.ts +347 -0
  363. package/src/text-buffer.ts +250 -0
  364. package/src/types.ts +161 -0
  365. package/src/utils.ts +88 -0
  366. package/src/zig/ansi.zig +268 -0
  367. package/src/zig/bench/README.md +50 -0
  368. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +887 -0
  369. package/src/zig/bench/edit-buffer_bench.zig +476 -0
  370. package/src/zig/bench/native-span-feed_bench.zig +100 -0
  371. package/src/zig/bench/rope-markers_bench.zig +713 -0
  372. package/src/zig/bench/rope_bench.zig +514 -0
  373. package/src/zig/bench/styled-text_bench.zig +470 -0
  374. package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
  375. package/src/zig/bench/text-buffer-view_bench.zig +459 -0
  376. package/src/zig/bench/text-chunk-graphemes_bench.zig +273 -0
  377. package/src/zig/bench/utf8_bench.zig +799 -0
  378. package/src/zig/bench-utils.zig +431 -0
  379. package/src/zig/bench.zig +217 -0
  380. package/src/zig/buffer-methods.zig +211 -0
  381. package/src/zig/buffer.zig +2281 -0
  382. package/src/zig/build.zig +289 -0
  383. package/src/zig/build.zig.zon +16 -0
  384. package/src/zig/edit-buffer.zig +825 -0
  385. package/src/zig/editor-view.zig +802 -0
  386. package/src/zig/event-bus.zig +13 -0
  387. package/src/zig/event-emitter.zig +65 -0
  388. package/src/zig/file-logger.zig +92 -0
  389. package/src/zig/grapheme.zig +599 -0
  390. package/src/zig/lib.zig +1854 -0
  391. package/src/zig/link.zig +333 -0
  392. package/src/zig/logger.zig +43 -0
  393. package/src/zig/mem-registry.zig +125 -0
  394. package/src/zig/native-span-feed-bench-lib.zig +7 -0
  395. package/src/zig/native-span-feed.zig +708 -0
  396. package/src/zig/renderer.zig +1393 -0
  397. package/src/zig/rope.zig +1220 -0
  398. package/src/zig/syntax-style.zig +161 -0
  399. package/src/zig/terminal.zig +987 -0
  400. package/src/zig/test.zig +72 -0
  401. package/src/zig/tests/README.md +18 -0
  402. package/src/zig/tests/buffer-methods_test.zig +1109 -0
  403. package/src/zig/tests/buffer_test.zig +2557 -0
  404. package/src/zig/tests/edit-buffer-history_test.zig +271 -0
  405. package/src/zig/tests/edit-buffer_test.zig +1689 -0
  406. package/src/zig/tests/editor-view_test.zig +3299 -0
  407. package/src/zig/tests/event-emitter_test.zig +249 -0
  408. package/src/zig/tests/grapheme_test.zig +1304 -0
  409. package/src/zig/tests/link_test.zig +190 -0
  410. package/src/zig/tests/mem-registry_test.zig +473 -0
  411. package/src/zig/tests/memory_leak_regression_test.zig +159 -0
  412. package/src/zig/tests/native-span-feed_test.zig +1264 -0
  413. package/src/zig/tests/renderer_test.zig +1017 -0
  414. package/src/zig/tests/rope-nested_test.zig +712 -0
  415. package/src/zig/tests/rope_fuzz_test.zig +238 -0
  416. package/src/zig/tests/rope_test.zig +2362 -0
  417. package/src/zig/tests/segment-merge.test.zig +148 -0
  418. package/src/zig/tests/syntax-style_test.zig +557 -0
  419. package/src/zig/tests/terminal_test.zig +754 -0
  420. package/src/zig/tests/text-buffer-drawing_test.zig +3237 -0
  421. package/src/zig/tests/text-buffer-highlights_test.zig +666 -0
  422. package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
  423. package/src/zig/tests/text-buffer-segment_test.zig +320 -0
  424. package/src/zig/tests/text-buffer-selection_test.zig +1035 -0
  425. package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
  426. package/src/zig/tests/text-buffer-view_test.zig +3649 -0
  427. package/src/zig/tests/text-buffer_test.zig +2191 -0
  428. package/src/zig/tests/unicode-width-map.zon +3909 -0
  429. package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
  430. package/src/zig/tests/utf8_test.zig +4057 -0
  431. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
  432. package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
  433. package/src/zig/tests/word-wrap-editing_test.zig +498 -0
  434. package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
  435. package/src/zig/text-buffer-iterators.zig +499 -0
  436. package/src/zig/text-buffer-segment.zig +404 -0
  437. package/src/zig/text-buffer-view.zig +1371 -0
  438. package/src/zig/text-buffer.zig +1180 -0
  439. package/src/zig/utf8.zig +1948 -0
  440. package/src/zig/utils.zig +9 -0
  441. package/src/zig-structs.ts +261 -0
  442. package/src/zig.ts +3884 -0
  443. package/tsconfig.build.json +24 -0
  444. package/tsconfig.json +27 -0
  445. package/3d/SpriteResourceManager.d.ts +0 -74
  446. package/3d/SpriteUtils.d.ts +0 -13
  447. package/3d/TextureUtils.d.ts +0 -24
  448. package/3d/ThreeRenderable.d.ts +0 -40
  449. package/3d/WGPURenderer.d.ts +0 -61
  450. package/3d/animation/ExplodingSpriteEffect.d.ts +0 -71
  451. package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +0 -76
  452. package/3d/animation/SpriteAnimator.d.ts +0 -124
  453. package/3d/animation/SpriteParticleGenerator.d.ts +0 -62
  454. package/3d/canvas.d.ts +0 -44
  455. package/3d/index.d.ts +0 -12
  456. package/3d/physics/PlanckPhysicsAdapter.d.ts +0 -19
  457. package/3d/physics/RapierPhysicsAdapter.d.ts +0 -19
  458. package/3d/physics/physics-interface.d.ts +0 -27
  459. package/3d.d.ts +0 -2
  460. package/3d.js +0 -34041
  461. package/3d.js.map +0 -155
  462. package/LICENSE +0 -21
  463. package/NativeSpanFeed.d.ts +0 -41
  464. package/Renderable.d.ts +0 -334
  465. package/animation/Timeline.d.ts +0 -126
  466. package/ansi.d.ts +0 -13
  467. package/buffer.d.ts +0 -111
  468. package/console.d.ts +0 -144
  469. package/edit-buffer.d.ts +0 -98
  470. package/editor-view.d.ts +0 -73
  471. package/index-8fks7yv1.js +0 -411
  472. package/index-8fks7yv1.js.map +0 -10
  473. package/index-egy5e2rs.js +0 -12267
  474. package/index-egy5e2rs.js.map +0 -42
  475. package/index-tse8gzh0.js +0 -20614
  476. package/index-tse8gzh0.js.map +0 -67
  477. package/index.d.ts +0 -23
  478. package/index.js +0 -478
  479. package/index.js.map +0 -9
  480. package/lib/KeyHandler.d.ts +0 -61
  481. package/lib/RGBA.d.ts +0 -25
  482. package/lib/ascii.font.d.ts +0 -508
  483. package/lib/border.d.ts +0 -51
  484. package/lib/bunfs.d.ts +0 -7
  485. package/lib/clipboard.d.ts +0 -17
  486. package/lib/clock.d.ts +0 -15
  487. package/lib/data-paths.d.ts +0 -26
  488. package/lib/debounce.d.ts +0 -42
  489. package/lib/detect-links.d.ts +0 -6
  490. package/lib/env.d.ts +0 -42
  491. package/lib/extmarks-history.d.ts +0 -17
  492. package/lib/extmarks.d.ts +0 -89
  493. package/lib/hast-styled-text.d.ts +0 -17
  494. package/lib/index.d.ts +0 -21
  495. package/lib/keymapping.d.ts +0 -25
  496. package/lib/objects-in-viewport.d.ts +0 -24
  497. package/lib/output.capture.d.ts +0 -24
  498. package/lib/parse.keypress-kitty.d.ts +0 -2
  499. package/lib/parse.keypress.d.ts +0 -26
  500. package/lib/parse.mouse.d.ts +0 -30
  501. package/lib/paste.d.ts +0 -7
  502. package/lib/queue.d.ts +0 -15
  503. package/lib/renderable.validations.d.ts +0 -12
  504. package/lib/scroll-acceleration.d.ts +0 -43
  505. package/lib/selection.d.ts +0 -63
  506. package/lib/singleton.d.ts +0 -7
  507. package/lib/stdin-parser.d.ts +0 -87
  508. package/lib/styled-text.d.ts +0 -63
  509. package/lib/terminal-capability-detection.d.ts +0 -30
  510. package/lib/terminal-palette.d.ts +0 -50
  511. package/lib/tree-sitter/assets/update.d.ts +0 -11
  512. package/lib/tree-sitter/client.d.ts +0 -47
  513. package/lib/tree-sitter/default-parsers.d.ts +0 -2
  514. package/lib/tree-sitter/download-utils.d.ts +0 -21
  515. package/lib/tree-sitter/index.d.ts +0 -8
  516. package/lib/tree-sitter/parser.worker.d.ts +0 -1
  517. package/lib/tree-sitter/parsers-config.d.ts +0 -53
  518. package/lib/tree-sitter/resolve-ft.d.ts +0 -5
  519. package/lib/tree-sitter/types.d.ts +0 -82
  520. package/lib/tree-sitter-styled-text.d.ts +0 -14
  521. package/lib/validate-dir-name.d.ts +0 -1
  522. package/lib/yoga.options.d.ts +0 -32
  523. package/parser.worker.js +0 -899
  524. package/parser.worker.js.map +0 -12
  525. package/plugins/core-slot.d.ts +0 -72
  526. package/plugins/registry.d.ts +0 -42
  527. package/plugins/types.d.ts +0 -34
  528. package/post/effects.d.ts +0 -147
  529. package/post/filters.d.ts +0 -65
  530. package/post/matrices.d.ts +0 -20
  531. package/renderables/ASCIIFont.d.ts +0 -52
  532. package/renderables/Box.d.ts +0 -81
  533. package/renderables/Code.d.ts +0 -78
  534. package/renderables/Diff.d.ts +0 -142
  535. package/renderables/EditBufferRenderable.d.ts +0 -237
  536. package/renderables/FrameBuffer.d.ts +0 -16
  537. package/renderables/Input.d.ts +0 -67
  538. package/renderables/LineNumberRenderable.d.ts +0 -78
  539. package/renderables/Markdown.d.ts +0 -185
  540. package/renderables/ScrollBar.d.ts +0 -77
  541. package/renderables/ScrollBox.d.ts +0 -124
  542. package/renderables/Select.d.ts +0 -115
  543. package/renderables/Slider.d.ts +0 -47
  544. package/renderables/TabSelect.d.ts +0 -96
  545. package/renderables/Text.d.ts +0 -36
  546. package/renderables/TextBufferRenderable.d.ts +0 -105
  547. package/renderables/TextNode.d.ts +0 -91
  548. package/renderables/TextTable.d.ts +0 -140
  549. package/renderables/Textarea.d.ts +0 -63
  550. package/renderables/TimeToFirstDraw.d.ts +0 -24
  551. package/renderables/__tests__/renderable-test-utils.d.ts +0 -12
  552. package/renderables/composition/VRenderable.d.ts +0 -16
  553. package/renderables/composition/constructs.d.ts +0 -35
  554. package/renderables/composition/vnode.d.ts +0 -46
  555. package/renderables/index.d.ts +0 -23
  556. package/renderables/markdown-parser.d.ts +0 -10
  557. package/renderer.d.ts +0 -419
  558. package/runtime-plugin-support.d.ts +0 -3
  559. package/runtime-plugin-support.js +0 -29
  560. package/runtime-plugin-support.js.map +0 -10
  561. package/runtime-plugin.d.ts +0 -16
  562. package/runtime-plugin.js +0 -16
  563. package/runtime-plugin.js.map +0 -9
  564. package/syntax-style.d.ts +0 -54
  565. package/testing/manual-clock.d.ts +0 -17
  566. package/testing/mock-keys.d.ts +0 -81
  567. package/testing/mock-mouse.d.ts +0 -38
  568. package/testing/mock-tree-sitter-client.d.ts +0 -23
  569. package/testing/spy.d.ts +0 -7
  570. package/testing/test-recorder.d.ts +0 -61
  571. package/testing/test-renderer.d.ts +0 -23
  572. package/testing.d.ts +0 -6
  573. package/testing.js +0 -697
  574. package/testing.js.map +0 -15
  575. package/text-buffer-view.d.ts +0 -42
  576. package/text-buffer.d.ts +0 -67
  577. package/types.d.ts +0 -139
  578. package/utils.d.ts +0 -14
  579. package/zig-structs.d.ts +0 -155
  580. package/zig.d.ts +0 -353
  581. /package/{assets → src/lib/tree-sitter/assets}/javascript/highlights.scm +0 -0
  582. /package/{assets → src/lib/tree-sitter/assets}/javascript/tree-sitter-javascript.wasm +0 -0
  583. /package/{assets → src/lib/tree-sitter/assets}/markdown/highlights.scm +0 -0
  584. /package/{assets → src/lib/tree-sitter/assets}/markdown/injections.scm +0 -0
  585. /package/{assets → src/lib/tree-sitter/assets}/markdown/tree-sitter-markdown.wasm +0 -0
  586. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/highlights.scm +0 -0
  587. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  588. /package/{assets → src/lib/tree-sitter/assets}/typescript/highlights.scm +0 -0
  589. /package/{assets → src/lib/tree-sitter/assets}/typescript/tree-sitter-typescript.wasm +0 -0
  590. /package/{assets → src/lib/tree-sitter/assets}/zig/highlights.scm +0 -0
  591. /package/{assets → src/lib/tree-sitter/assets}/zig/tree-sitter-zig.wasm +0 -0
@@ -0,0 +1,200 @@
1
+ import { test, expect, beforeEach, afterEach, describe } from "bun:test"
2
+ import { Renderable, type RenderableOptions } from "../Renderable.js"
3
+ import { createTestRenderer, type TestRenderer } from "../testing/test-renderer.js"
4
+ import type { RenderContext } from "../types.js"
5
+ import type { OptimizedBuffer } from "../buffer.js"
6
+
7
+ class TestRenderable extends Renderable {
8
+ public renderSelfCalled = false
9
+ public customOnUpdate?: () => void
10
+
11
+ constructor(ctx: RenderContext, options: RenderableOptions) {
12
+ super(ctx, options)
13
+ }
14
+
15
+ public override onUpdate(deltaTime: number): void {
16
+ if (this.customOnUpdate) {
17
+ this.customOnUpdate()
18
+ }
19
+ }
20
+
21
+ protected override renderSelf(buffer: OptimizedBuffer, deltaTime: number): void {
22
+ this.renderSelfCalled = true
23
+ }
24
+ }
25
+
26
+ let testRenderer: TestRenderer
27
+ let renderOnce: () => Promise<void>
28
+
29
+ beforeEach(async () => {
30
+ ;({ renderer: testRenderer, renderOnce } = await createTestRenderer({}))
31
+ })
32
+
33
+ afterEach(() => {
34
+ testRenderer.destroy()
35
+ })
36
+
37
+ describe("Destroy During Render - Actual Bugs", () => {
38
+ test("BUG: destroying self in onUpdate still calls renderSelf", async () => {
39
+ const renderable = new TestRenderable(testRenderer, {
40
+ id: "test",
41
+ width: 100,
42
+ height: 100,
43
+ })
44
+
45
+ renderable.customOnUpdate = () => {
46
+ renderable.destroy()
47
+ }
48
+
49
+ testRenderer.root.add(renderable)
50
+ await renderOnce()
51
+
52
+ expect(renderable.isDestroyed).toBe(true)
53
+ // BUG: renderSelf should NOT be called after destroy in onUpdate
54
+ expect(renderable.renderSelfCalled).toBe(false)
55
+ })
56
+
57
+ test("BUG: destroying child in parent's onUpdate, child still renders", async () => {
58
+ const parent = new TestRenderable(testRenderer, {
59
+ id: "parent",
60
+ width: 100,
61
+ height: 100,
62
+ })
63
+ const child = new TestRenderable(testRenderer, {
64
+ id: "child",
65
+ width: 50,
66
+ height: 50,
67
+ })
68
+
69
+ parent.add(child)
70
+ testRenderer.root.add(parent)
71
+
72
+ parent.customOnUpdate = () => {
73
+ child.destroy()
74
+ }
75
+
76
+ await renderOnce()
77
+
78
+ expect(child.isDestroyed).toBe(true)
79
+ // BUG: Child should not render if destroyed in parent's onUpdate
80
+ expect(child.renderSelfCalled).toBe(false)
81
+ })
82
+
83
+ test("BUG: destroying sibling in onUpdate, sibling still renders", async () => {
84
+ const parent = new TestRenderable(testRenderer, { id: "parent" })
85
+ const child1 = new TestRenderable(testRenderer, {
86
+ id: "child1",
87
+ width: 50,
88
+ height: 50,
89
+ })
90
+ const child2 = new TestRenderable(testRenderer, {
91
+ id: "child2",
92
+ width: 50,
93
+ height: 50,
94
+ })
95
+
96
+ parent.add(child1)
97
+ parent.add(child2)
98
+ testRenderer.root.add(parent)
99
+
100
+ child1.customOnUpdate = () => {
101
+ child2.destroy()
102
+ }
103
+
104
+ await renderOnce()
105
+
106
+ expect(child2.isDestroyed).toBe(true)
107
+ // BUG: child2 should not render if destroyed by sibling's onUpdate
108
+ expect(child2.renderSelfCalled).toBe(false)
109
+ })
110
+
111
+ test("BUG: destroying sibling in renderBefore, sibling (later in render list) still renders", async () => {
112
+ const parent = new TestRenderable(testRenderer, { id: "parent" })
113
+ const child2 = new TestRenderable(testRenderer, {
114
+ id: "child2",
115
+ width: 50,
116
+ height: 50,
117
+ zIndex: 2,
118
+ })
119
+
120
+ const child1 = new TestRenderable(testRenderer, {
121
+ id: "child1",
122
+ width: 50,
123
+ height: 50,
124
+ zIndex: 1,
125
+ renderBefore: function () {
126
+ child2.destroy()
127
+ },
128
+ })
129
+
130
+ parent.add(child1)
131
+ parent.add(child2)
132
+ testRenderer.root.add(parent)
133
+
134
+ await renderOnce()
135
+
136
+ expect(child2.isDestroyed).toBe(true)
137
+ // BUG: child2 should not render since it was destroyed before its turn
138
+ expect(child2.renderSelfCalled).toBe(false)
139
+ })
140
+
141
+ test("BUG: onLifecyclePass not called (registration issue)", async () => {
142
+ let lifecyclePassCalled = false
143
+
144
+ const renderable = new TestRenderable(testRenderer, { id: "test" })
145
+ renderable.onLifecyclePass = () => {
146
+ lifecyclePassCalled = true
147
+ }
148
+
149
+ testRenderer.root.add(renderable)
150
+ await renderOnce()
151
+
152
+ // BUG: Lifecycle pass should be called but isn't
153
+ expect(lifecyclePassCalled).toBe(true)
154
+ })
155
+ })
156
+
157
+ describe("Destroy During Render - Working Cases (for documentation)", () => {
158
+ test("WORKS: destroying self in renderAfter", async () => {
159
+ const renderable = new TestRenderable(testRenderer, {
160
+ id: "test",
161
+ width: 100,
162
+ height: 100,
163
+ renderAfter: function () {
164
+ this.destroy()
165
+ },
166
+ })
167
+
168
+ testRenderer.root.add(renderable)
169
+ await renderOnce()
170
+
171
+ expect(renderable.isDestroyed).toBe(true)
172
+ // renderSelf was already called by this point, which is fine
173
+ expect(renderable.renderSelfCalled).toBe(true)
174
+ })
175
+
176
+ test("WORKS: destroying child in renderAfter", async () => {
177
+ const child = new TestRenderable(testRenderer, {
178
+ id: "child",
179
+ width: 50,
180
+ height: 50,
181
+ })
182
+
183
+ const parent = new TestRenderable(testRenderer, {
184
+ id: "parent",
185
+ width: 100,
186
+ height: 100,
187
+ renderAfter: function () {
188
+ child.destroy()
189
+ },
190
+ })
191
+
192
+ parent.add(child)
193
+ testRenderer.root.add(parent)
194
+
195
+ await renderOnce()
196
+
197
+ expect(child.isDestroyed).toBe(true)
198
+ // Child already rendered before parent's renderAfter, which is expected
199
+ })
200
+ })
@@ -0,0 +1,36 @@
1
+ import { Readable } from "node:stream"
2
+ import { createTestRenderer } from "@opentui/core/testing"
3
+
4
+ const code = parseInt(process.argv[2] ?? "0", 10)
5
+ const mode = process.argv[3] ?? "idle"
6
+
7
+ const stdin = new Readable({ read() {} }) as NodeJS.ReadStream & {
8
+ setRawMode: (enabled: boolean) => NodeJS.ReadStream
9
+ }
10
+ stdin.setRawMode = (enabled) => {
11
+ if (!enabled) {
12
+ console.log("raw mode disabled")
13
+ }
14
+ return stdin
15
+ }
16
+
17
+ const { renderer } = await createTestRenderer({ width: 20, height: 10, stdin })
18
+ const lib = (renderer as any).lib
19
+ const originalSuspendRenderer = lib.suspendRenderer.bind(lib)
20
+ lib.suspendRenderer = (rendererPtr: unknown) => {
21
+ console.log("renderer suspended")
22
+ originalSuspendRenderer(rendererPtr)
23
+ }
24
+
25
+ process.on("exit", () => {
26
+ renderer.destroy()
27
+ })
28
+
29
+ if (mode === "during-render") {
30
+ renderer.setFrameCallback(async () => {
31
+ process.exit(code)
32
+ })
33
+ renderer.start()
34
+ } else {
35
+ process.exit(code)
36
+ }
@@ -0,0 +1,41 @@
1
+ import { describe, expect, it } from "bun:test"
2
+ import { join } from "node:path"
3
+
4
+ const fixturePath = join(import.meta.dir, "destroy-on-exit.fixture.ts")
5
+
6
+ const runFixture = (code: number, mode: "idle" | "during-render" = "idle") => {
7
+ const result = Bun.spawnSync([process.execPath, fixturePath, code.toString(), mode], {
8
+ cwd: join(import.meta.dir, ".."),
9
+ stdout: "pipe",
10
+ stderr: "pipe",
11
+ env: process.env,
12
+ })
13
+
14
+ const stdout = result.stdout.toString()
15
+
16
+ return { result, stdout }
17
+ }
18
+
19
+ describe("destroy on process exit", () => {
20
+ it("it should let applications restore terminal state in an exit handler", () => {
21
+ const { result, stdout } = runFixture(0)
22
+
23
+ expect(result.exitCode).toBe(0)
24
+ expect(stdout).toInclude("raw mode disabled")
25
+ })
26
+
27
+ it("it should restore terminal state for non-zero exit codes", () => {
28
+ const { result, stdout } = runFixture(1)
29
+
30
+ expect(result.exitCode).toBe(1)
31
+ expect(stdout).toInclude("raw mode disabled")
32
+ })
33
+
34
+ it("it should suspend the renderer when destroy happens during an active frame in an exit handler", () => {
35
+ const { result, stdout } = runFixture(0, "during-render")
36
+
37
+ expect(result.exitCode).toBe(0)
38
+ expect(stdout).toInclude("raw mode disabled")
39
+ expect(stdout).toInclude("renderer suspended")
40
+ })
41
+ })
@@ -0,0 +1,98 @@
1
+ import { beforeEach, describe, expect, test, afterEach } from "bun:test"
2
+ import { createTestRenderer, MouseButtons, type MockMouse, type TestRenderer } from "../testing.js"
3
+ import { BoxRenderable } from "../renderables/index.js"
4
+ import type { MousePointerStyle } from "../types.js"
5
+
6
+ describe("mouse pointer style", () => {
7
+ let renderer: TestRenderer
8
+ let mockMouse: MockMouse
9
+ let renderOnce: () => Promise<void>
10
+
11
+ beforeEach(async () => {
12
+ ;({ renderer, mockMouse, renderOnce } = await createTestRenderer({ width: 40, height: 20 }))
13
+ })
14
+
15
+ afterEach(() => {
16
+ renderer.destroy()
17
+ })
18
+
19
+ test("setMousePointer sets style", async () => {
20
+ renderer.setMousePointer("pointer")
21
+ expect((renderer as any)._currentMousePointerStyle).toBe("pointer")
22
+ })
23
+
24
+ test("setMousePointer with 'default' clears style", async () => {
25
+ renderer.setMousePointer("pointer")
26
+ renderer.setMousePointer("default")
27
+ expect((renderer as any)._currentMousePointerStyle).toBe("default")
28
+ })
29
+
30
+ test("setMousePointer supports all style types", async () => {
31
+ const styles: MousePointerStyle[] = ["default", "pointer", "text", "crosshair", "move", "not-allowed"]
32
+ for (const style of styles) {
33
+ renderer.setMousePointer(style)
34
+ expect((renderer as any)._currentMousePointerStyle).toBe(style)
35
+ }
36
+ })
37
+
38
+ test("onMouseOver callback can set mouse pointer", async () => {
39
+ let pointerSet = false
40
+ const box = new BoxRenderable(renderer, {
41
+ position: "absolute",
42
+ left: 5,
43
+ top: 5,
44
+ width: 10,
45
+ height: 5,
46
+ onMouseOver() {
47
+ this.ctx.setMousePointer("pointer")
48
+ pointerSet = true
49
+ },
50
+ })
51
+ renderer.root.add(box)
52
+ await renderOnce()
53
+
54
+ await mockMouse.moveTo(10, 7)
55
+ await renderOnce()
56
+
57
+ expect(pointerSet).toBe(true)
58
+ expect((renderer as any)._currentMousePointerStyle).toBe("pointer")
59
+ })
60
+
61
+ test("onMouseOut callback can reset mouse pointer", async () => {
62
+ let pointerReset = false
63
+ const box = new BoxRenderable(renderer, {
64
+ position: "absolute",
65
+ left: 5,
66
+ top: 5,
67
+ width: 10,
68
+ height: 5,
69
+ onMouseOver() {
70
+ this.ctx.setMousePointer("pointer")
71
+ },
72
+ onMouseOut() {
73
+ this.ctx.setMousePointer("default")
74
+ pointerReset = true
75
+ },
76
+ })
77
+ renderer.root.add(box)
78
+ await renderOnce()
79
+
80
+ // Move into box
81
+ await mockMouse.moveTo(10, 7)
82
+ await renderOnce()
83
+ expect((renderer as any)._currentMousePointerStyle).toBe("pointer")
84
+
85
+ // Move out of box
86
+ await mockMouse.moveTo(1, 1)
87
+ await renderOnce()
88
+
89
+ expect(pointerReset).toBe(true)
90
+ expect((renderer as any)._currentMousePointerStyle).toBe("default")
91
+ })
92
+
93
+ test("pointer resets on renderer destroy", async () => {
94
+ renderer.setMousePointer("pointer")
95
+ renderer.destroy()
96
+ // After destroy, the reset is called internally - just verify no error
97
+ })
98
+ })
@@ -0,0 +1,173 @@
1
+ import { test, expect } from "bun:test"
2
+ import { NativeSpanFeed } from "../NativeSpanFeed.js"
3
+ import { resolveRenderLib } from "../zig.js"
4
+
5
+ const lib = resolveRenderLib()
6
+
7
+ function writeAndCommit(stream: NativeSpanFeed, data: Uint8Array): void {
8
+ lib.streamWrite(stream.streamPtr, data)
9
+ lib.streamCommit(stream.streamPtr)
10
+ }
11
+
12
+ test("async handler keeps chunk pinned until Promise resolves", async () => {
13
+ // Single chunk forces reuse; async handlers must keep data pinned.
14
+ const stream = NativeSpanFeed.create({ chunkSize: 64, initialChunks: 1 })
15
+
16
+ let resolveHandler!: () => void
17
+ const handlerDone = new Promise<void>((r) => {
18
+ resolveHandler = r
19
+ })
20
+
21
+ let capturedData: Uint8Array | null = null
22
+ let dataValidAtResolve = false
23
+
24
+ stream.onData(async (data) => {
25
+ capturedData = data
26
+ const originalBytes = new Uint8Array(data)
27
+ await handlerDone
28
+ dataValidAtResolve = capturedData.every((b, i) => b === originalBytes[i])
29
+ })
30
+ const original = new Uint8Array(64)
31
+ for (let i = 0; i < 64; i++) original[i] = i
32
+ writeAndCommit(stream, original)
33
+ const overwrite = new Uint8Array(64).fill(0xff)
34
+ writeAndCommit(stream, overwrite)
35
+ stream.drainAll()
36
+ resolveHandler()
37
+ await new Promise((r) => setTimeout(r, 10))
38
+
39
+ expect(capturedData).not.toBeNull()
40
+ expect(dataValidAtResolve).toBe(true)
41
+
42
+ stream.close()
43
+ })
44
+
45
+ test("mixed sync and async handlers on same stream", async () => {
46
+ const stream = NativeSpanFeed.create({ chunkSize: 256, initialChunks: 1 })
47
+
48
+ const syncReceived: string[] = []
49
+ let asyncReceived: string[] = []
50
+ let resolveAsync!: () => void
51
+ const asyncDone = new Promise<void>((r) => {
52
+ resolveAsync = r
53
+ })
54
+
55
+ stream.onData((data) => {
56
+ syncReceived.push(new TextDecoder().decode(data))
57
+ })
58
+ stream.onData(async (data) => {
59
+ const text = new TextDecoder().decode(data)
60
+ await asyncDone
61
+ asyncReceived.push(text)
62
+ })
63
+
64
+ const msg = new TextEncoder().encode("hello")
65
+ writeAndCommit(stream, msg)
66
+ stream.drainAll()
67
+
68
+ expect(syncReceived).toEqual(["hello"])
69
+ expect(asyncReceived).toEqual([])
70
+ resolveAsync()
71
+ await new Promise((r) => setTimeout(r, 10))
72
+
73
+ expect(asyncReceived).toEqual(["hello"])
74
+
75
+ stream.close()
76
+ })
77
+
78
+ test("async handler rejection still decrements refcount", async () => {
79
+ const stream = NativeSpanFeed.create({ chunkSize: 64, initialChunks: 1 })
80
+
81
+ stream.onData(async () => {
82
+ throw new Error("async failure")
83
+ })
84
+
85
+ const data = new Uint8Array(64).fill(0xaa)
86
+ writeAndCommit(stream, data)
87
+ stream.drainAll()
88
+
89
+ await new Promise((r) => setTimeout(r, 10))
90
+ const received: Uint8Array[] = []
91
+ stream.onData((d) => {
92
+ received.push(new Uint8Array(d))
93
+ })
94
+
95
+ const data2 = new Uint8Array(64).fill(0xbb)
96
+ writeAndCommit(stream, data2)
97
+ stream.drainAll()
98
+
99
+ expect(received.length).toBe(1)
100
+ expect(received[0][0]).toBe(0xbb)
101
+
102
+ stream.close()
103
+ })
104
+
105
+ test("sync-only handlers decrement refcount immediately (no regression)", () => {
106
+ const stream = NativeSpanFeed.create({ chunkSize: 64, initialChunks: 1 })
107
+
108
+ const received: string[] = []
109
+ stream.onData((data) => {
110
+ received.push(new TextDecoder().decode(data))
111
+ })
112
+
113
+ const msg1 = new TextEncoder().encode("A".repeat(64))
114
+ writeAndCommit(stream, msg1)
115
+ stream.drainAll()
116
+ const msg2 = new TextEncoder().encode("B".repeat(64))
117
+ writeAndCommit(stream, msg2)
118
+ stream.drainAll()
119
+
120
+ expect(received.length).toBe(2)
121
+ expect(received[1]).toBe("B".repeat(64))
122
+
123
+ stream.close()
124
+ })
125
+
126
+ test("multiple async handlers all settle before refcount decrement", async () => {
127
+ const stream = NativeSpanFeed.create({ chunkSize: 64, initialChunks: 1 })
128
+
129
+ let resolve1!: () => void
130
+ let resolve2!: () => void
131
+ const done1 = new Promise<void>((r) => {
132
+ resolve1 = r
133
+ })
134
+ const done2 = new Promise<void>((r) => {
135
+ resolve2 = r
136
+ })
137
+
138
+ const order: string[] = []
139
+
140
+ stream.onData(async (_data) => {
141
+ await done1
142
+ order.push("handler1")
143
+ })
144
+
145
+ stream.onData(async (_data) => {
146
+ await done2
147
+ order.push("handler2")
148
+ })
149
+
150
+ const data = new Uint8Array(64).fill(0xcc)
151
+ writeAndCommit(stream, data)
152
+ stream.drainAll()
153
+
154
+ resolve1()
155
+ await new Promise((r) => setTimeout(r, 10))
156
+ resolve2()
157
+ await new Promise((r) => setTimeout(r, 10))
158
+
159
+ expect(order).toEqual(["handler1", "handler2"])
160
+
161
+ const received: number[] = []
162
+ stream.onData((d) => {
163
+ received.push(d[0])
164
+ })
165
+
166
+ const data2 = new Uint8Array(64).fill(0xdd)
167
+ writeAndCommit(stream, data2)
168
+ stream.drainAll()
169
+
170
+ expect(received).toContain(0xdd)
171
+
172
+ stream.close()
173
+ })
@@ -0,0 +1,120 @@
1
+ import { test, expect } from "bun:test"
2
+ import { NativeSpanFeed } from "../NativeSpanFeed.js"
3
+ import { resolveRenderLib } from "../zig.js"
4
+
5
+ const lib = resolveRenderLib()
6
+
7
+ function nextTick(): Promise<void> {
8
+ // Use a timer turn instead of process.nextTick so Promise/microtask work
9
+ // from async handlers and close deferral can settle before assertions.
10
+ return new Promise((resolve) => setTimeout(resolve, 0))
11
+ }
12
+
13
+ const enum EventId {
14
+ Closed = 5,
15
+ }
16
+
17
+ test("streamClose emits Closed once", () => {
18
+ const events: number[] = []
19
+
20
+ const streamPtr = lib.createNativeSpanFeed(null)
21
+ expect(streamPtr).not.toBe(0)
22
+ expect(streamPtr).not.toBeNull()
23
+ lib.registerNativeSpanFeedStream(streamPtr!, (eventId) => {
24
+ events.push(Number(eventId))
25
+ })
26
+ expect(lib.attachNativeSpanFeed(streamPtr!)).toBe(0)
27
+
28
+ expect(lib.streamClose(streamPtr!)).toBe(0)
29
+ expect(lib.streamClose(streamPtr!)).toBe(0)
30
+ lib.unregisterNativeSpanFeedStream(streamPtr!)
31
+ lib.destroyNativeSpanFeed(streamPtr!)
32
+
33
+ const closedEvents = events.filter((id) => id === EventId.Closed).length
34
+ expect(closedEvents).toBe(1)
35
+ })
36
+
37
+ test("destroyNativeSpanFeed emits Closed when needed", () => {
38
+ const events: number[] = []
39
+
40
+ const streamPtr = lib.createNativeSpanFeed(null)
41
+ expect(streamPtr).not.toBe(0)
42
+ expect(streamPtr).not.toBeNull()
43
+ lib.registerNativeSpanFeedStream(streamPtr!, (eventId) => {
44
+ events.push(Number(eventId))
45
+ })
46
+ expect(lib.attachNativeSpanFeed(streamPtr!)).toBe(0)
47
+ lib.destroyNativeSpanFeed(streamPtr!)
48
+
49
+ const closedEvents = events.filter((id) => id === EventId.Closed).length
50
+ expect(closedEvents).toBe(1)
51
+ })
52
+
53
+ test("close should not destroy immediately while async handler is still pending", async () => {
54
+ const stream = NativeSpanFeed.create({ chunkSize: 64, initialChunks: 1 })
55
+ const ptr = stream.streamPtr
56
+
57
+ let release!: () => void
58
+ const gate = new Promise<void>((resolve) => {
59
+ release = resolve
60
+ })
61
+
62
+ let handlerStarted = false
63
+ let handlerSettled = false
64
+
65
+ stream.onData(async (_data) => {
66
+ handlerStarted = true
67
+ await gate
68
+ handlerSettled = true
69
+ })
70
+
71
+ const payload = new Uint8Array(64).fill(0xaa)
72
+ lib.streamWrite(ptr, payload)
73
+ lib.streamCommit(ptr)
74
+ stream.drainAll()
75
+
76
+ expect(handlerStarted).toBe(true)
77
+
78
+ stream.close()
79
+
80
+ const destroyedImmediately = (stream as any).destroyed === true
81
+
82
+ release()
83
+ await nextTick()
84
+
85
+ expect(handlerSettled).toBe(true)
86
+
87
+ try {
88
+ expect(destroyedImmediately).toBe(false)
89
+ } finally {
90
+ if (!(stream as any).destroyed) {
91
+ lib.destroyNativeSpanFeed(ptr)
92
+ }
93
+ }
94
+ })
95
+
96
+ test("close should not destroy when native close reports Busy", () => {
97
+ const stream = NativeSpanFeed.create({ chunkSize: 64, initialChunks: 1, autoCommitOnFull: false })
98
+ const ptr = stream.streamPtr
99
+
100
+ const reserve = lib.streamReserve(ptr, 1)
101
+ expect(reserve.status).toBe(0)
102
+
103
+ try {
104
+ stream.close()
105
+ } catch {
106
+ // If close starts throwing on Busy, that's acceptable for this assertion.
107
+ }
108
+
109
+ const destroyedAfterBusyClose = (stream as any).destroyed === true
110
+
111
+ try {
112
+ expect(destroyedAfterBusyClose).toBe(false)
113
+ } finally {
114
+ if (!(stream as any).destroyed) {
115
+ lib.streamCommitReserved(ptr, 0)
116
+ lib.streamClose(ptr)
117
+ lib.destroyNativeSpanFeed(ptr)
118
+ }
119
+ }
120
+ })