@fairyhunter13/opentui-core 0.1.113 → 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 +62 -53
  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-9vwc3fg6.js +0 -12260
  472. package/index-9vwc3fg6.js.map +0 -42
  473. package/index-dcj62y8t.js +0 -20614
  474. package/index-dcj62y8t.js.map +0 -67
  475. package/index-f7n39gpy.js +0 -411
  476. package/index-f7n39gpy.js.map +0 -10
  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,738 @@
1
+ import { describe, expect, it, beforeEach, afterEach } from "bun:test"
2
+ import { createTestRenderer, type TestRenderer, type MockMouse, 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 - Event Handlers 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("Change Events", () => {
26
+ describe("onCursorChange", () => {
27
+ it("should fire onCursorChange when cursor moves", async () => {
28
+ let cursorChangeCount = 0
29
+ let lastCursorEvent: { line: number; visualColumn: number } | null = null
30
+
31
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
32
+ initialValue: "Line 1\nLine 2\nLine 3",
33
+ width: 40,
34
+ height: 10,
35
+ onCursorChange: (event) => {
36
+ cursorChangeCount++
37
+ lastCursorEvent = event
38
+ },
39
+ })
40
+
41
+ editor.focus()
42
+ const initialCount = cursorChangeCount
43
+
44
+ editor.moveCursorRight()
45
+ await new Promise((resolve) => setTimeout(resolve, 10))
46
+
47
+ expect(cursorChangeCount).toBeGreaterThan(initialCount)
48
+ expect(lastCursorEvent).not.toBe(null)
49
+ expect(lastCursorEvent!.line).toBe(0)
50
+ expect(lastCursorEvent!.visualColumn).toBe(1)
51
+
52
+ const prevCount = cursorChangeCount
53
+
54
+ editor.moveCursorDown()
55
+ await new Promise((resolve) => setTimeout(resolve, 20))
56
+
57
+ expect(cursorChangeCount).toBeGreaterThanOrEqual(prevCount)
58
+ expect(lastCursorEvent).not.toBe(null)
59
+ expect(lastCursorEvent!.line).toBeGreaterThanOrEqual(0)
60
+ })
61
+
62
+ it("should fire onCursorChange when typing moves cursor", async () => {
63
+ let cursorChangeCount = 0
64
+ let lastCursorEvent: { line: number; visualColumn: number } | null = null
65
+
66
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
67
+ initialValue: "",
68
+ width: 40,
69
+ height: 10,
70
+ onCursorChange: (event) => {
71
+ cursorChangeCount++
72
+ lastCursorEvent = event
73
+ },
74
+ })
75
+
76
+ editor.focus()
77
+ const initialCount = cursorChangeCount
78
+
79
+ currentMockInput.pressKey("H")
80
+ await new Promise((resolve) => setTimeout(resolve, 10))
81
+
82
+ expect(cursorChangeCount).toBeGreaterThan(initialCount)
83
+ expect(lastCursorEvent).not.toBe(null)
84
+ expect(lastCursorEvent!.line).toBe(0)
85
+ expect(lastCursorEvent!.visualColumn).toBe(1)
86
+ })
87
+
88
+ it("should fire onCursorChange when pressing arrow keys", async () => {
89
+ let cursorEventCount = 0
90
+ let lastCursorEvent: { line: number; visualColumn: number } | null = null
91
+
92
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
93
+ initialValue: "ABC\nDEF",
94
+ width: 40,
95
+ height: 10,
96
+ onCursorChange: (event) => {
97
+ cursorEventCount++
98
+ lastCursorEvent = event
99
+ },
100
+ })
101
+
102
+ editor.focus()
103
+ const initialCount = cursorEventCount
104
+
105
+ currentMockInput.pressArrow("right")
106
+ await new Promise((resolve) => setTimeout(resolve, 10))
107
+
108
+ expect(cursorEventCount).toBeGreaterThan(initialCount)
109
+ expect(lastCursorEvent).not.toBe(null)
110
+ expect(lastCursorEvent!.visualColumn).toBe(1)
111
+
112
+ const beforeDown = cursorEventCount
113
+ currentMockInput.pressArrow("down")
114
+ await new Promise((resolve) => setTimeout(resolve, 20))
115
+
116
+ expect(cursorEventCount).toBeGreaterThanOrEqual(beforeDown)
117
+ expect(lastCursorEvent).not.toBe(null)
118
+ })
119
+
120
+ it("should fire onCursorChange when using gotoLine", async () => {
121
+ let cursorChangeCount = 0
122
+ let lastCursorEvent: { line: number; visualColumn: number } | null = null
123
+
124
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
125
+ initialValue: "Line 0\nLine 1\nLine 2",
126
+ width: 40,
127
+ height: 10,
128
+ onCursorChange: (event) => {
129
+ cursorChangeCount++
130
+ lastCursorEvent = event
131
+ },
132
+ })
133
+
134
+ editor.focus()
135
+ const initialCount = cursorChangeCount
136
+
137
+ editor.gotoLine(2)
138
+ await new Promise((resolve) => setTimeout(resolve, 10))
139
+
140
+ expect(cursorChangeCount).toBeGreaterThan(initialCount)
141
+ expect(lastCursorEvent).not.toBe(null)
142
+ expect(lastCursorEvent!.line).toBe(2)
143
+ expect(lastCursorEvent!.visualColumn).toBe(0)
144
+ })
145
+
146
+ it("should fire onCursorChange after undo", async () => {
147
+ let cursorChangeCount = 0
148
+
149
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
150
+ initialValue: "",
151
+ width: 40,
152
+ height: 10,
153
+ onCursorChange: () => {
154
+ cursorChangeCount++
155
+ },
156
+ })
157
+
158
+ editor.focus()
159
+
160
+ currentMockInput.pressKey("H")
161
+ currentMockInput.pressKey("i")
162
+ await new Promise((resolve) => setTimeout(resolve, 10))
163
+
164
+ const beforeUndo = cursorChangeCount
165
+
166
+ editor.undo()
167
+ await new Promise((resolve) => setTimeout(resolve, 10))
168
+
169
+ expect(cursorChangeCount).toBeGreaterThan(beforeUndo)
170
+ })
171
+
172
+ it("should update event handler when set dynamically", async () => {
173
+ let firstHandlerCalled = false
174
+ let secondHandlerCalled = false
175
+
176
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
177
+ initialValue: "Test",
178
+ width: 40,
179
+ height: 10,
180
+ onCursorChange: () => {
181
+ firstHandlerCalled = true
182
+ },
183
+ })
184
+
185
+ editor.focus()
186
+
187
+ editor.moveCursorRight()
188
+ await new Promise((resolve) => setTimeout(resolve, 10))
189
+ expect(firstHandlerCalled).toBe(true)
190
+
191
+ editor.onCursorChange = () => {
192
+ secondHandlerCalled = true
193
+ }
194
+
195
+ editor.moveCursorRight()
196
+ await new Promise((resolve) => setTimeout(resolve, 10))
197
+ expect(secondHandlerCalled).toBe(true)
198
+ })
199
+
200
+ it("should not fire when handler is undefined", async () => {
201
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
202
+ initialValue: "Test",
203
+ width: 40,
204
+ height: 10,
205
+ onCursorChange: undefined,
206
+ })
207
+
208
+ editor.focus()
209
+
210
+ editor.moveCursorRight()
211
+ expect(editor.logicalCursor.col).toBe(1)
212
+ })
213
+ })
214
+
215
+ describe("onContentChange", () => {
216
+ it("should fire onContentChange when typing", async () => {
217
+ let contentChangeCount = 0
218
+
219
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
220
+ initialValue: "",
221
+ width: 40,
222
+ height: 10,
223
+ onContentChange: () => {
224
+ contentChangeCount++
225
+ },
226
+ })
227
+
228
+ editor.focus()
229
+ const initialCount = contentChangeCount
230
+
231
+ currentMockInput.pressKey("H")
232
+ await new Promise((resolve) => setTimeout(resolve, 10))
233
+
234
+ expect(contentChangeCount).toBeGreaterThan(initialCount)
235
+ expect(editor.plainText).toBe("H")
236
+ })
237
+
238
+ it("should fire onContentChange when deleting", async () => {
239
+ let contentChangeCount = 0
240
+
241
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
242
+ initialValue: "Hello",
243
+ width: 40,
244
+ height: 10,
245
+ onContentChange: () => {
246
+ contentChangeCount++
247
+ },
248
+ })
249
+
250
+ editor.focus()
251
+ editor.gotoLine(9999)
252
+ const initialCount = contentChangeCount
253
+
254
+ currentMockInput.pressBackspace()
255
+ await new Promise((resolve) => setTimeout(resolve, 10))
256
+
257
+ expect(contentChangeCount).toBeGreaterThan(initialCount)
258
+ expect(editor.plainText).toBe("Hell")
259
+ })
260
+
261
+ it("should fire onContentChange when inserting newline", async () => {
262
+ let contentChangeCount = 0
263
+
264
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
265
+ initialValue: "Test",
266
+ width: 40,
267
+ height: 10,
268
+ onContentChange: () => {
269
+ contentChangeCount++
270
+ },
271
+ })
272
+
273
+ editor.focus()
274
+ editor.gotoLine(9999)
275
+ const initialCount = contentChangeCount
276
+
277
+ currentMockInput.pressEnter()
278
+ await new Promise((resolve) => setTimeout(resolve, 10))
279
+
280
+ expect(contentChangeCount).toBeGreaterThan(initialCount)
281
+ expect(editor.plainText).toBe("Test\n")
282
+ })
283
+
284
+ it("should fire onContentChange when pasting", async () => {
285
+ let contentChangeCount = 0
286
+
287
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
288
+ initialValue: "Hello",
289
+ width: 40,
290
+ height: 10,
291
+ onContentChange: () => {
292
+ contentChangeCount++
293
+ },
294
+ })
295
+
296
+ editor.focus()
297
+ editor.gotoLine(9999)
298
+
299
+ const initialCount = contentChangeCount
300
+
301
+ await currentMockInput.pasteBracketedText(" World")
302
+
303
+ expect(contentChangeCount).toBeGreaterThan(initialCount)
304
+ expect(editor.plainText).toBe("Hello World")
305
+ })
306
+
307
+ it("should fire onContentChange after undo", async () => {
308
+ let contentChangeCount = 0
309
+
310
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
311
+ initialValue: "",
312
+ width: 40,
313
+ height: 10,
314
+ onContentChange: () => {
315
+ contentChangeCount++
316
+ },
317
+ })
318
+
319
+ editor.focus()
320
+
321
+ currentMockInput.pressKey("T")
322
+ currentMockInput.pressKey("e")
323
+ await new Promise((resolve) => setTimeout(resolve, 20))
324
+
325
+ const beforeUndo = contentChangeCount
326
+
327
+ editor.undo()
328
+ await new Promise((resolve) => setTimeout(resolve, 20))
329
+
330
+ expect(contentChangeCount).toBeGreaterThanOrEqual(beforeUndo)
331
+ expect(editor.plainText).toBe("T")
332
+ })
333
+
334
+ it("should fire onContentChange after redo", async () => {
335
+ let contentChangeCount = 0
336
+
337
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
338
+ initialValue: "",
339
+ width: 40,
340
+ height: 10,
341
+ onContentChange: () => {
342
+ contentChangeCount++
343
+ },
344
+ })
345
+
346
+ editor.focus()
347
+
348
+ currentMockInput.pressKey("X")
349
+ await new Promise((resolve) => setTimeout(resolve, 20))
350
+ editor.undo()
351
+ await new Promise((resolve) => setTimeout(resolve, 20))
352
+
353
+ const beforeRedo = contentChangeCount
354
+
355
+ editor.redo()
356
+ await new Promise((resolve) => setTimeout(resolve, 20))
357
+
358
+ expect(contentChangeCount).toBeGreaterThanOrEqual(beforeRedo)
359
+ expect(editor.plainText).toBe("X")
360
+ })
361
+
362
+ it("should fire onContentChange when setting value programmatically", async () => {
363
+ let contentChangeCount = 0
364
+
365
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
366
+ initialValue: "Initial",
367
+ width: 40,
368
+ height: 10,
369
+ onContentChange: () => {
370
+ contentChangeCount++
371
+ },
372
+ })
373
+
374
+ const initialCount = contentChangeCount
375
+
376
+ editor.setText("Updated")
377
+ await new Promise((resolve) => setTimeout(resolve, 10))
378
+
379
+ expect(contentChangeCount).toBeGreaterThan(initialCount)
380
+ expect(editor.plainText).toBe("Updated")
381
+ })
382
+
383
+ it("should fire onContentChange when deleting selection", async () => {
384
+ let contentChangeCount = 0
385
+
386
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
387
+ initialValue: "Hello World",
388
+ width: 40,
389
+ height: 10,
390
+ selectable: true,
391
+ onContentChange: () => {
392
+ contentChangeCount++
393
+ },
394
+ })
395
+
396
+ editor.focus()
397
+
398
+ for (let i = 0; i < 5; i++) {
399
+ currentMockInput.pressArrow("right", { shift: true })
400
+ }
401
+ await new Promise((resolve) => setTimeout(resolve, 10))
402
+
403
+ const beforeDelete = contentChangeCount
404
+
405
+ currentMockInput.pressBackspace()
406
+ await new Promise((resolve) => setTimeout(resolve, 10))
407
+
408
+ expect(contentChangeCount).toBeGreaterThan(beforeDelete)
409
+ expect(editor.plainText).toBe(" World")
410
+ })
411
+
412
+ it("should update event handler when set dynamically", async () => {
413
+ let firstHandlerCalled = false
414
+ let secondHandlerCalled = false
415
+
416
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
417
+ initialValue: "",
418
+ width: 40,
419
+ height: 10,
420
+ onContentChange: () => {
421
+ firstHandlerCalled = true
422
+ },
423
+ })
424
+
425
+ editor.focus()
426
+
427
+ currentMockInput.pressKey("A")
428
+ await new Promise((resolve) => setTimeout(resolve, 10))
429
+ expect(firstHandlerCalled).toBe(true)
430
+
431
+ editor.onContentChange = () => {
432
+ secondHandlerCalled = true
433
+ }
434
+
435
+ currentMockInput.pressKey("B")
436
+ await new Promise((resolve) => setTimeout(resolve, 10))
437
+ expect(secondHandlerCalled).toBe(true)
438
+ })
439
+
440
+ it("should not fire when handler is undefined", async () => {
441
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
442
+ initialValue: "",
443
+ width: 40,
444
+ height: 10,
445
+ onContentChange: undefined,
446
+ })
447
+
448
+ editor.focus()
449
+
450
+ currentMockInput.pressKey("X")
451
+ expect(editor.plainText).toBe("X")
452
+ })
453
+
454
+ it("should fire exactly once when setting via setter and pressing a key", async () => {
455
+ let contentChangeCount = 0
456
+
457
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
458
+ initialValue: "",
459
+ width: 40,
460
+ height: 10,
461
+ })
462
+
463
+ editor.focus()
464
+
465
+ editor.onContentChange = () => {
466
+ contentChangeCount++
467
+ }
468
+
469
+ currentMockInput.pressKey("X")
470
+ await new Promise((resolve) => setTimeout(resolve, 10))
471
+
472
+ expect(contentChangeCount).toBe(1)
473
+ expect(editor.plainText).toBe("X")
474
+ })
475
+ })
476
+
477
+ describe("onSubmit", () => {
478
+ it("should fire onSubmit with default keybinding (Meta+Enter)", async () => {
479
+ let submitCount = 0
480
+
481
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
482
+ initialValue: "Test content",
483
+ width: 40,
484
+ height: 10,
485
+ onSubmit: () => {
486
+ submitCount++
487
+ },
488
+ })
489
+
490
+ editor.focus()
491
+ const initialCount = submitCount
492
+
493
+ currentMockInput.pressEnter({ meta: true })
494
+ await new Promise((resolve) => setTimeout(resolve, 10))
495
+
496
+ expect(submitCount).toBe(initialCount + 1)
497
+ expect(editor.plainText).toBe("Test content")
498
+ })
499
+
500
+ it("should fire onSubmit with alternative keybinding (Meta+Return)", async () => {
501
+ let submitCount = 0
502
+
503
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
504
+ initialValue: "Test",
505
+ width: 40,
506
+ height: 10,
507
+ onSubmit: () => {
508
+ submitCount++
509
+ },
510
+ })
511
+
512
+ editor.focus()
513
+
514
+ currentMockInput.pressEnter({ meta: true })
515
+ await new Promise((resolve) => setTimeout(resolve, 10))
516
+
517
+ expect(submitCount).toBe(1)
518
+ })
519
+
520
+ it("should not insert newline when submitting", async () => {
521
+ let submitCount = 0
522
+
523
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
524
+ initialValue: "Test",
525
+ width: 40,
526
+ height: 10,
527
+ onSubmit: () => {
528
+ submitCount++
529
+ },
530
+ })
531
+
532
+ editor.focus()
533
+ editor.gotoLine(9999)
534
+
535
+ currentMockInput.pressEnter({ meta: true })
536
+ await new Promise((resolve) => setTimeout(resolve, 10))
537
+
538
+ expect(submitCount).toBe(1)
539
+ expect(editor.plainText).toBe("Test")
540
+ })
541
+
542
+ it("should update handler via setter", async () => {
543
+ let firstHandlerCalled = false
544
+ let secondHandlerCalled = false
545
+
546
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
547
+ initialValue: "",
548
+ width: 40,
549
+ height: 10,
550
+ onSubmit: () => {
551
+ firstHandlerCalled = true
552
+ },
553
+ })
554
+
555
+ editor.focus()
556
+
557
+ currentMockInput.pressEnter({ meta: true })
558
+ await new Promise((resolve) => setTimeout(resolve, 10))
559
+ expect(firstHandlerCalled).toBe(true)
560
+
561
+ editor.onSubmit = () => {
562
+ secondHandlerCalled = true
563
+ }
564
+
565
+ currentMockInput.pressEnter({ meta: true })
566
+ await new Promise((resolve) => setTimeout(resolve, 10))
567
+ expect(secondHandlerCalled).toBe(true)
568
+ })
569
+
570
+ it("should not fire when handler is undefined", async () => {
571
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
572
+ initialValue: "Test",
573
+ width: 40,
574
+ height: 10,
575
+ onSubmit: undefined,
576
+ })
577
+
578
+ editor.focus()
579
+
580
+ currentMockInput.pressEnter({ meta: true })
581
+ expect(editor.plainText).toBe("Test")
582
+ })
583
+
584
+ it("should support custom keybinding for submit", async () => {
585
+ let submitCount = 0
586
+
587
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
588
+ initialValue: "Test",
589
+ width: 40,
590
+ height: 10,
591
+ keyBindings: [{ name: "s", ctrl: true, action: "submit" }],
592
+ onSubmit: () => {
593
+ submitCount++
594
+ },
595
+ })
596
+
597
+ editor.focus()
598
+
599
+ currentMockInput.pressKey("s", { ctrl: true })
600
+ await new Promise((resolve) => setTimeout(resolve, 10))
601
+
602
+ expect(submitCount).toBe(1)
603
+ })
604
+
605
+ it("should get current handler via getter", async () => {
606
+ const handler = () => {}
607
+
608
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
609
+ initialValue: "",
610
+ width: 40,
611
+ height: 10,
612
+ onSubmit: handler,
613
+ })
614
+
615
+ expect(editor.onSubmit).toBe(handler)
616
+ })
617
+
618
+ it("should allow removing handler by setting to undefined", async () => {
619
+ let submitCount = 0
620
+
621
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
622
+ initialValue: "",
623
+ width: 40,
624
+ height: 10,
625
+ onSubmit: () => {
626
+ submitCount++
627
+ },
628
+ })
629
+
630
+ editor.focus()
631
+
632
+ currentMockInput.pressEnter({ meta: true })
633
+ await new Promise((resolve) => setTimeout(resolve, 10))
634
+ expect(submitCount).toBe(1)
635
+
636
+ editor.onSubmit = undefined
637
+
638
+ currentMockInput.pressEnter({ meta: true })
639
+ await new Promise((resolve) => setTimeout(resolve, 10))
640
+ expect(submitCount).toBe(1)
641
+ })
642
+ })
643
+
644
+ describe("Combined cursor and content events", () => {
645
+ it("should fire both onCursorChange and onContentChange when typing", async () => {
646
+ let cursorChangeCount = 0
647
+ let contentChangeCount = 0
648
+
649
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
650
+ initialValue: "",
651
+ width: 40,
652
+ height: 10,
653
+ onCursorChange: () => {
654
+ cursorChangeCount++
655
+ },
656
+ onContentChange: () => {
657
+ contentChangeCount++
658
+ },
659
+ })
660
+
661
+ editor.focus()
662
+ const initialCursorCount = cursorChangeCount
663
+ const initialContentCount = contentChangeCount
664
+
665
+ currentMockInput.pressKey("H")
666
+ await new Promise((resolve) => setTimeout(resolve, 10))
667
+
668
+ expect(cursorChangeCount).toBeGreaterThan(initialCursorCount)
669
+ expect(contentChangeCount).toBeGreaterThan(initialContentCount)
670
+ })
671
+
672
+ it("should fire onCursorChange but not onContentChange when only moving cursor", async () => {
673
+ let cursorChangeCount = 0
674
+ let contentChangeCount = 0
675
+
676
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
677
+ initialValue: "Test",
678
+ width: 40,
679
+ height: 10,
680
+ onCursorChange: () => {
681
+ cursorChangeCount++
682
+ },
683
+ onContentChange: () => {
684
+ contentChangeCount++
685
+ },
686
+ })
687
+
688
+ editor.focus()
689
+ const initialCursorCount = cursorChangeCount
690
+ const initialContentCount = contentChangeCount
691
+
692
+ editor.moveCursorRight()
693
+ await new Promise((resolve) => setTimeout(resolve, 10))
694
+
695
+ expect(cursorChangeCount).toBeGreaterThan(initialCursorCount)
696
+ expect(contentChangeCount).toBe(initialContentCount) // Should not change
697
+ })
698
+
699
+ it("should track events through complex editing sequence", async () => {
700
+ const events: Array<{ type: "cursor" | "content"; time: number }> = []
701
+
702
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
703
+ initialValue: "",
704
+ width: 40,
705
+ height: 10,
706
+ onCursorChange: () => {
707
+ events.push({ type: "cursor", time: Date.now() })
708
+ },
709
+ onContentChange: () => {
710
+ events.push({ type: "content", time: Date.now() })
711
+ },
712
+ })
713
+
714
+ editor.focus()
715
+ events.length = 0 // Clear initial events
716
+
717
+ currentMockInput.pressKey("H")
718
+ currentMockInput.pressKey("e")
719
+ currentMockInput.pressKey("l")
720
+ currentMockInput.pressKey("l")
721
+ currentMockInput.pressKey("o")
722
+
723
+ editor.moveCursorLeft()
724
+ editor.moveCursorLeft()
725
+
726
+ currentMockInput.pressBackspace()
727
+
728
+ await new Promise((resolve) => setTimeout(resolve, 50))
729
+
730
+ const cursorEvents = events.filter((e) => e.type === "cursor")
731
+ const contentEvents = events.filter((e) => e.type === "content")
732
+
733
+ expect(cursorEvents.length).toBeGreaterThan(0)
734
+ expect(contentEvents.length).toBeGreaterThan(0)
735
+ })
736
+ })
737
+ })
738
+ })