@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,675 @@
1
+ import { describe, expect, it, beforeEach, afterEach } from "bun:test"
2
+ import { createTestRenderer, type TestRenderer, type MockInput } from "../../testing/test-renderer.js"
3
+ import { createTextareaRenderable } from "./renderable-test-utils.js"
4
+
5
+ let currentRenderer: TestRenderer
6
+ let renderOnce: () => Promise<void>
7
+ let currentMockInput: MockInput
8
+
9
+ describe("Textarea - Destroyed Renderable Event Tests", () => {
10
+ beforeEach(async () => {
11
+ ;({
12
+ renderer: currentRenderer,
13
+ renderOnce,
14
+ mockInput: currentMockInput,
15
+ } = await createTestRenderer({
16
+ width: 80,
17
+ height: 24,
18
+ }))
19
+ })
20
+
21
+ afterEach(() => {
22
+ currentRenderer.destroy()
23
+ })
24
+
25
+ describe("Keypress events on destroyed renderable", () => {
26
+ it("should not trigger handleKeyPress after destroy is called", async () => {
27
+ let keypressCalled = false
28
+ let handleKeyPressCalled = false
29
+
30
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
31
+ initialValue: "Test",
32
+ width: 40,
33
+ height: 10,
34
+ onKeyDown: () => {
35
+ keypressCalled = true
36
+ },
37
+ })
38
+
39
+ // Override handleKeyPress to track calls
40
+ const originalHandleKeyPress = editor.handleKeyPress.bind(editor)
41
+ editor.handleKeyPress = (key) => {
42
+ handleKeyPressCalled = true
43
+ return originalHandleKeyPress(key)
44
+ }
45
+
46
+ editor.focus()
47
+ await renderOnce()
48
+
49
+ // Destroy the renderable
50
+ editor.destroy()
51
+
52
+ // Reset flags
53
+ keypressCalled = false
54
+ handleKeyPressCalled = false
55
+
56
+ // Try to send a key event after destruction
57
+ currentMockInput.pressKey("A")
58
+ await new Promise((resolve) => setTimeout(resolve, 20))
59
+
60
+ expect(keypressCalled).toBe(false)
61
+ expect(handleKeyPressCalled).toBe(false)
62
+ })
63
+
64
+ it("should not trigger handleKeyPress when destroyed before blur", async () => {
65
+ let keypressCalled = false
66
+
67
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
68
+ initialValue: "Test",
69
+ width: 40,
70
+ height: 10,
71
+ onKeyDown: () => {
72
+ keypressCalled = true
73
+ },
74
+ })
75
+
76
+ editor.focus()
77
+ await renderOnce()
78
+
79
+ // Destroy without explicitly blurring first (destroy should handle this)
80
+ editor.destroy()
81
+
82
+ keypressCalled = false
83
+
84
+ currentMockInput.pressKey("B")
85
+ await new Promise((resolve) => setTimeout(resolve, 20))
86
+
87
+ expect(keypressCalled).toBe(false)
88
+ })
89
+
90
+ it("should not trigger keypress during async operations after destroy", async () => {
91
+ let keypressCount = 0
92
+
93
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
94
+ initialValue: "Test",
95
+ width: 40,
96
+ height: 10,
97
+ onKeyDown: () => {
98
+ keypressCount++
99
+ },
100
+ })
101
+
102
+ editor.focus()
103
+
104
+ // Queue multiple key presses
105
+ currentMockInput.pressKey("A")
106
+ currentMockInput.pressKey("B")
107
+
108
+ // Destroy while events might still be processing
109
+ editor.destroy()
110
+
111
+ // Queue more events after destroy
112
+ currentMockInput.pressKey("C")
113
+ currentMockInput.pressKey("D")
114
+
115
+ await new Promise((resolve) => setTimeout(resolve, 50))
116
+
117
+ // At most the first couple events should have been processed before destroy
118
+ // After destroy, no new events should be processed
119
+ expect(keypressCount).toBeLessThanOrEqual(2)
120
+ })
121
+
122
+ it("should handle rapid focus/destroy/keypress cycles", async () => {
123
+ let errors: Error[] = []
124
+
125
+ try {
126
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
127
+ initialValue: "Test",
128
+ width: 40,
129
+ height: 10,
130
+ })
131
+
132
+ editor.focus()
133
+ currentMockInput.pressKey("A")
134
+ editor.destroy()
135
+ currentMockInput.pressKey("B")
136
+
137
+ await new Promise((resolve) => setTimeout(resolve, 20))
138
+
139
+ // Create and destroy another
140
+ const { textarea: editor2 } = await createTextareaRenderable(currentRenderer, renderOnce, {
141
+ initialValue: "Test2",
142
+ width: 40,
143
+ height: 10,
144
+ })
145
+
146
+ editor2.focus()
147
+ currentMockInput.pressKey("C")
148
+ editor2.destroy()
149
+ currentMockInput.pressKey("D")
150
+
151
+ await new Promise((resolve) => setTimeout(resolve, 20))
152
+ } catch (error) {
153
+ if (error instanceof Error) {
154
+ errors.push(error)
155
+ }
156
+ }
157
+
158
+ expect(errors.length).toBe(0)
159
+ })
160
+
161
+ it("should not crash when keypressHandler fires after editBuffer is destroyed", async () => {
162
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
163
+ initialValue: "Test",
164
+ width: 40,
165
+ height: 10,
166
+ })
167
+
168
+ editor.focus()
169
+ await renderOnce()
170
+
171
+ // Destroy the whole textarea properly (not just editBuffer)
172
+ // Destroying only editBuffer while textarea is alive is undefined behavior
173
+ editor.destroy()
174
+
175
+ // Try pressing key after destroy - should be safely ignored
176
+ currentMockInput.pressKey("X")
177
+ await new Promise((resolve) => setTimeout(resolve, 20))
178
+
179
+ // Should not crash
180
+ expect(editor.isDestroyed).toBe(true)
181
+ })
182
+ })
183
+
184
+ describe("Paste events on destroyed renderable", () => {
185
+ it("should not trigger handlePaste after destroy is called", async () => {
186
+ let pasteCalled = false
187
+
188
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
189
+ initialValue: "Test",
190
+ width: 40,
191
+ height: 10,
192
+ onPaste: () => {
193
+ pasteCalled = true
194
+ },
195
+ })
196
+
197
+ editor.focus()
198
+ await renderOnce()
199
+
200
+ editor.destroy()
201
+ pasteCalled = false
202
+
203
+ await currentMockInput.pasteBracketedText("PastedText")
204
+ await new Promise((resolve) => setTimeout(resolve, 20))
205
+
206
+ expect(pasteCalled).toBe(false)
207
+ })
208
+
209
+ it("should not trigger paste during async operations after destroy", async () => {
210
+ let pasteCount = 0
211
+
212
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
213
+ initialValue: "Test",
214
+ width: 40,
215
+ height: 10,
216
+ onPaste: () => {
217
+ pasteCount++
218
+ },
219
+ })
220
+
221
+ editor.focus()
222
+
223
+ // Queue paste operation
224
+ const pastePromise = currentMockInput.pasteBracketedText("Text1")
225
+
226
+ // Destroy while paste might still be processing
227
+ editor.destroy()
228
+
229
+ // Try another paste after destroy
230
+ await currentMockInput.pasteBracketedText("Text2")
231
+
232
+ await pastePromise
233
+ await new Promise((resolve) => setTimeout(resolve, 50))
234
+
235
+ // At most the first paste should have been processed
236
+ expect(pasteCount).toBeLessThanOrEqual(1)
237
+ })
238
+ })
239
+
240
+ describe("Event handlers cleanup on destroy", () => {
241
+ it("should remove keypress handler from internal key input on destroy", async () => {
242
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
243
+ initialValue: "Test",
244
+ width: 40,
245
+ height: 10,
246
+ })
247
+
248
+ editor.focus()
249
+ await renderOnce()
250
+
251
+ // Check that handlers are set up
252
+ expect(editor.focused).toBe(true)
253
+
254
+ editor.destroy()
255
+
256
+ // After destroy, focused should be false and handlers should be removed
257
+ expect(editor.focused).toBe(false)
258
+
259
+ // Verify isDestroyed is true
260
+ expect(editor.isDestroyed).toBe(true)
261
+ })
262
+
263
+ it("should not trigger events when destroyed renderable is still in tree", async () => {
264
+ let keypressCount = 0
265
+
266
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
267
+ initialValue: "Test",
268
+ width: 40,
269
+ height: 10,
270
+ onKeyDown: () => {
271
+ keypressCount++
272
+ },
273
+ })
274
+
275
+ editor.focus()
276
+ await renderOnce()
277
+
278
+ // Destroy the renderable (this should remove it from parent and clean up handlers)
279
+ editor.destroy()
280
+
281
+ expect(editor.isDestroyed).toBe(true)
282
+ keypressCount = 0
283
+
284
+ // Try to send events
285
+ currentMockInput.pressKey("A")
286
+ await new Promise((resolve) => setTimeout(resolve, 20))
287
+
288
+ expect(keypressCount).toBe(0)
289
+ })
290
+
291
+ it("should handle destroy called multiple times", async () => {
292
+ let errorOccurred = false
293
+
294
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
295
+ initialValue: "Test",
296
+ width: 40,
297
+ height: 10,
298
+ })
299
+
300
+ editor.focus()
301
+
302
+ try {
303
+ editor.destroy()
304
+ editor.destroy()
305
+ editor.destroy()
306
+ } catch (error) {
307
+ errorOccurred = true
308
+ }
309
+
310
+ expect(errorOccurred).toBe(false)
311
+ })
312
+
313
+ it("should clean up event listeners when destroyed while handling an event", async () => {
314
+ let handlerCallCount = 0
315
+ let shouldDestroy = false
316
+ let errorThrown = false
317
+
318
+ // Capture console.error to check for error logs
319
+ const originalConsoleError = console.error
320
+ console.error = (...args: any[]) => {
321
+ if (args[0]?.includes?.("[KeyHandler] Error in renderable")) {
322
+ errorThrown = true
323
+ }
324
+ originalConsoleError(...args)
325
+ }
326
+
327
+ try {
328
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
329
+ initialValue: "Test",
330
+ width: 40,
331
+ height: 10,
332
+ onKeyDown: () => {
333
+ handlerCallCount++
334
+ if (shouldDestroy) {
335
+ editor.destroy()
336
+ }
337
+ },
338
+ })
339
+
340
+ editor.focus()
341
+
342
+ // First keypress should work
343
+ currentMockInput.pressKey("A")
344
+ await new Promise((resolve) => setTimeout(resolve, 20))
345
+ expect(handlerCallCount).toBe(1)
346
+
347
+ // Second keypress destroys the renderable
348
+ shouldDestroy = true
349
+ currentMockInput.pressKey("B")
350
+ await new Promise((resolve) => setTimeout(resolve, 20))
351
+ expect(handlerCallCount).toBe(2)
352
+
353
+ // Third keypress should not trigger anything
354
+ currentMockInput.pressKey("C")
355
+ await new Promise((resolve) => setTimeout(resolve, 20))
356
+ expect(handlerCallCount).toBe(2)
357
+
358
+ // CRITICAL: No error should be thrown when destroying during callback
359
+ expect(errorThrown).toBe(false)
360
+ } finally {
361
+ console.error = originalConsoleError
362
+ }
363
+ })
364
+ })
365
+
366
+ describe("Destroyed renderable with queued operations", () => {
367
+ it("should not process insertText after destroy", async () => {
368
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
369
+ initialValue: "Initial",
370
+ width: 40,
371
+ height: 10,
372
+ })
373
+
374
+ editor.focus()
375
+
376
+ editor.destroy()
377
+
378
+ // Try to call methods on destroyed renderable
379
+ try {
380
+ editor.insertText("New Text")
381
+ } catch (error) {
382
+ // Expected: operations might throw after destroy
383
+ expect(error).toBeDefined()
384
+ }
385
+
386
+ await new Promise((resolve) => setTimeout(resolve, 20))
387
+
388
+ // Either the operation threw an error or it was safely ignored
389
+ expect(true).toBe(true)
390
+ })
391
+
392
+ it("should handle events arriving between destroy and cleanup", async () => {
393
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
394
+ initialValue: "Test",
395
+ width: 40,
396
+ height: 10,
397
+ })
398
+
399
+ editor.focus()
400
+
401
+ // Queue several key events
402
+ currentMockInput.pressKey("A")
403
+ currentMockInput.pressKey("B")
404
+ currentMockInput.pressKey("C")
405
+
406
+ // Destroy immediately without waiting for events to process
407
+ editor.destroy()
408
+
409
+ // Events might still be in the queue
410
+ await new Promise((resolve) => setTimeout(resolve, 50))
411
+
412
+ // No crashes should occur
413
+ expect(editor.isDestroyed).toBe(true)
414
+ })
415
+
416
+ it("should safely handle focus after destroy", async () => {
417
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
418
+ initialValue: "Test",
419
+ width: 40,
420
+ height: 10,
421
+ })
422
+
423
+ editor.focus()
424
+ expect(editor.focused).toBe(true)
425
+
426
+ editor.destroy()
427
+
428
+ // Try to focus again after destroy (should be no-op or throw)
429
+ try {
430
+ editor.focus()
431
+ } catch (error) {
432
+ // May throw, that's fine
433
+ expect(error).toBeDefined()
434
+ }
435
+
436
+ // Whether it throws or not, it shouldn't crash
437
+ expect(editor.focused).toBe(false)
438
+ })
439
+ })
440
+
441
+ describe("EditorView and EditBuffer destroyed state", () => {
442
+ it("should check if editBuffer guard prevents operations after destroy", async () => {
443
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
444
+ initialValue: "Test",
445
+ width: 40,
446
+ height: 10,
447
+ })
448
+
449
+ editor.focus()
450
+
451
+ // Destroy the textarea (which should destroy editBuffer and editorView)
452
+ editor.destroy()
453
+
454
+ // Try to access editBuffer methods that should throw if destroyed
455
+ let errorThrown = false
456
+ try {
457
+ editor.editBuffer.getText()
458
+ } catch (error) {
459
+ errorThrown = true
460
+ expect((error as Error).message).toContain("destroyed")
461
+ }
462
+
463
+ expect(errorThrown).toBe(true)
464
+ })
465
+
466
+ it("should check if editorView guard prevents operations after destroy", async () => {
467
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
468
+ initialValue: "Test",
469
+ width: 40,
470
+ height: 10,
471
+ })
472
+
473
+ editor.focus()
474
+
475
+ // Destroy the textarea
476
+ editor.destroy()
477
+
478
+ // Try to access editorView methods that should throw if destroyed
479
+ let errorThrown = false
480
+ try {
481
+ editor.editorView.getCursor()
482
+ } catch (error) {
483
+ errorThrown = true
484
+ expect((error as Error).message).toContain("destroyed")
485
+ }
486
+
487
+ expect(errorThrown).toBe(true)
488
+ })
489
+
490
+ it("should not allow keypress after proper destroy", async () => {
491
+ let keypressFired = false
492
+
493
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
494
+ initialValue: "Test",
495
+ width: 40,
496
+ height: 10,
497
+ onKeyDown: () => {
498
+ keypressFired = true
499
+ },
500
+ })
501
+
502
+ editor.focus()
503
+ await renderOnce()
504
+
505
+ // Properly destroy the whole textarea
506
+ editor.destroy()
507
+
508
+ // Try to trigger a keypress after destroy
509
+ currentMockInput.pressKey("A")
510
+ await new Promise((resolve) => setTimeout(resolve, 20))
511
+
512
+ // Keypress handler should not have fired
513
+ expect(keypressFired).toBe(false)
514
+ expect(editor.isDestroyed).toBe(true)
515
+ })
516
+ })
517
+
518
+ describe("Multiple renderables and event routing", () => {
519
+ it("should not route events to destroyed renderable when multiple exist", async () => {
520
+ let editor1KeypressCount = 0
521
+ let editor2KeypressCount = 0
522
+
523
+ const { textarea: editor1 } = await createTextareaRenderable(currentRenderer, renderOnce, {
524
+ initialValue: "Editor 1",
525
+ width: 40,
526
+ height: 10,
527
+ onKeyDown: () => {
528
+ editor1KeypressCount++
529
+ },
530
+ })
531
+
532
+ const { textarea: editor2 } = await createTextareaRenderable(currentRenderer, renderOnce, {
533
+ initialValue: "Editor 2",
534
+ width: 40,
535
+ height: 10,
536
+ top: 10,
537
+ onKeyDown: () => {
538
+ editor2KeypressCount++
539
+ },
540
+ })
541
+
542
+ // Focus first editor
543
+ editor1.focus()
544
+ currentMockInput.pressKey("A")
545
+ await new Promise((resolve) => setTimeout(resolve, 20))
546
+
547
+ expect(editor1KeypressCount).toBe(1)
548
+ expect(editor2KeypressCount).toBe(0)
549
+
550
+ // Destroy first editor and focus second
551
+ editor1.destroy()
552
+ editor2.focus()
553
+
554
+ editor1KeypressCount = 0
555
+ editor2KeypressCount = 0
556
+
557
+ currentMockInput.pressKey("B")
558
+ await new Promise((resolve) => setTimeout(resolve, 20))
559
+
560
+ expect(editor1KeypressCount).toBe(0)
561
+ expect(editor2KeypressCount).toBe(1)
562
+
563
+ editor2.destroy()
564
+ })
565
+
566
+ it("should handle switching focus between renderables rapidly", async () => {
567
+ const { textarea: editor1 } = await createTextareaRenderable(currentRenderer, renderOnce, {
568
+ initialValue: "Editor 1",
569
+ width: 40,
570
+ height: 10,
571
+ })
572
+
573
+ const { textarea: editor2 } = await createTextareaRenderable(currentRenderer, renderOnce, {
574
+ initialValue: "Editor 2",
575
+ width: 40,
576
+ height: 10,
577
+ top: 10,
578
+ })
579
+
580
+ // Rapidly switch focus and destroy
581
+ editor1.focus()
582
+ editor2.focus()
583
+ editor1.destroy()
584
+ editor2.blur()
585
+ editor2.focus()
586
+ editor2.destroy()
587
+
588
+ // Send events after all destroyed
589
+ currentMockInput.pressKey("X")
590
+ await new Promise((resolve) => setTimeout(resolve, 20))
591
+
592
+ // Should not crash
593
+ expect(true).toBe(true)
594
+ })
595
+ })
596
+
597
+ describe("Renderable destroyed flag checks", () => {
598
+ it("should prevent handleKeyPress execution when isDestroyed is true", async () => {
599
+ let callCount = 0
600
+
601
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
602
+ initialValue: "Test",
603
+ width: 40,
604
+ height: 10,
605
+ })
606
+
607
+ // Wrap handleKeyPress to track calls
608
+ const originalHandleKeyPress = editor.handleKeyPress.bind(editor)
609
+ editor.handleKeyPress = (key) => {
610
+ callCount++
611
+ if (editor.isDestroyed) {
612
+ // Should not execute when destroyed
613
+ throw new Error("handleKeyPress called on destroyed renderable")
614
+ }
615
+ return originalHandleKeyPress(key)
616
+ }
617
+
618
+ editor.focus()
619
+ currentMockInput.pressKey("A")
620
+ await new Promise((resolve) => setTimeout(resolve, 20))
621
+
622
+ expect(callCount).toBe(1)
623
+
624
+ // Destroy and try again
625
+ editor.destroy()
626
+ callCount = 0
627
+
628
+ let errorThrown = false
629
+ try {
630
+ currentMockInput.pressKey("B")
631
+ await new Promise((resolve) => setTimeout(resolve, 20))
632
+ } catch (error) {
633
+ errorThrown = true
634
+ }
635
+
636
+ // Should not have called handleKeyPress after destroy
637
+ expect(callCount).toBe(0)
638
+ expect(errorThrown).toBe(false)
639
+ })
640
+
641
+ it("should check isDestroyed in event handler methods", async () => {
642
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
643
+ initialValue: "Test",
644
+ width: 40,
645
+ height: 10,
646
+ })
647
+
648
+ expect(editor.isDestroyed).toBe(false)
649
+
650
+ editor.focus()
651
+ expect(editor.isDestroyed).toBe(false)
652
+
653
+ editor.destroy()
654
+ expect(editor.isDestroyed).toBe(true)
655
+
656
+ // After destroy, operations should either fail or be no-ops
657
+ let errorCount = 0
658
+ try {
659
+ editor.focus()
660
+ } catch {
661
+ errorCount++
662
+ }
663
+
664
+ try {
665
+ editor.blur()
666
+ } catch {
667
+ errorCount++
668
+ }
669
+
670
+ // Operations after destroy should either throw or be ignored
671
+ // The important thing is we should be able to detect destroyed state
672
+ expect(editor.isDestroyed).toBe(true)
673
+ })
674
+ })
675
+ })