@fairyhunter13/opentui-core 0.1.88 → 0.1.90

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 (570) 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 +141 -0
  7. package/docs/env-vars.md +140 -0
  8. package/docs/getting-started.md +353 -0
  9. package/docs/renderables-vs-constructs.md +159 -0
  10. package/docs/tree-sitter.md +311 -0
  11. package/package.json +61 -52
  12. package/scripts/build.ts +400 -0
  13. package/scripts/publish.ts +60 -0
  14. package/src/3d/SpriteResourceManager.ts +286 -0
  15. package/src/3d/SpriteUtils.ts +71 -0
  16. package/src/3d/TextureUtils.ts +196 -0
  17. package/src/3d/ThreeRenderable.ts +197 -0
  18. package/src/3d/WGPURenderer.ts +294 -0
  19. package/src/3d/animation/ExplodingSpriteEffect.ts +513 -0
  20. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +429 -0
  21. package/src/3d/animation/SpriteAnimator.ts +633 -0
  22. package/src/3d/animation/SpriteParticleGenerator.ts +435 -0
  23. package/src/3d/canvas.ts +464 -0
  24. package/src/3d/index.ts +12 -0
  25. package/src/3d/physics/PlanckPhysicsAdapter.ts +72 -0
  26. package/src/3d/physics/RapierPhysicsAdapter.ts +66 -0
  27. package/src/3d/physics/physics-interface.ts +31 -0
  28. package/src/3d/shaders/supersampling.wgsl +201 -0
  29. package/src/3d.ts +3 -0
  30. package/src/NativeSpanFeed.ts +300 -0
  31. package/src/Renderable.ts +1698 -0
  32. package/src/__snapshots__/buffer.test.ts.snap +28 -0
  33. package/src/animation/Timeline.test.ts +2709 -0
  34. package/src/animation/Timeline.ts +598 -0
  35. package/src/ansi.ts +18 -0
  36. package/src/benchmark/latest-all-bench-run.json +707 -0
  37. package/src/benchmark/latest-async-bench-run.json +336 -0
  38. package/src/benchmark/latest-default-bench-run.json +657 -0
  39. package/src/benchmark/latest-large-bench-run.json +707 -0
  40. package/src/benchmark/latest-quick-bench-run.json +207 -0
  41. package/src/benchmark/markdown-benchmark.ts +1804 -0
  42. package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
  43. package/src/benchmark/native-span-feed-benchmark.md +56 -0
  44. package/src/benchmark/native-span-feed-benchmark.ts +596 -0
  45. package/src/benchmark/native-span-feed-compare.ts +280 -0
  46. package/src/benchmark/renderer-benchmark.ts +754 -0
  47. package/src/benchmark/text-table-benchmark.ts +947 -0
  48. package/src/buffer.test.ts +291 -0
  49. package/src/buffer.ts +519 -0
  50. package/src/console.test.ts +612 -0
  51. package/src/console.ts +1255 -0
  52. package/src/edit-buffer.test.ts +1769 -0
  53. package/src/edit-buffer.ts +411 -0
  54. package/src/editor-view.test.ts +1032 -0
  55. package/src/editor-view.ts +284 -0
  56. package/src/examples/ascii-font-selection-demo.ts +245 -0
  57. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  58. package/src/examples/assets/concrete.png +0 -0
  59. package/src/examples/assets/crate.png +0 -0
  60. package/src/examples/assets/crate_emissive.png +0 -0
  61. package/src/examples/assets/forrest_background.png +0 -0
  62. package/src/examples/assets/hast-example.json +1018 -0
  63. package/src/examples/assets/heart.png +0 -0
  64. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  65. package/src/examples/assets/main_char_idle.png +0 -0
  66. package/src/examples/assets/main_char_jump_end.png +0 -0
  67. package/src/examples/assets/main_char_jump_landing.png +0 -0
  68. package/src/examples/assets/main_char_jump_start.png +0 -0
  69. package/src/examples/assets/main_char_run_loop.png +0 -0
  70. package/src/examples/assets/roughness_map.jpg +0 -0
  71. package/src/examples/build.ts +115 -0
  72. package/src/examples/code-demo.ts +584 -0
  73. package/src/examples/console-demo.ts +358 -0
  74. package/src/examples/core-plugin-slots-demo.ts +759 -0
  75. package/src/examples/diff-demo.ts +699 -0
  76. package/src/examples/draggable-three-demo.ts +259 -0
  77. package/src/examples/editor-demo.ts +322 -0
  78. package/src/examples/extmarks-demo.ts +204 -0
  79. package/src/examples/focus-restore-demo.ts +310 -0
  80. package/src/examples/fonts.ts +245 -0
  81. package/src/examples/fractal-shader-demo.ts +268 -0
  82. package/src/examples/framebuffer-demo.ts +674 -0
  83. package/src/examples/full-unicode-demo.ts +181 -0
  84. package/src/examples/golden-star-demo.ts +933 -0
  85. package/src/examples/grayscale-buffer-demo.ts +249 -0
  86. package/src/examples/hast-syntax-highlighting-demo.ts +129 -0
  87. package/src/examples/index.ts +925 -0
  88. package/src/examples/input-demo.ts +377 -0
  89. package/src/examples/input-select-layout-demo.ts +425 -0
  90. package/src/examples/install.sh +143 -0
  91. package/src/examples/keypress-debug-demo.ts +452 -0
  92. package/src/examples/lib/HexList.ts +122 -0
  93. package/src/examples/lib/PaletteGrid.ts +125 -0
  94. package/src/examples/lib/standalone-keys.ts +25 -0
  95. package/src/examples/lib/tab-controller.ts +243 -0
  96. package/src/examples/lights-phong-demo.ts +290 -0
  97. package/src/examples/link-demo.ts +220 -0
  98. package/src/examples/live-state-demo.ts +480 -0
  99. package/src/examples/markdown-demo.ts +620 -0
  100. package/src/examples/mouse-interaction-demo.ts +428 -0
  101. package/src/examples/nested-zindex-demo.ts +357 -0
  102. package/src/examples/opacity-example.ts +235 -0
  103. package/src/examples/opentui-demo.ts +1057 -0
  104. package/src/examples/physx-planck-2d-demo.ts +507 -0
  105. package/src/examples/physx-rapier-2d-demo.ts +526 -0
  106. package/src/examples/relative-positioning-demo.ts +323 -0
  107. package/src/examples/scroll-example.ts +214 -0
  108. package/src/examples/scrollbox-mouse-test.ts +112 -0
  109. package/src/examples/scrollbox-overlay-hit-test.ts +206 -0
  110. package/src/examples/select-demo.ts +237 -0
  111. package/src/examples/shader-cube-demo.ts +772 -0
  112. package/src/examples/simple-layout-example.ts +591 -0
  113. package/src/examples/slider-demo.ts +617 -0
  114. package/src/examples/split-mode-demo.ts +445 -0
  115. package/src/examples/sprite-animation-demo.ts +443 -0
  116. package/src/examples/sprite-particle-generator-demo.ts +486 -0
  117. package/src/examples/static-sprite-demo.ts +193 -0
  118. package/src/examples/sticky-scroll-example.ts +308 -0
  119. package/src/examples/styled-text-demo.ts +282 -0
  120. package/src/examples/tab-select-demo.ts +219 -0
  121. package/src/examples/terminal-title.ts +29 -0
  122. package/src/examples/terminal.ts +305 -0
  123. package/src/examples/text-node-demo.ts +416 -0
  124. package/src/examples/text-selection-demo.ts +377 -0
  125. package/src/examples/text-table-demo.ts +503 -0
  126. package/src/examples/text-truncation-demo.ts +481 -0
  127. package/src/examples/text-wrap.ts +757 -0
  128. package/src/examples/texture-loading-demo.ts +259 -0
  129. package/src/examples/timeline-example.ts +670 -0
  130. package/src/examples/transparency-demo.ts +241 -0
  131. package/src/examples/vnode-composition-demo.ts +404 -0
  132. package/src/index.ts +22 -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 +168 -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 +31 -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 +280 -0
  168. package/src/lib/keymapping.ts +87 -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 +1676 -0
  187. package/src/lib/stdin-parser.ts +1248 -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 +331 -0
  195. package/src/lib/tree-sitter/assets.d.ts +9 -0
  196. package/src/lib/tree-sitter/cache.test.ts +270 -0
  197. package/src/lib/tree-sitter/client.test.ts +1061 -0
  198. package/src/lib/tree-sitter/client.ts +615 -0
  199. package/src/lib/tree-sitter/default-parsers.ts +80 -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 +1001 -0
  203. package/src/lib/tree-sitter/parsers-config.ts +75 -0
  204. package/src/lib/tree-sitter/resolve-ft.ts +62 -0
  205. package/src/lib/tree-sitter/types.ts +81 -0
  206. package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
  207. package/src/lib/tree-sitter-styled-text.ts +306 -0
  208. package/src/lib/validate-dir-name.ts +55 -0
  209. package/src/lib/yoga.options.test.ts +628 -0
  210. package/src/lib/yoga.options.ts +346 -0
  211. package/src/plugins/core-slot.ts +579 -0
  212. package/src/plugins/registry.ts +377 -0
  213. package/src/plugins/types.ts +46 -0
  214. package/src/post/filters.ts +888 -0
  215. package/src/renderables/ASCIIFont.ts +219 -0
  216. package/src/renderables/Box.test.ts +160 -0
  217. package/src/renderables/Box.ts +295 -0
  218. package/src/renderables/Code.test.ts +2062 -0
  219. package/src/renderables/Code.ts +357 -0
  220. package/src/renderables/Diff.regression.test.ts +226 -0
  221. package/src/renderables/Diff.test.ts +3027 -0
  222. package/src/renderables/Diff.ts +1209 -0
  223. package/src/renderables/EditBufferRenderable.ts +764 -0
  224. package/src/renderables/FrameBuffer.ts +47 -0
  225. package/src/renderables/Input.test.ts +1228 -0
  226. package/src/renderables/Input.ts +245 -0
  227. package/src/renderables/LineNumberRenderable.ts +675 -0
  228. package/src/renderables/Markdown.ts +1106 -0
  229. package/src/renderables/ScrollBar.ts +422 -0
  230. package/src/renderables/ScrollBox.ts +883 -0
  231. package/src/renderables/Select.test.ts +1010 -0
  232. package/src/renderables/Select.ts +523 -0
  233. package/src/renderables/Slider.test.ts +456 -0
  234. package/src/renderables/Slider.ts +347 -0
  235. package/src/renderables/TabSelect.test.ts +197 -0
  236. package/src/renderables/TabSelect.ts +455 -0
  237. package/src/renderables/Text.selection-buffer.test.ts +123 -0
  238. package/src/renderables/Text.test.ts +2660 -0
  239. package/src/renderables/Text.ts +147 -0
  240. package/src/renderables/TextBufferRenderable.ts +518 -0
  241. package/src/renderables/TextNode.test.ts +1058 -0
  242. package/src/renderables/TextNode.ts +325 -0
  243. package/src/renderables/TextTable.test.ts +1421 -0
  244. package/src/renderables/TextTable.ts +1344 -0
  245. package/src/renderables/Textarea.ts +732 -0
  246. package/src/renderables/TimeToFirstDraw.ts +89 -0
  247. package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
  248. package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
  249. package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
  250. package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
  251. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
  252. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +816 -0
  253. package/src/renderables/__tests__/LineNumberRenderable.test.ts +1787 -0
  254. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
  255. package/src/renderables/__tests__/Markdown.test.ts +2287 -0
  256. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
  257. package/src/renderables/__tests__/Textarea.buffer.test.ts +682 -0
  258. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
  259. package/src/renderables/__tests__/Textarea.editing.test.ts +2041 -0
  260. package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
  261. package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
  262. package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
  263. package/src/renderables/__tests__/Textarea.keybinding.test.ts +3149 -0
  264. package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
  265. package/src/renderables/__tests__/Textarea.rendering.test.ts +1864 -0
  266. package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
  267. package/src/renderables/__tests__/Textarea.selection.test.ts +1590 -0
  268. package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
  269. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
  270. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
  271. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
  272. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
  273. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
  274. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
  275. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
  276. package/src/renderables/__tests__/markdown-parser.test.ts +217 -0
  277. package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
  278. package/src/renderables/composition/README.md +8 -0
  279. package/src/renderables/composition/VRenderable.ts +32 -0
  280. package/src/renderables/composition/constructs.ts +127 -0
  281. package/src/renderables/composition/vnode.ts +289 -0
  282. package/src/renderables/index.ts +22 -0
  283. package/src/renderables/markdown-parser.ts +66 -0
  284. package/src/renderer.ts +2363 -0
  285. package/src/runtime-plugin-support.ts +39 -0
  286. package/src/runtime-plugin.ts +144 -0
  287. package/src/syntax-style.test.ts +841 -0
  288. package/src/syntax-style.ts +264 -0
  289. package/src/testing/README.md +210 -0
  290. package/src/testing/capture-spans.test.ts +194 -0
  291. package/src/testing/integration.test.ts +276 -0
  292. package/src/testing/manual-clock.ts +106 -0
  293. package/src/testing/mock-keys.test.ts +1356 -0
  294. package/src/testing/mock-keys.ts +449 -0
  295. package/src/testing/mock-mouse.test.ts +218 -0
  296. package/src/testing/mock-mouse.ts +247 -0
  297. package/src/testing/mock-tree-sitter-client.ts +73 -0
  298. package/src/testing/spy.ts +13 -0
  299. package/src/testing/test-recorder.test.ts +415 -0
  300. package/src/testing/test-recorder.ts +145 -0
  301. package/src/testing/test-renderer.ts +116 -0
  302. package/src/testing.ts +7 -0
  303. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
  304. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
  305. package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
  306. package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
  307. package/src/tests/allocator-stats.test.ts +38 -0
  308. package/src/tests/destroy-during-render.test.ts +200 -0
  309. package/src/tests/hover-cursor.test.ts +98 -0
  310. package/src/tests/native-span-feed-async.test.ts +173 -0
  311. package/src/tests/native-span-feed-close.test.ts +120 -0
  312. package/src/tests/native-span-feed-coverage.test.ts +227 -0
  313. package/src/tests/native-span-feed-edge-cases.test.ts +352 -0
  314. package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
  315. package/src/tests/opacity.test.ts +123 -0
  316. package/src/tests/renderable.snapshot.test.ts +524 -0
  317. package/src/tests/renderable.test.ts +1281 -0
  318. package/src/tests/renderer.console-startup.test.ts +65 -0
  319. package/src/tests/renderer.control.test.ts +364 -0
  320. package/src/tests/renderer.core-slot-binding.test.ts +952 -0
  321. package/src/tests/renderer.cursor.test.ts +26 -0
  322. package/src/tests/renderer.destroy-during-render.test.ts +110 -0
  323. package/src/tests/renderer.focus-restore.test.ts +228 -0
  324. package/src/tests/renderer.focus.test.ts +251 -0
  325. package/src/tests/renderer.idle.test.ts +219 -0
  326. package/src/tests/renderer.input.test.ts +2145 -0
  327. package/src/tests/renderer.kitty-flags.test.ts +195 -0
  328. package/src/tests/renderer.mouse.test.ts +1269 -0
  329. package/src/tests/renderer.palette.test.ts +629 -0
  330. package/src/tests/renderer.selection.test.ts +49 -0
  331. package/src/tests/renderer.slot-registry.test.ts +649 -0
  332. package/src/tests/renderer.useMouse.test.ts +50 -0
  333. package/src/tests/runtime-plugin-support.fixture.ts +11 -0
  334. package/src/tests/runtime-plugin-support.test.ts +28 -0
  335. package/src/tests/runtime-plugin.fixture.ts +40 -0
  336. package/src/tests/runtime-plugin.test.ts +190 -0
  337. package/src/tests/scrollbox-culling-bug.test.ts +114 -0
  338. package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
  339. package/src/tests/scrollbox-hitgrid.test.ts +909 -0
  340. package/src/tests/scrollbox.test.ts +1530 -0
  341. package/src/tests/wrap-resize-perf.test.ts +229 -0
  342. package/src/tests/yoga-setters.test.ts +921 -0
  343. package/src/text-buffer-view.test.ts +705 -0
  344. package/src/text-buffer-view.ts +189 -0
  345. package/src/text-buffer.test.ts +347 -0
  346. package/src/text-buffer.ts +250 -0
  347. package/src/types.ts +152 -0
  348. package/src/utils.ts +88 -0
  349. package/src/zig/ansi.zig +268 -0
  350. package/src/zig/bench/README.md +50 -0
  351. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +887 -0
  352. package/src/zig/bench/edit-buffer_bench.zig +476 -0
  353. package/src/zig/bench/native-span-feed_bench.zig +100 -0
  354. package/src/zig/bench/rope-markers_bench.zig +713 -0
  355. package/src/zig/bench/rope_bench.zig +514 -0
  356. package/src/zig/bench/styled-text_bench.zig +470 -0
  357. package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
  358. package/src/zig/bench/text-buffer-view_bench.zig +459 -0
  359. package/src/zig/bench/text-chunk-graphemes_bench.zig +273 -0
  360. package/src/zig/bench/utf8_bench.zig +799 -0
  361. package/src/zig/bench-utils.zig +431 -0
  362. package/src/zig/bench.zig +217 -0
  363. package/src/zig/buffer.zig +2223 -0
  364. package/src/zig/build.zig +289 -0
  365. package/src/zig/build.zig.zon +16 -0
  366. package/src/zig/edit-buffer.zig +825 -0
  367. package/src/zig/editor-view.zig +802 -0
  368. package/src/zig/event-bus.zig +13 -0
  369. package/src/zig/event-emitter.zig +65 -0
  370. package/src/zig/file-logger.zig +92 -0
  371. package/src/zig/grapheme.zig +599 -0
  372. package/src/zig/lib.zig +1834 -0
  373. package/src/zig/link.zig +333 -0
  374. package/src/zig/logger.zig +43 -0
  375. package/src/zig/mem-registry.zig +125 -0
  376. package/src/zig/native-span-feed-bench-lib.zig +7 -0
  377. package/src/zig/native-span-feed.zig +708 -0
  378. package/src/zig/renderer.zig +1386 -0
  379. package/src/zig/rope.zig +1220 -0
  380. package/src/zig/syntax-style.zig +161 -0
  381. package/src/zig/terminal.zig +975 -0
  382. package/src/zig/test.zig +70 -0
  383. package/src/zig/tests/README.md +18 -0
  384. package/src/zig/tests/buffer_test.zig +2526 -0
  385. package/src/zig/tests/edit-buffer-history_test.zig +271 -0
  386. package/src/zig/tests/edit-buffer_test.zig +1689 -0
  387. package/src/zig/tests/editor-view_test.zig +3299 -0
  388. package/src/zig/tests/event-emitter_test.zig +249 -0
  389. package/src/zig/tests/grapheme_test.zig +1304 -0
  390. package/src/zig/tests/link_test.zig +190 -0
  391. package/src/zig/tests/mem-registry_test.zig +473 -0
  392. package/src/zig/tests/memory_leak_regression_test.zig +159 -0
  393. package/src/zig/tests/native-span-feed_test.zig +1264 -0
  394. package/src/zig/tests/renderer_test.zig +1010 -0
  395. package/src/zig/tests/rope-nested_test.zig +712 -0
  396. package/src/zig/tests/rope_fuzz_test.zig +238 -0
  397. package/src/zig/tests/rope_test.zig +2362 -0
  398. package/src/zig/tests/segment-merge.test.zig +148 -0
  399. package/src/zig/tests/syntax-style_test.zig +557 -0
  400. package/src/zig/tests/terminal_test.zig +719 -0
  401. package/src/zig/tests/text-buffer-drawing_test.zig +3237 -0
  402. package/src/zig/tests/text-buffer-highlights_test.zig +666 -0
  403. package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
  404. package/src/zig/tests/text-buffer-segment_test.zig +320 -0
  405. package/src/zig/tests/text-buffer-selection_test.zig +1035 -0
  406. package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
  407. package/src/zig/tests/text-buffer-view_test.zig +3649 -0
  408. package/src/zig/tests/text-buffer_test.zig +2191 -0
  409. package/src/zig/tests/unicode-width-map.zon +3909 -0
  410. package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
  411. package/src/zig/tests/utf8_test.zig +4057 -0
  412. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
  413. package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
  414. package/src/zig/tests/word-wrap-editing_test.zig +498 -0
  415. package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
  416. package/src/zig/text-buffer-iterators.zig +499 -0
  417. package/src/zig/text-buffer-segment.zig +404 -0
  418. package/src/zig/text-buffer-view.zig +1371 -0
  419. package/src/zig/text-buffer.zig +1180 -0
  420. package/src/zig/utf8.zig +1948 -0
  421. package/src/zig/utils.zig +9 -0
  422. package/src/zig-structs.ts +261 -0
  423. package/src/zig.ts +3843 -0
  424. package/tsconfig.build.json +22 -0
  425. package/tsconfig.json +28 -0
  426. package/3d/SpriteResourceManager.d.ts +0 -74
  427. package/3d/SpriteUtils.d.ts +0 -13
  428. package/3d/TextureUtils.d.ts +0 -24
  429. package/3d/ThreeRenderable.d.ts +0 -40
  430. package/3d/WGPURenderer.d.ts +0 -61
  431. package/3d/animation/ExplodingSpriteEffect.d.ts +0 -71
  432. package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +0 -76
  433. package/3d/animation/SpriteAnimator.d.ts +0 -124
  434. package/3d/animation/SpriteParticleGenerator.d.ts +0 -62
  435. package/3d/canvas.d.ts +0 -44
  436. package/3d/index.d.ts +0 -12
  437. package/3d/physics/PlanckPhysicsAdapter.d.ts +0 -19
  438. package/3d/physics/RapierPhysicsAdapter.d.ts +0 -19
  439. package/3d/physics/physics-interface.d.ts +0 -27
  440. package/3d.d.ts +0 -2
  441. package/3d.js +0 -34042
  442. package/3d.js.map +0 -155
  443. package/LICENSE +0 -21
  444. package/NativeSpanFeed.d.ts +0 -41
  445. package/Renderable.d.ts +0 -334
  446. package/animation/Timeline.d.ts +0 -126
  447. package/ansi.d.ts +0 -13
  448. package/buffer.d.ts +0 -107
  449. package/console.d.ts +0 -143
  450. package/edit-buffer.d.ts +0 -98
  451. package/editor-view.d.ts +0 -73
  452. package/index-e4hzc2j2.js +0 -113
  453. package/index-e4hzc2j2.js.map +0 -10
  454. package/index-nkrr8a4c.js +0 -18415
  455. package/index-nkrr8a4c.js.map +0 -64
  456. package/index-nyw5p3ep.js +0 -12619
  457. package/index-nyw5p3ep.js.map +0 -43
  458. package/index.d.ts +0 -21
  459. package/index.js +0 -430
  460. package/index.js.map +0 -9
  461. package/lib/KeyHandler.d.ts +0 -61
  462. package/lib/RGBA.d.ts +0 -25
  463. package/lib/ascii.font.d.ts +0 -508
  464. package/lib/border.d.ts +0 -49
  465. package/lib/bunfs.d.ts +0 -7
  466. package/lib/clipboard.d.ts +0 -17
  467. package/lib/clock.d.ts +0 -15
  468. package/lib/data-paths.d.ts +0 -26
  469. package/lib/debounce.d.ts +0 -42
  470. package/lib/detect-links.d.ts +0 -6
  471. package/lib/env.d.ts +0 -42
  472. package/lib/extmarks-history.d.ts +0 -17
  473. package/lib/extmarks.d.ts +0 -89
  474. package/lib/hast-styled-text.d.ts +0 -17
  475. package/lib/index.d.ts +0 -21
  476. package/lib/keymapping.d.ts +0 -25
  477. package/lib/objects-in-viewport.d.ts +0 -24
  478. package/lib/output.capture.d.ts +0 -24
  479. package/lib/parse.keypress-kitty.d.ts +0 -2
  480. package/lib/parse.keypress.d.ts +0 -26
  481. package/lib/parse.mouse.d.ts +0 -30
  482. package/lib/paste.d.ts +0 -7
  483. package/lib/queue.d.ts +0 -15
  484. package/lib/renderable.validations.d.ts +0 -12
  485. package/lib/scroll-acceleration.d.ts +0 -43
  486. package/lib/selection.d.ts +0 -63
  487. package/lib/singleton.d.ts +0 -7
  488. package/lib/stdin-parser.d.ts +0 -76
  489. package/lib/styled-text.d.ts +0 -63
  490. package/lib/terminal-capability-detection.d.ts +0 -30
  491. package/lib/terminal-palette.d.ts +0 -50
  492. package/lib/tree-sitter/assets/update.d.ts +0 -11
  493. package/lib/tree-sitter/client.d.ts +0 -47
  494. package/lib/tree-sitter/default-parsers.d.ts +0 -2
  495. package/lib/tree-sitter/download-utils.d.ts +0 -21
  496. package/lib/tree-sitter/index.d.ts +0 -8
  497. package/lib/tree-sitter/parser.worker.d.ts +0 -1
  498. package/lib/tree-sitter/parsers-config.d.ts +0 -38
  499. package/lib/tree-sitter/resolve-ft.d.ts +0 -2
  500. package/lib/tree-sitter/types.d.ts +0 -81
  501. package/lib/tree-sitter-styled-text.d.ts +0 -14
  502. package/lib/validate-dir-name.d.ts +0 -1
  503. package/lib/yoga.options.d.ts +0 -32
  504. package/parser.worker.js +0 -869
  505. package/parser.worker.js.map +0 -12
  506. package/plugins/core-slot.d.ts +0 -72
  507. package/plugins/registry.d.ts +0 -38
  508. package/plugins/types.d.ts +0 -34
  509. package/post/filters.d.ts +0 -105
  510. package/renderables/ASCIIFont.d.ts +0 -52
  511. package/renderables/Box.d.ts +0 -72
  512. package/renderables/Code.d.ts +0 -78
  513. package/renderables/Diff.d.ts +0 -142
  514. package/renderables/EditBufferRenderable.d.ts +0 -162
  515. package/renderables/FrameBuffer.d.ts +0 -16
  516. package/renderables/Input.d.ts +0 -67
  517. package/renderables/LineNumberRenderable.d.ts +0 -74
  518. package/renderables/Markdown.d.ts +0 -173
  519. package/renderables/ScrollBar.d.ts +0 -77
  520. package/renderables/ScrollBox.d.ts +0 -124
  521. package/renderables/Select.d.ts +0 -115
  522. package/renderables/Slider.d.ts +0 -44
  523. package/renderables/TabSelect.d.ts +0 -96
  524. package/renderables/Text.d.ts +0 -36
  525. package/renderables/TextBufferRenderable.d.ts +0 -105
  526. package/renderables/TextNode.d.ts +0 -91
  527. package/renderables/TextTable.d.ts +0 -140
  528. package/renderables/Textarea.d.ts +0 -114
  529. package/renderables/TimeToFirstDraw.d.ts +0 -24
  530. package/renderables/__tests__/renderable-test-utils.d.ts +0 -12
  531. package/renderables/composition/VRenderable.d.ts +0 -16
  532. package/renderables/composition/constructs.d.ts +0 -35
  533. package/renderables/composition/vnode.d.ts +0 -46
  534. package/renderables/index.d.ts +0 -22
  535. package/renderables/markdown-parser.d.ts +0 -10
  536. package/renderer.d.ts +0 -388
  537. package/runtime-plugin-support.d.ts +0 -3
  538. package/runtime-plugin-support.js +0 -29
  539. package/runtime-plugin-support.js.map +0 -10
  540. package/runtime-plugin.d.ts +0 -11
  541. package/runtime-plugin.js +0 -16
  542. package/runtime-plugin.js.map +0 -9
  543. package/syntax-style.d.ts +0 -54
  544. package/testing/manual-clock.d.ts +0 -16
  545. package/testing/mock-keys.d.ts +0 -81
  546. package/testing/mock-mouse.d.ts +0 -38
  547. package/testing/mock-tree-sitter-client.d.ts +0 -23
  548. package/testing/spy.d.ts +0 -7
  549. package/testing/test-recorder.d.ts +0 -61
  550. package/testing/test-renderer.d.ts +0 -23
  551. package/testing.d.ts +0 -6
  552. package/testing.js +0 -675
  553. package/testing.js.map +0 -15
  554. package/text-buffer-view.d.ts +0 -42
  555. package/text-buffer.d.ts +0 -67
  556. package/types.d.ts +0 -131
  557. package/utils.d.ts +0 -14
  558. package/zig-structs.d.ts +0 -155
  559. package/zig.d.ts +0 -351
  560. /package/{assets → src/lib/tree-sitter/assets}/javascript/highlights.scm +0 -0
  561. /package/{assets → src/lib/tree-sitter/assets}/javascript/tree-sitter-javascript.wasm +0 -0
  562. /package/{assets → src/lib/tree-sitter/assets}/markdown/highlights.scm +0 -0
  563. /package/{assets → src/lib/tree-sitter/assets}/markdown/injections.scm +0 -0
  564. /package/{assets → src/lib/tree-sitter/assets}/markdown/tree-sitter-markdown.wasm +0 -0
  565. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/highlights.scm +0 -0
  566. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  567. /package/{assets → src/lib/tree-sitter/assets}/typescript/highlights.scm +0 -0
  568. /package/{assets → src/lib/tree-sitter/assets}/typescript/tree-sitter-typescript.wasm +0 -0
  569. /package/{assets → src/lib/tree-sitter/assets}/zig/highlights.scm +0 -0
  570. /package/{assets → src/lib/tree-sitter/assets}/zig/tree-sitter-zig.wasm +0 -0
@@ -0,0 +1,682 @@
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 - Buffer 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("getTextRange", () => {
26
+ it("should get text range by display-width offsets", async () => {
27
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
28
+ initialValue: "Hello, World!\nThis is line 2.",
29
+ width: 40,
30
+ height: 10,
31
+ })
32
+
33
+ const range1 = editor.getTextRange(0, 5)
34
+ expect(range1).toBe("Hello")
35
+
36
+ const range2 = editor.getTextRange(7, 12)
37
+ expect(range2).toBe("World")
38
+
39
+ const range3 = editor.getTextRange(0, 13)
40
+ expect(range3).toBe("Hello, World!")
41
+
42
+ const range4 = editor.getTextRange(14, 21)
43
+ expect(range4).toBe("This is")
44
+ })
45
+
46
+ it("should get text range by row/col coordinates", async () => {
47
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
48
+ initialValue: "Hello, World!\nThis is line 2.",
49
+ width: 40,
50
+ height: 10,
51
+ })
52
+
53
+ const range1 = editor.getTextRangeByCoords(0, 0, 0, 5)
54
+ expect(range1).toBe("Hello")
55
+
56
+ const range2 = editor.getTextRangeByCoords(0, 7, 0, 12)
57
+ expect(range2).toBe("World")
58
+
59
+ const range3 = editor.getTextRangeByCoords(1, 0, 1, 7)
60
+ expect(range3).toBe("This is")
61
+
62
+ const range4 = editor.getTextRangeByCoords(0, 0, 1, 7)
63
+ expect(range4).toBe("Hello, World!\nThis is")
64
+ })
65
+
66
+ it("should handle empty ranges with getTextRangeByCoords", async () => {
67
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
68
+ initialValue: "Hello, World!",
69
+ width: 40,
70
+ height: 10,
71
+ })
72
+
73
+ const rangeEmpty = editor.getTextRangeByCoords(0, 5, 0, 5)
74
+ expect(rangeEmpty).toBe("")
75
+
76
+ const rangeInvalid = editor.getTextRangeByCoords(0, 10, 0, 5)
77
+ expect(rangeInvalid).toBe("")
78
+ })
79
+
80
+ it("should handle ranges spanning multiple lines with getTextRangeByCoords", async () => {
81
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
82
+ initialValue: "Line 1\nLine 2\nLine 3",
83
+ width: 40,
84
+ height: 10,
85
+ })
86
+
87
+ const range1 = editor.getTextRangeByCoords(0, 5, 1, 4)
88
+ expect(range1).toBe("1\nLine")
89
+
90
+ const range2 = editor.getTextRangeByCoords(0, 0, 2, 6)
91
+ expect(range2).toBe("Line 1\nLine 2\nLine 3")
92
+
93
+ const range3 = editor.getTextRangeByCoords(1, 0, 2, 6)
94
+ expect(range3).toBe("Line 2\nLine 3")
95
+ })
96
+
97
+ it("should handle Unicode characters with getTextRangeByCoords", async () => {
98
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
99
+ initialValue: "Hello 🌟 World",
100
+ width: 40,
101
+ height: 10,
102
+ })
103
+
104
+ const range1 = editor.getTextRangeByCoords(0, 0, 0, 6)
105
+ expect(range1).toBe("Hello ")
106
+
107
+ const range2 = editor.getTextRangeByCoords(0, 6, 0, 8)
108
+ expect(range2).toBe("🌟")
109
+
110
+ const range3 = editor.getTextRangeByCoords(0, 8, 0, 14)
111
+ expect(range3).toBe(" World")
112
+ })
113
+
114
+ it("should handle CJK characters with getTextRangeByCoords", async () => {
115
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
116
+ initialValue: "Hello 世界",
117
+ width: 40,
118
+ height: 10,
119
+ })
120
+
121
+ const range1 = editor.getTextRangeByCoords(0, 0, 0, 6)
122
+ expect(range1).toBe("Hello ")
123
+
124
+ const range2 = editor.getTextRangeByCoords(0, 6, 0, 10)
125
+ expect(range2).toBe("世界")
126
+ })
127
+
128
+ it("should get text range by coords after editing operations", async () => {
129
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
130
+ initialValue: "ABC\nDEF",
131
+ width: 40,
132
+ height: 10,
133
+ })
134
+
135
+ editor.focus()
136
+
137
+ const range1 = editor.getTextRangeByCoords(0, 0, 1, 3)
138
+ expect(range1).toBe("ABC\nDEF")
139
+
140
+ editor.gotoLine(1)
141
+ currentMockInput.pressBackspace()
142
+ expect(editor.plainText).toBe("ABCDEF")
143
+
144
+ const range2 = editor.getTextRangeByCoords(0, 1, 0, 5)
145
+ expect(range2).toBe("BCDE")
146
+
147
+ const range3 = editor.getTextRangeByCoords(0, 0, 0, 6)
148
+ expect(range3).toBe("ABCDEF")
149
+ })
150
+
151
+ it("should handle out-of-bounds coordinates with getTextRangeByCoords", async () => {
152
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
153
+ initialValue: "Short",
154
+ width: 40,
155
+ height: 10,
156
+ })
157
+
158
+ const range1 = editor.getTextRangeByCoords(10, 0, 20, 0)
159
+ expect(range1).toBe("")
160
+
161
+ const range2 = editor.getTextRangeByCoords(0, 0, 0, 5)
162
+ expect(range2).toBe("Short")
163
+
164
+ const range3 = editor.getTextRangeByCoords(0, 100, 0, 200)
165
+ expect(range3).toBe("")
166
+ })
167
+
168
+ it("should match offset-based and coords-based methods", async () => {
169
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
170
+ initialValue: "Line 1\nLine 2\nLine 3",
171
+ width: 40,
172
+ height: 10,
173
+ })
174
+
175
+ const offsetBased = editor.getTextRange(0, 6)
176
+ const coordsBased = editor.getTextRangeByCoords(0, 0, 0, 6)
177
+ expect(coordsBased).toBe(offsetBased)
178
+ expect(coordsBased).toBe("Line 1")
179
+
180
+ const offsetBased2 = editor.getTextRange(7, 13)
181
+ const coordsBased2 = editor.getTextRangeByCoords(1, 0, 1, 6)
182
+ expect(coordsBased2).toBe(offsetBased2)
183
+ expect(coordsBased2).toBe("Line 2")
184
+
185
+ const offsetBased3 = editor.getTextRange(5, 12)
186
+ const coordsBased3 = editor.getTextRangeByCoords(0, 5, 1, 5)
187
+ expect(coordsBased3).toBe(offsetBased3)
188
+ expect(coordsBased3).toBe("1\nLine ")
189
+ })
190
+
191
+ it("should handle empty ranges", async () => {
192
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
193
+ initialValue: "Hello, World!",
194
+ width: 40,
195
+ height: 10,
196
+ })
197
+
198
+ const rangeEmpty = editor.getTextRange(5, 5)
199
+ expect(rangeEmpty).toBe("")
200
+
201
+ const rangeInvalid = editor.getTextRange(10, 5)
202
+ expect(rangeInvalid).toBe("")
203
+ })
204
+
205
+ it("should handle ranges spanning multiple lines", async () => {
206
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
207
+ initialValue: "Line 1\nLine 2\nLine 3",
208
+ width: 40,
209
+ height: 10,
210
+ })
211
+
212
+ const range1 = editor.getTextRange(0, 13)
213
+ expect(range1).toBe("Line 1\nLine 2")
214
+
215
+ const range2 = editor.getTextRange(5, 12)
216
+ expect(range2).toBe("1\nLine ")
217
+ })
218
+
219
+ it("should handle Unicode characters in ranges", async () => {
220
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
221
+ initialValue: "Hello 🌟 World",
222
+ width: 40,
223
+ height: 10,
224
+ })
225
+
226
+ const range1 = editor.getTextRange(0, 6)
227
+ expect(range1).toBe("Hello ")
228
+
229
+ const range2 = editor.getTextRange(6, 8)
230
+ expect(range2).toBe("🌟")
231
+
232
+ const range3 = editor.getTextRange(8, 14)
233
+ expect(range3).toBe(" World")
234
+ })
235
+
236
+ it("should handle CJK characters in ranges", async () => {
237
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
238
+ initialValue: "Hello 世界",
239
+ width: 40,
240
+ height: 10,
241
+ })
242
+
243
+ const range1 = editor.getTextRange(0, 6)
244
+ expect(range1).toBe("Hello ")
245
+
246
+ const range2 = editor.getTextRange(6, 10)
247
+ expect(range2).toBe("世界")
248
+ })
249
+
250
+ it("should get text range after editing operations", async () => {
251
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
252
+ initialValue: "ABC",
253
+ width: 40,
254
+ height: 10,
255
+ })
256
+
257
+ editor.focus()
258
+
259
+ editor.gotoLine(9999)
260
+ editor.insertText("DEF")
261
+ expect(editor.plainText).toBe("ABCDEF")
262
+
263
+ const range1 = editor.getTextRange(0, 6)
264
+ expect(range1).toBe("ABCDEF")
265
+
266
+ const range2 = editor.getTextRange(0, 3)
267
+ expect(range2).toBe("ABC")
268
+
269
+ const range3 = editor.getTextRange(3, 6)
270
+ expect(range3).toBe("DEF")
271
+ })
272
+
273
+ it("should get text range across chunk boundaries after line joins", async () => {
274
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
275
+ initialValue: "ABC\nDEF",
276
+ width: 40,
277
+ height: 10,
278
+ })
279
+
280
+ editor.focus()
281
+ editor.gotoLine(1)
282
+
283
+ currentMockInput.pressBackspace()
284
+ expect(editor.plainText).toBe("ABCDEF")
285
+
286
+ const range1 = editor.getTextRange(1, 5)
287
+ expect(range1).toBe("BCDE")
288
+
289
+ const range2 = editor.getTextRange(0, 6)
290
+ expect(range2).toBe("ABCDEF")
291
+ })
292
+
293
+ it("should handle range at buffer boundaries", async () => {
294
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
295
+ initialValue: "Test",
296
+ width: 40,
297
+ height: 10,
298
+ })
299
+
300
+ const range1 = editor.getTextRange(0, 2)
301
+ expect(range1).toBe("Te")
302
+
303
+ const range2 = editor.getTextRange(2, 4)
304
+ expect(range2).toBe("st")
305
+
306
+ const range3 = editor.getTextRange(0, 4)
307
+ expect(range3).toBe("Test")
308
+ })
309
+
310
+ it("should return empty string for out-of-bounds ranges", async () => {
311
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
312
+ initialValue: "Short",
313
+ width: 40,
314
+ height: 10,
315
+ })
316
+
317
+ const range1 = editor.getTextRange(100, 200)
318
+ expect(range1).toBe("")
319
+
320
+ const range2 = editor.getTextRange(0, 1000)
321
+ expect(range2).toBe("Short")
322
+ })
323
+ })
324
+
325
+ describe("Visual Cursor with Offset", () => {
326
+ it("should have visualCursor with offset property", async () => {
327
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
328
+ initialValue: "",
329
+ width: 40,
330
+ height: 10,
331
+ })
332
+
333
+ editor.focus()
334
+
335
+ const visualCursor = editor.visualCursor
336
+ expect(visualCursor).not.toBe(null)
337
+ expect(visualCursor!.offset).toBeDefined()
338
+ expect(visualCursor!.offset).toBe(0)
339
+ })
340
+
341
+ it("should update offset after inserting text", async () => {
342
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
343
+ initialValue: "",
344
+ width: 40,
345
+ height: 10,
346
+ })
347
+
348
+ editor.focus()
349
+
350
+ editor.insertText("Hello")
351
+
352
+ const visualCursor = editor.visualCursor
353
+ expect(visualCursor).not.toBe(null)
354
+ expect(visualCursor!.offset).toBe(5)
355
+ })
356
+
357
+ it("should update offset correctly for multi-line content", async () => {
358
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
359
+ initialValue: "ABC\nDEF",
360
+ width: 40,
361
+ height: 10,
362
+ })
363
+
364
+ editor.focus()
365
+
366
+ // Cursor at start
367
+ let visualCursor = editor.visualCursor
368
+ expect(visualCursor!.offset).toBe(0)
369
+
370
+ // Move to end of first line
371
+ for (let i = 0; i < 3; i++) {
372
+ editor.moveCursorRight()
373
+ }
374
+ visualCursor = editor.visualCursor
375
+ expect(visualCursor!.offset).toBe(3)
376
+
377
+ // Move to second line (across newline)
378
+ editor.moveCursorRight()
379
+ visualCursor = editor.visualCursor
380
+ expect(visualCursor!.offset).toBe(4)
381
+ expect(visualCursor!.logicalRow).toBe(1)
382
+ expect(visualCursor!.logicalCol).toBe(0)
383
+
384
+ // Move to end of second line
385
+ for (let i = 0; i < 3; i++) {
386
+ editor.moveCursorRight()
387
+ }
388
+ visualCursor = editor.visualCursor
389
+ expect(visualCursor!.offset).toBe(7)
390
+ })
391
+
392
+ it("should set cursor by offset", async () => {
393
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
394
+ initialValue: "Hello World",
395
+ width: 40,
396
+ height: 10,
397
+ })
398
+
399
+ editor.focus()
400
+
401
+ // Set cursor to offset 6 (after "Hello ")
402
+ editor.editBuffer.setCursorByOffset(6)
403
+
404
+ const visualCursor = editor.visualCursor
405
+ expect(visualCursor).not.toBe(null)
406
+ expect(visualCursor!.offset).toBe(6)
407
+ expect(visualCursor!.logicalRow).toBe(0)
408
+ expect(visualCursor!.logicalCol).toBe(6)
409
+
410
+ // Set cursor to offset 2
411
+ editor.editBuffer.setCursorByOffset(2)
412
+
413
+ const newVisualCursor = editor.visualCursor
414
+ expect(newVisualCursor).not.toBe(null)
415
+ expect(newVisualCursor!.offset).toBe(2)
416
+ expect(newVisualCursor!.logicalRow).toBe(0)
417
+ expect(newVisualCursor!.logicalCol).toBe(2)
418
+ })
419
+
420
+ it("should set cursor by offset in multi-line content", async () => {
421
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
422
+ initialValue: "Line1\nLine2\nLine3",
423
+ width: 40,
424
+ height: 10,
425
+ })
426
+
427
+ editor.focus()
428
+
429
+ // Set cursor to offset 6 (start of "Line2")
430
+ editor.editBuffer.setCursorByOffset(6)
431
+
432
+ const visualCursor = editor.visualCursor
433
+ expect(visualCursor).not.toBe(null)
434
+ expect(visualCursor!.offset).toBe(6)
435
+ expect(visualCursor!.logicalRow).toBe(1)
436
+ expect(visualCursor!.logicalCol).toBe(0)
437
+
438
+ // Set cursor to offset 8 (L[i]ne2, at 'n')
439
+ editor.editBuffer.setCursorByOffset(8)
440
+
441
+ const newVisualCursor = editor.visualCursor
442
+ expect(newVisualCursor).not.toBe(null)
443
+ expect(newVisualCursor!.offset).toBe(8)
444
+ expect(newVisualCursor!.logicalRow).toBe(1)
445
+ expect(newVisualCursor!.logicalCol).toBe(2)
446
+ })
447
+
448
+ it("should maintain offset consistency when using editorView.setCursorByOffset", async () => {
449
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
450
+ initialValue: "ABCDEF",
451
+ width: 40,
452
+ height: 10,
453
+ })
454
+
455
+ editor.focus()
456
+
457
+ // Use editorView instead of editBuffer
458
+ editor.editorView.setCursorByOffset(3)
459
+
460
+ const visualCursor = editor.visualCursor
461
+ expect(visualCursor).not.toBe(null)
462
+ expect(visualCursor!.offset).toBe(3)
463
+ expect(visualCursor!.logicalRow).toBe(0)
464
+ expect(visualCursor!.logicalCol).toBe(3)
465
+ })
466
+
467
+ it("should set cursor to end of content using cursorOffset setter and Bun.stringWidth", async () => {
468
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
469
+ initialValue: "",
470
+ width: 40,
471
+ height: 10,
472
+ })
473
+
474
+ editor.focus()
475
+
476
+ const content = "Hello World"
477
+ editor.setText(content)
478
+ editor.cursorOffset = Bun.stringWidth(content)
479
+
480
+ const visualCursor = editor.visualCursor
481
+ expect(visualCursor).not.toBe(null)
482
+ expect(visualCursor!.offset).toBe(Bun.stringWidth(content))
483
+ expect(visualCursor!.logicalRow).toBe(0)
484
+ expect(visualCursor!.logicalCol).toBe(content.length)
485
+ expect(visualCursor!.visualCol).toBe(content.length)
486
+
487
+ // Verify cursor is at the end
488
+ expect(editor.cursorOffset).toBe(11)
489
+ expect(editor.plainText).toBe("Hello World")
490
+ })
491
+ })
492
+
493
+ describe("EditBufferRenderable Methods", () => {
494
+ describe("deleteRange", () => {
495
+ it("should delete range within a single line", async () => {
496
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
497
+ initialValue: "Hello World",
498
+ width: 40,
499
+ height: 10,
500
+ })
501
+
502
+ editor.deleteRange(0, 6, 0, 11)
503
+ await renderOnce()
504
+
505
+ expect(editor.plainText).toBe("Hello ")
506
+ })
507
+
508
+ it("should delete range across multiple lines", async () => {
509
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
510
+ initialValue: "Line 1\nLine 2\nLine 3",
511
+ width: 40,
512
+ height: 10,
513
+ })
514
+
515
+ editor.deleteRange(0, 5, 2, 5)
516
+ await renderOnce()
517
+
518
+ expect(editor.plainText).toBe("Line 3")
519
+ })
520
+
521
+ it("should delete entire line", async () => {
522
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
523
+ initialValue: "First\nSecond\nThird",
524
+ width: 40,
525
+ height: 10,
526
+ })
527
+
528
+ editor.deleteRange(1, 0, 1, 6)
529
+ await renderOnce()
530
+
531
+ expect(editor.plainText).toBe("First\n\nThird")
532
+ })
533
+
534
+ it("should mark yoga node as dirty and request render", async () => {
535
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
536
+ initialValue: "Test text",
537
+ width: 40,
538
+ height: 10,
539
+ })
540
+
541
+ const initialHeight = editor.height
542
+ editor.deleteRange(0, 0, 0, 5)
543
+ await renderOnce()
544
+
545
+ expect(editor.plainText).toBe("text")
546
+ })
547
+
548
+ it("should handle empty range deletion", async () => {
549
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
550
+ initialValue: "Hello",
551
+ width: 40,
552
+ height: 10,
553
+ })
554
+
555
+ editor.deleteRange(0, 2, 0, 2)
556
+ await renderOnce()
557
+
558
+ expect(editor.plainText).toBe("Hello")
559
+ })
560
+ })
561
+
562
+ describe("insertText", () => {
563
+ it("should insert text at cursor position", async () => {
564
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
565
+ initialValue: "Hello",
566
+ width: 40,
567
+ height: 10,
568
+ })
569
+
570
+ editor.insertText(" World")
571
+ await renderOnce()
572
+
573
+ expect(editor.plainText).toBe(" WorldHello")
574
+ })
575
+
576
+ it("should insert text in middle of content", async () => {
577
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
578
+ initialValue: "HelloWorld",
579
+ width: 40,
580
+ height: 10,
581
+ })
582
+
583
+ editor.editBuffer.setCursor(0, 5)
584
+ editor.insertText(" ")
585
+ await renderOnce()
586
+
587
+ expect(editor.plainText).toBe("Hello World")
588
+ })
589
+
590
+ it("should insert multiline text", async () => {
591
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
592
+ initialValue: "Start",
593
+ width: 40,
594
+ height: 10,
595
+ })
596
+
597
+ editor.editBuffer.setCursor(0, 5)
598
+ editor.insertText("\nEnd")
599
+ await renderOnce()
600
+
601
+ expect(editor.plainText).toBe("Start\nEnd")
602
+ })
603
+
604
+ it("should mark yoga node as dirty and request render", async () => {
605
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
606
+ initialValue: "",
607
+ width: 40,
608
+ height: 10,
609
+ })
610
+
611
+ editor.insertText("Test")
612
+ await renderOnce()
613
+
614
+ expect(editor.plainText).toBe("Test")
615
+ })
616
+
617
+ it("should insert multiline text and update content", async () => {
618
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
619
+ initialValue: "Line 1",
620
+ width: 40,
621
+ height: 10,
622
+ })
623
+
624
+ editor.editBuffer.setCursor(0, 6)
625
+ editor.insertText("\nLine 2\nLine 3")
626
+ await renderOnce()
627
+
628
+ expect(editor.plainText).toBe("Line 1\nLine 2\nLine 3")
629
+ expect(editor.logicalCursor.row).toBe(2)
630
+ })
631
+ })
632
+
633
+ describe("Combined deleteRange and insertText", () => {
634
+ it("should replace text by deleting range then inserting", async () => {
635
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
636
+ initialValue: "Hello World",
637
+ width: 40,
638
+ height: 10,
639
+ })
640
+
641
+ editor.deleteRange(0, 6, 0, 11)
642
+ editor.editBuffer.setCursor(0, 6)
643
+ editor.insertText("Friend")
644
+ await renderOnce()
645
+
646
+ expect(editor.plainText).toBe("Hello Friend")
647
+ })
648
+
649
+ it("should handle complex editing operations", async () => {
650
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
651
+ initialValue: "Line 1\nLine 2\nLine 3",
652
+ width: 40,
653
+ height: 10,
654
+ })
655
+
656
+ editor.deleteRange(1, 0, 1, 6)
657
+ editor.editBuffer.setCursor(1, 0)
658
+ editor.insertText("Modified")
659
+ await renderOnce()
660
+
661
+ expect(editor.plainText).toBe("Line 1\nModified\nLine 3")
662
+ })
663
+
664
+ it("should work after multiple operations", async () => {
665
+ const { textarea: editor } = await createTextareaRenderable(currentRenderer, renderOnce, {
666
+ initialValue: "Start",
667
+ width: 40,
668
+ height: 10,
669
+ })
670
+
671
+ editor.editBuffer.setCursor(0, 5)
672
+ editor.insertText(" Middle")
673
+ editor.editBuffer.setCursor(0, 12)
674
+ editor.insertText(" End")
675
+ editor.deleteRange(0, 0, 0, 5)
676
+ await renderOnce()
677
+
678
+ expect(editor.plainText).toBe(" Middle End")
679
+ })
680
+ })
681
+ })
682
+ })