@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,1035 @@
1
+ const std = @import("std");
2
+ const text_buffer = @import("../text-buffer.zig");
3
+ const text_buffer_view = @import("../text-buffer-view.zig");
4
+ const buffer = @import("../buffer.zig");
5
+ const gp = @import("../grapheme.zig");
6
+ const link = @import("../link.zig");
7
+
8
+ const TextBuffer = text_buffer.TextBuffer;
9
+ const TextBufferView = text_buffer_view.TextBufferView;
10
+ const RGBA = text_buffer.RGBA;
11
+
12
+ test "Selection - basic selection without wrap" {
13
+ const pool = gp.initGlobalPool(std.testing.allocator);
14
+ defer gp.deinitGlobalPool();
15
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
16
+ defer link.deinitGlobalLinkPool();
17
+
18
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
19
+ defer tb.deinit();
20
+
21
+ var view = try TextBufferView.init(std.testing.allocator, tb);
22
+ defer view.deinit();
23
+
24
+ try tb.setText("Hello World");
25
+
26
+ _ = view.setLocalSelection(2, 0, 7, 0, null, null);
27
+
28
+ const packed_info = view.packSelectionInfo();
29
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
30
+
31
+ const start = @as(u32, @intCast(packed_info >> 32));
32
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
33
+ try std.testing.expectEqual(@as(u32, 2), start);
34
+ try std.testing.expectEqual(@as(u32, 7), end);
35
+ }
36
+
37
+ test "Selection - with wrapped lines" {
38
+ const pool = gp.initGlobalPool(std.testing.allocator);
39
+ defer gp.deinitGlobalPool();
40
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
41
+ defer link.deinitGlobalLinkPool();
42
+
43
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
44
+ defer tb.deinit();
45
+
46
+ var view = try TextBufferView.init(std.testing.allocator, tb);
47
+ defer view.deinit();
48
+
49
+ try tb.setText("ABCDEFGHIJKLMNOPQRST");
50
+
51
+ view.setWrapMode(.char);
52
+ view.setWrapWidth(10);
53
+
54
+ try std.testing.expectEqual(@as(u32, 2), view.getVirtualLineCount());
55
+
56
+ _ = view.setLocalSelection(5, 0, 5, 1, null, null);
57
+
58
+ const packed_info = view.packSelectionInfo();
59
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
60
+
61
+ const start = @as(u32, @intCast(packed_info >> 32));
62
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
63
+ try std.testing.expectEqual(@as(u32, 5), start);
64
+ try std.testing.expectEqual(@as(u32, 15), end);
65
+ }
66
+
67
+ test "Selection - no selection returns all bits set" {
68
+ const pool = gp.initGlobalPool(std.testing.allocator);
69
+ defer gp.deinitGlobalPool();
70
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
71
+ defer link.deinitGlobalLinkPool();
72
+
73
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
74
+ defer tb.deinit();
75
+
76
+ var view = try TextBufferView.init(std.testing.allocator, tb);
77
+ defer view.deinit();
78
+
79
+ try tb.setText("Hello World");
80
+
81
+ const packed_info = view.packSelectionInfo();
82
+ try std.testing.expectEqual(@as(u64, 0xFFFFFFFF_FFFFFFFF), packed_info);
83
+ }
84
+
85
+ test "Selection - with newline characters" {
86
+ const pool = gp.initGlobalPool(std.testing.allocator);
87
+ defer gp.deinitGlobalPool();
88
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
89
+ defer link.deinitGlobalLinkPool();
90
+
91
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
92
+ defer tb.deinit();
93
+
94
+ var view = try TextBufferView.init(std.testing.allocator, tb);
95
+ defer view.deinit();
96
+
97
+ try tb.setText("Line 1\nLine 2\nLine 3");
98
+
99
+ _ = view.setLocalSelection(2, 1, 4, 2, null, null);
100
+
101
+ const packed_info = view.packSelectionInfo();
102
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
103
+
104
+ var out_buffer: [100]u8 = undefined;
105
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
106
+ const text = out_buffer[0..len];
107
+
108
+ try std.testing.expect(std.mem.indexOf(u8, text, "ne 2") != null);
109
+ try std.testing.expect(std.mem.indexOf(u8, text, "\n") != null);
110
+ }
111
+
112
+ test "Selection - across empty lines" {
113
+ const pool = gp.initGlobalPool(std.testing.allocator);
114
+ defer gp.deinitGlobalPool();
115
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
116
+ defer link.deinitGlobalLinkPool();
117
+
118
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
119
+ defer tb.deinit();
120
+
121
+ var view = try TextBufferView.init(std.testing.allocator, tb);
122
+ defer view.deinit();
123
+
124
+ try tb.setText("Line 1\nLine 2\n\nLine 4");
125
+
126
+ _ = view.setLocalSelection(0, 0, 2, 2, null, null);
127
+
128
+ const packed_info = view.packSelectionInfo();
129
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
130
+
131
+ const start = @as(u32, @intCast(packed_info >> 32));
132
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
133
+ try std.testing.expectEqual(@as(u32, 0), start);
134
+ // With newline-aware offsets: Line 0 (0-5) + newline (6) + Line 1 (7-12) + newline (13) + Line 2 empty (14)
135
+ // Selection to (row=2, col=2) with empty line 2 clamps to col=0, so end=14
136
+ try std.testing.expectEqual(@as(u32, 14), end);
137
+ }
138
+
139
+ test "Selection - ending in empty line" {
140
+ const pool = gp.initGlobalPool(std.testing.allocator);
141
+ defer gp.deinitGlobalPool();
142
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
143
+ defer link.deinitGlobalLinkPool();
144
+
145
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
146
+ defer tb.deinit();
147
+
148
+ var view = try TextBufferView.init(std.testing.allocator, tb);
149
+ defer view.deinit();
150
+
151
+ try tb.setText("Line 1\n\nLine 3");
152
+
153
+ _ = view.setLocalSelection(0, 0, 3, 1, null, null);
154
+
155
+ const packed_info = view.packSelectionInfo();
156
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
157
+
158
+ const start = @as(u32, @intCast(packed_info >> 32));
159
+ try std.testing.expectEqual(@as(u32, 0), start);
160
+ }
161
+
162
+ test "Selection - spanning multiple lines completely" {
163
+ const pool = gp.initGlobalPool(std.testing.allocator);
164
+ defer gp.deinitGlobalPool();
165
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
166
+ defer link.deinitGlobalLinkPool();
167
+
168
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
169
+ defer tb.deinit();
170
+
171
+ var view = try TextBufferView.init(std.testing.allocator, tb);
172
+ defer view.deinit();
173
+
174
+ try tb.setText("First\nSecond\nThird");
175
+
176
+ _ = view.setLocalSelection(0, 1, 6, 1, null, null);
177
+
178
+ var out_buffer: [100]u8 = undefined;
179
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
180
+ const text = out_buffer[0..len];
181
+
182
+ try std.testing.expectEqualStrings("Second", text);
183
+ }
184
+
185
+ test "Selection - including multiple line breaks" {
186
+ const pool = gp.initGlobalPool(std.testing.allocator);
187
+ defer gp.deinitGlobalPool();
188
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
189
+ defer link.deinitGlobalLinkPool();
190
+
191
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
192
+ defer tb.deinit();
193
+
194
+ var view = try TextBufferView.init(std.testing.allocator, tb);
195
+ defer view.deinit();
196
+
197
+ try tb.setText("A\nB\nC\nD");
198
+
199
+ _ = view.setLocalSelection(0, 1, 1, 2, null, null);
200
+
201
+ var out_buffer: [100]u8 = undefined;
202
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
203
+ const text = out_buffer[0..len];
204
+
205
+ try std.testing.expect(std.mem.indexOf(u8, text, "\n") != null);
206
+ try std.testing.expect(std.mem.indexOf(u8, text, "B") != null);
207
+ try std.testing.expect(std.mem.indexOf(u8, text, "C") != null);
208
+ }
209
+
210
+ test "Selection - at line boundaries" {
211
+ const pool = gp.initGlobalPool(std.testing.allocator);
212
+ defer gp.deinitGlobalPool();
213
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
214
+ defer link.deinitGlobalLinkPool();
215
+
216
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
217
+ defer tb.deinit();
218
+
219
+ var view = try TextBufferView.init(std.testing.allocator, tb);
220
+ defer view.deinit();
221
+
222
+ try tb.setText("Line1\nLine2\nLine3");
223
+
224
+ _ = view.setLocalSelection(4, 0, 2, 1, null, null);
225
+
226
+ var out_buffer: [100]u8 = undefined;
227
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
228
+ const text = out_buffer[0..len];
229
+
230
+ try std.testing.expect(std.mem.indexOf(u8, text, "1") != null);
231
+ try std.testing.expect(std.mem.indexOf(u8, text, "\n") != null);
232
+ try std.testing.expect(std.mem.indexOf(u8, text, "Li") != null);
233
+ }
234
+
235
+ test "Selection - empty text" {
236
+ const pool = gp.initGlobalPool(std.testing.allocator);
237
+ defer gp.deinitGlobalPool();
238
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
239
+ defer link.deinitGlobalLinkPool();
240
+
241
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
242
+ defer tb.deinit();
243
+
244
+ var view = try TextBufferView.init(std.testing.allocator, tb);
245
+ defer view.deinit();
246
+
247
+ try tb.setText("");
248
+
249
+ _ = view.setLocalSelection(0, 0, 0, 0, null, null);
250
+
251
+ const packed_info = view.packSelectionInfo();
252
+ try std.testing.expectEqual(@as(u64, 0xFFFFFFFF_FFFFFFFF), packed_info);
253
+ }
254
+
255
+ test "Selection - single character" {
256
+ const pool = gp.initGlobalPool(std.testing.allocator);
257
+ defer gp.deinitGlobalPool();
258
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
259
+ defer link.deinitGlobalLinkPool();
260
+
261
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
262
+ defer tb.deinit();
263
+
264
+ var view = try TextBufferView.init(std.testing.allocator, tb);
265
+ defer view.deinit();
266
+
267
+ try tb.setText("A");
268
+
269
+ _ = view.setLocalSelection(0, 0, 1, 0, null, null);
270
+
271
+ const packed_info = view.packSelectionInfo();
272
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
273
+
274
+ const start = @as(u32, @intCast(packed_info >> 32));
275
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
276
+ try std.testing.expectEqual(@as(u32, 0), start);
277
+ try std.testing.expectEqual(@as(u32, 1), end);
278
+
279
+ var out_buffer: [100]u8 = undefined;
280
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
281
+ const text = out_buffer[0..len];
282
+ try std.testing.expectEqualStrings("A", text);
283
+ }
284
+
285
+ test "Selection - zero-width selection" {
286
+ const pool = gp.initGlobalPool(std.testing.allocator);
287
+ defer gp.deinitGlobalPool();
288
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
289
+ defer link.deinitGlobalLinkPool();
290
+
291
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
292
+ defer tb.deinit();
293
+
294
+ var view = try TextBufferView.init(std.testing.allocator, tb);
295
+ defer view.deinit();
296
+
297
+ try tb.setText("Hello World");
298
+
299
+ _ = view.setLocalSelection(5, 0, 5, 0, null, null);
300
+
301
+ const packed_info = view.packSelectionInfo();
302
+ try std.testing.expectEqual(@as(u64, 0xFFFFFFFF_FFFFFFFF), packed_info);
303
+ }
304
+
305
+ test "Selection - beyond text bounds" {
306
+ const pool = gp.initGlobalPool(std.testing.allocator);
307
+ defer gp.deinitGlobalPool();
308
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
309
+ defer link.deinitGlobalLinkPool();
310
+
311
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
312
+ defer tb.deinit();
313
+
314
+ var view = try TextBufferView.init(std.testing.allocator, tb);
315
+ defer view.deinit();
316
+
317
+ try tb.setText("Hi");
318
+
319
+ _ = view.setLocalSelection(0, 0, 10, 0, null, null);
320
+
321
+ const packed_info = view.packSelectionInfo();
322
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
323
+
324
+ const start = @as(u32, @intCast(packed_info >> 32));
325
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
326
+ try std.testing.expectEqual(@as(u32, 0), start);
327
+ try std.testing.expectEqual(@as(u32, 2), end);
328
+ }
329
+
330
+ test "Selection - clear selection" {
331
+ const pool = gp.initGlobalPool(std.testing.allocator);
332
+ defer gp.deinitGlobalPool();
333
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
334
+ defer link.deinitGlobalLinkPool();
335
+
336
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
337
+ defer tb.deinit();
338
+
339
+ var view = try TextBufferView.init(std.testing.allocator, tb);
340
+ defer view.deinit();
341
+
342
+ try tb.setText("Hello World");
343
+
344
+ _ = view.setLocalSelection(0, 0, 5, 0, null, null);
345
+ var packed_info = view.packSelectionInfo();
346
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
347
+
348
+ view.resetLocalSelection();
349
+ packed_info = view.packSelectionInfo();
350
+ try std.testing.expectEqual(@as(u64, 0xFFFFFFFF_FFFFFFFF), packed_info);
351
+ }
352
+
353
+ test "Selection - at wrap boundary" {
354
+ const pool = gp.initGlobalPool(std.testing.allocator);
355
+ defer gp.deinitGlobalPool();
356
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
357
+ defer link.deinitGlobalLinkPool();
358
+
359
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
360
+ defer tb.deinit();
361
+
362
+ var view = try TextBufferView.init(std.testing.allocator, tb);
363
+ defer view.deinit();
364
+
365
+ try tb.setText("ABCDEFGHIJKLMNOPQRST");
366
+
367
+ view.setWrapMode(.char);
368
+ view.setWrapWidth(10);
369
+
370
+ _ = view.setLocalSelection(9, 0, 1, 1, null, null);
371
+
372
+ const packed_info = view.packSelectionInfo();
373
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
374
+
375
+ const start = @as(u32, @intCast(packed_info >> 32));
376
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
377
+ try std.testing.expectEqual(@as(u32, 9), start);
378
+ try std.testing.expectEqual(@as(u32, 11), end);
379
+ }
380
+
381
+ test "Selection - spanning multiple wrapped lines" {
382
+ const pool = gp.initGlobalPool(std.testing.allocator);
383
+ defer gp.deinitGlobalPool();
384
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
385
+ defer link.deinitGlobalLinkPool();
386
+
387
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
388
+ defer tb.deinit();
389
+
390
+ var view = try TextBufferView.init(std.testing.allocator, tb);
391
+ defer view.deinit();
392
+
393
+ try tb.setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123");
394
+
395
+ view.setWrapMode(.char);
396
+ view.setWrapWidth(10);
397
+ try std.testing.expectEqual(@as(u32, 3), view.getVirtualLineCount());
398
+
399
+ _ = view.setLocalSelection(2, 0, 8, 2, null, null);
400
+
401
+ const packed_info = view.packSelectionInfo();
402
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
403
+
404
+ const start = @as(u32, @intCast(packed_info >> 32));
405
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
406
+ try std.testing.expectEqual(@as(u32, 2), start);
407
+ try std.testing.expectEqual(@as(u32, 28), end);
408
+ }
409
+
410
+ test "Selection - changes when wrap width changes" {
411
+ const pool = gp.initGlobalPool(std.testing.allocator);
412
+ defer gp.deinitGlobalPool();
413
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
414
+ defer link.deinitGlobalLinkPool();
415
+
416
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
417
+ defer tb.deinit();
418
+
419
+ var view = try TextBufferView.init(std.testing.allocator, tb);
420
+ defer view.deinit();
421
+
422
+ try tb.setText("ABCDEFGHIJKLMNOPQRST");
423
+
424
+ view.setWrapMode(.char);
425
+ view.setWrapWidth(10);
426
+ _ = view.setLocalSelection(5, 0, 5, 1, null, null);
427
+
428
+ var packed_info = view.packSelectionInfo();
429
+ var start = @as(u32, @intCast(packed_info >> 32));
430
+ var end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
431
+ try std.testing.expectEqual(@as(u32, 5), start);
432
+ try std.testing.expectEqual(@as(u32, 15), end);
433
+
434
+ view.setWrapWidth(5);
435
+ _ = view.setLocalSelection(5, 0, 5, 1, null, null);
436
+
437
+ packed_info = view.packSelectionInfo();
438
+ start = @as(u32, @intCast(packed_info >> 32));
439
+ end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
440
+
441
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
442
+ }
443
+
444
+ test "Selection - with newlines and wrapping" {
445
+ const pool = gp.initGlobalPool(std.testing.allocator);
446
+ defer gp.deinitGlobalPool();
447
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
448
+ defer link.deinitGlobalLinkPool();
449
+
450
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
451
+ defer tb.deinit();
452
+
453
+ var view = try TextBufferView.init(std.testing.allocator, tb);
454
+ defer view.deinit();
455
+
456
+ try tb.setText("ABCDEFGHIJKLMNO\nPQRSTUVWXYZ");
457
+
458
+ view.setWrapMode(.char);
459
+ view.setWrapWidth(10);
460
+
461
+ const vline_count = view.getVirtualLineCount();
462
+ try std.testing.expect(vline_count >= 3);
463
+
464
+ _ = view.setLocalSelection(5, 0, 5, 2, null, null);
465
+
466
+ const packed_info = view.packSelectionInfo();
467
+ try std.testing.expect(packed_info != 0xFFFFFFFF_FFFFFFFF);
468
+ }
469
+
470
+ test "Selection - getSelectedText simple" {
471
+ const pool = gp.initGlobalPool(std.testing.allocator);
472
+ defer gp.deinitGlobalPool();
473
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
474
+ defer link.deinitGlobalLinkPool();
475
+
476
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
477
+ defer tb.deinit();
478
+
479
+ var view = try TextBufferView.init(std.testing.allocator, tb);
480
+ defer view.deinit();
481
+
482
+ try tb.setText("Hello World");
483
+ view.setSelection(6, 11, null, null);
484
+
485
+ var out_buffer: [100]u8 = undefined;
486
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
487
+ const text = out_buffer[0..len];
488
+
489
+ try std.testing.expectEqualStrings("World", text);
490
+ }
491
+
492
+ test "Selection - getSelectedText with newlines" {
493
+ const pool = gp.initGlobalPool(std.testing.allocator);
494
+ defer gp.deinitGlobalPool();
495
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
496
+ defer link.deinitGlobalLinkPool();
497
+
498
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
499
+ defer tb.deinit();
500
+
501
+ var view = try TextBufferView.init(std.testing.allocator, tb);
502
+ defer view.deinit();
503
+
504
+ try tb.setText("Line 1\nLine 2\nLine 3");
505
+ // With rope weight system: Line 0 (0-5) + newline (6) + Line 1 (7-12) + newline (13) + Line 2 (14-19)
506
+ // Selection [0, 9) includes: "Line 1" (0-5) + newline (6) + "Li" (7-8) = 9 chars total
507
+ view.setSelection(0, 9, null, null);
508
+
509
+ var out_buffer: [100]u8 = undefined;
510
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
511
+ const text = out_buffer[0..len];
512
+
513
+ try std.testing.expectEqualStrings("Line 1\nLi", text);
514
+ }
515
+
516
+ test "Selection - spanning multiple lines with getSelectedText" {
517
+ const pool = gp.initGlobalPool(std.testing.allocator);
518
+ defer gp.deinitGlobalPool();
519
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
520
+ defer link.deinitGlobalLinkPool();
521
+
522
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
523
+ defer tb.deinit();
524
+
525
+ var view = try TextBufferView.init(std.testing.allocator, tb);
526
+ defer view.deinit();
527
+
528
+ try tb.setText("Red\nBlue");
529
+ // Rope offsets: "Red" (0-2) + newline (3) + "Blue" (4-7)
530
+ // Selection [2, 5) = "d" (2) + newline (3) + "B" (4) = 3 chars
531
+ view.setSelection(2, 5, null, null);
532
+
533
+ var out_buffer: [100]u8 = undefined;
534
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
535
+ const text = out_buffer[0..len];
536
+
537
+ try std.testing.expectEqualStrings("d\nB", text);
538
+ }
539
+
540
+ test "Selection - with graphemes" {
541
+ const pool = gp.initGlobalPool(std.testing.allocator);
542
+ defer gp.deinitGlobalPool();
543
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
544
+ defer link.deinitGlobalLinkPool();
545
+
546
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
547
+ defer tb.deinit();
548
+
549
+ var view = try TextBufferView.init(std.testing.allocator, tb);
550
+ defer view.deinit();
551
+
552
+ try tb.setText("Hello 🌍 World");
553
+
554
+ view.setSelection(0, 8, null, null);
555
+
556
+ var out_buffer: [100]u8 = undefined;
557
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
558
+ const text = out_buffer[0..len];
559
+
560
+ try std.testing.expect(std.mem.indexOf(u8, text, "Hello") != null);
561
+ try std.testing.expect(std.mem.indexOf(u8, text, "🌍") != null);
562
+ }
563
+
564
+ test "Selection - wide emoji at boundary" {
565
+ const pool = gp.initGlobalPool(std.testing.allocator);
566
+ defer gp.deinitGlobalPool();
567
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
568
+ defer link.deinitGlobalLinkPool();
569
+
570
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
571
+ defer tb.deinit();
572
+
573
+ var view = try TextBufferView.init(std.testing.allocator, tb);
574
+ defer view.deinit();
575
+
576
+ try tb.setText("Hello 🌍 World");
577
+
578
+ // Select "Hello 🌍" which is 7 columns: H(0),e(1),l(2),l(3),o(4),space(5),🌍(6-7)
579
+ // Note: 🌍 is a 2-wide character
580
+ // Selection [0, 7) should include the emoji because it starts at column 6
581
+ view.setSelection(0, 7, null, null);
582
+
583
+ var out_buffer: [100]u8 = undefined;
584
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
585
+ const text = out_buffer[0..len];
586
+
587
+ try std.testing.expectEqualStrings("Hello 🌍", text);
588
+ }
589
+
590
+ test "Selection - wide emoji BEFORE selection start should be excluded" {
591
+ const pool = gp.initGlobalPool(std.testing.allocator);
592
+ defer gp.deinitGlobalPool();
593
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
594
+ defer link.deinitGlobalLinkPool();
595
+
596
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
597
+ defer tb.deinit();
598
+
599
+ var view = try TextBufferView.init(std.testing.allocator, tb);
600
+ defer view.deinit();
601
+
602
+ try tb.setText("Hello 🌍 World");
603
+
604
+ // Layout: H(0) e(1) l(2) l(3) o(4) space(5) 🌍(6-7) space(8) W(9) o(10) r(11) l(12) d(13)
605
+ // Select [7, 10) - starts at col 7 (second cell of emoji), ends at col 10
606
+ // When selection starts at second cell of width=2 grapheme, snap backward to include it
607
+ // So selection should include emoji (snaps to col 6), space, and W
608
+ // Should NOT include 'o' at col 10 because selection is [7, 10) exclusive end
609
+ view.setSelection(7, 10, null, null);
610
+
611
+ var out_buffer: [100]u8 = undefined;
612
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
613
+ const text = out_buffer[0..len];
614
+
615
+ try std.testing.expectEqualStrings("🌍 W", text);
616
+ }
617
+
618
+ test "Selection - start at second cell of width=2 grapheme should snap backward to include it" {
619
+ const pool = gp.initGlobalPool(std.testing.allocator);
620
+ defer gp.deinitGlobalPool();
621
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
622
+ defer link.deinitGlobalLinkPool();
623
+
624
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
625
+ defer tb.deinit();
626
+
627
+ var view = try TextBufferView.init(std.testing.allocator, tb);
628
+ defer view.deinit();
629
+
630
+ try tb.setText("AB🌍CD");
631
+
632
+ view.setSelection(3, 5, null, null);
633
+
634
+ var out_buffer: [100]u8 = undefined;
635
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
636
+ const text = out_buffer[0..len];
637
+
638
+ try std.testing.expectEqualStrings("🌍C", text);
639
+ }
640
+
641
+ test "Selection - end at first cell of width=2 grapheme should snap forward to include it" {
642
+ const pool = gp.initGlobalPool(std.testing.allocator);
643
+ defer gp.deinitGlobalPool();
644
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
645
+ defer link.deinitGlobalLinkPool();
646
+
647
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
648
+ defer tb.deinit();
649
+
650
+ var view = try TextBufferView.init(std.testing.allocator, tb);
651
+ defer view.deinit();
652
+
653
+ try tb.setText("AB🌍CD");
654
+
655
+ view.setSelection(1, 3, null, null);
656
+
657
+ var out_buffer: [100]u8 = undefined;
658
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
659
+ const text = out_buffer[0..len];
660
+
661
+ try std.testing.expectEqualStrings("B🌍", text);
662
+ }
663
+
664
+ test "Selection - both boundaries at cells of width=2 graphemes" {
665
+ const pool = gp.initGlobalPool(std.testing.allocator);
666
+ defer gp.deinitGlobalPool();
667
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
668
+ defer link.deinitGlobalLinkPool();
669
+
670
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
671
+ defer tb.deinit();
672
+
673
+ var view = try TextBufferView.init(std.testing.allocator, tb);
674
+ defer view.deinit();
675
+
676
+ try tb.setText("A🌍B🌎C");
677
+
678
+ view.setSelection(2, 5, null, null);
679
+
680
+ var out_buffer: [100]u8 = undefined;
681
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
682
+ const text = out_buffer[0..len];
683
+
684
+ try std.testing.expectEqualStrings("🌍B🌎", text);
685
+ }
686
+
687
+ test "Selection - updateSelection extends existing selection" {
688
+ const pool = gp.initGlobalPool(std.testing.allocator);
689
+ defer gp.deinitGlobalPool();
690
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
691
+ defer link.deinitGlobalLinkPool();
692
+
693
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
694
+ defer tb.deinit();
695
+
696
+ var view = try TextBufferView.init(std.testing.allocator, tb);
697
+ defer view.deinit();
698
+
699
+ try tb.setText("Hello World");
700
+
701
+ // Set initial selection from 0 to 5
702
+ view.setSelection(0, 5, null, null);
703
+
704
+ var packed_info = view.packSelectionInfo();
705
+ var start = @as(u32, @intCast(packed_info >> 32));
706
+ var end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
707
+ try std.testing.expectEqual(@as(u32, 0), start);
708
+ try std.testing.expectEqual(@as(u32, 5), end);
709
+
710
+ // Update to extend end to 11
711
+ view.updateSelection(11, null, null);
712
+
713
+ packed_info = view.packSelectionInfo();
714
+ start = @as(u32, @intCast(packed_info >> 32));
715
+ end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
716
+ try std.testing.expectEqual(@as(u32, 0), start);
717
+ try std.testing.expectEqual(@as(u32, 11), end);
718
+
719
+ var out_buffer: [100]u8 = undefined;
720
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
721
+ const text = out_buffer[0..len];
722
+ try std.testing.expectEqualStrings("Hello World", text);
723
+ }
724
+
725
+ test "Selection - updateSelection with no existing selection does nothing" {
726
+ const pool = gp.initGlobalPool(std.testing.allocator);
727
+ defer gp.deinitGlobalPool();
728
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
729
+ defer link.deinitGlobalLinkPool();
730
+
731
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
732
+ defer tb.deinit();
733
+
734
+ var view = try TextBufferView.init(std.testing.allocator, tb);
735
+ defer view.deinit();
736
+
737
+ try tb.setText("Hello World");
738
+
739
+ // No selection set
740
+ const packed_info_before = view.packSelectionInfo();
741
+ try std.testing.expectEqual(@as(u64, 0xFFFFFFFF_FFFFFFFF), packed_info_before);
742
+
743
+ // Try to update - should do nothing
744
+ view.updateSelection(5, null, null);
745
+
746
+ const packed_info_after = view.packSelectionInfo();
747
+ try std.testing.expectEqual(@as(u64, 0xFFFFFFFF_FFFFFFFF), packed_info_after);
748
+ }
749
+
750
+ test "Selection - updateSelection can shrink selection" {
751
+ const pool = gp.initGlobalPool(std.testing.allocator);
752
+ defer gp.deinitGlobalPool();
753
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
754
+ defer link.deinitGlobalLinkPool();
755
+
756
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
757
+ defer tb.deinit();
758
+
759
+ var view = try TextBufferView.init(std.testing.allocator, tb);
760
+ defer view.deinit();
761
+
762
+ try tb.setText("Hello World");
763
+
764
+ view.setSelection(0, 11, null, null);
765
+
766
+ // Shrink to 5
767
+ view.updateSelection(5, null, null);
768
+
769
+ const packed_info = view.packSelectionInfo();
770
+ const start = @as(u32, @intCast(packed_info >> 32));
771
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
772
+ try std.testing.expectEqual(@as(u32, 0), start);
773
+ try std.testing.expectEqual(@as(u32, 5), end);
774
+
775
+ var out_buffer: [100]u8 = undefined;
776
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
777
+ const text = out_buffer[0..len];
778
+ try std.testing.expectEqualStrings("Hello", text);
779
+ }
780
+
781
+ test "Selection - updateLocalSelection extends focus position" {
782
+ const pool = gp.initGlobalPool(std.testing.allocator);
783
+ defer gp.deinitGlobalPool();
784
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
785
+ defer link.deinitGlobalLinkPool();
786
+
787
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
788
+ defer tb.deinit();
789
+
790
+ var view = try TextBufferView.init(std.testing.allocator, tb);
791
+ defer view.deinit();
792
+
793
+ try tb.setText("Hello World");
794
+
795
+ // Set initial local selection from (0,0) to (5,0)
796
+ _ = view.setLocalSelection(0, 0, 5, 0, null, null);
797
+
798
+ var packed_info = view.packSelectionInfo();
799
+ var start = @as(u32, @intCast(packed_info >> 32));
800
+ var end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
801
+ try std.testing.expectEqual(@as(u32, 0), start);
802
+ try std.testing.expectEqual(@as(u32, 5), end);
803
+
804
+ // Update focus to (11,0) - should keep anchor at (0,0)
805
+ const changed = view.updateLocalSelection(0, 0, 11, 0, null, null);
806
+ try std.testing.expect(changed);
807
+
808
+ packed_info = view.packSelectionInfo();
809
+ start = @as(u32, @intCast(packed_info >> 32));
810
+ end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
811
+ try std.testing.expectEqual(@as(u32, 0), start);
812
+ try std.testing.expectEqual(@as(u32, 11), end);
813
+
814
+ var out_buffer: [100]u8 = undefined;
815
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
816
+ const text = out_buffer[0..len];
817
+ try std.testing.expectEqualStrings("Hello World", text);
818
+ }
819
+
820
+ test "Selection - updateLocalSelection with no existing selection falls back to setLocalSelection" {
821
+ const pool = gp.initGlobalPool(std.testing.allocator);
822
+ defer gp.deinitGlobalPool();
823
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
824
+ defer link.deinitGlobalLinkPool();
825
+
826
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
827
+ defer tb.deinit();
828
+
829
+ var view = try TextBufferView.init(std.testing.allocator, tb);
830
+ defer view.deinit();
831
+
832
+ try tb.setText("Hello World");
833
+
834
+ // No selection set - updateLocalSelection now falls back to setLocalSelection
835
+ const changed = view.updateLocalSelection(0, 0, 5, 0, null, null);
836
+ try std.testing.expect(changed);
837
+
838
+ const packed_info = view.packSelectionInfo();
839
+ const start = @as(u32, @intCast(packed_info >> 32));
840
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
841
+ try std.testing.expectEqual(@as(u32, 0), start);
842
+ try std.testing.expectEqual(@as(u32, 5), end);
843
+ }
844
+
845
+ test "Selection - updateLocalSelection can shrink selection" {
846
+ const pool = gp.initGlobalPool(std.testing.allocator);
847
+ defer gp.deinitGlobalPool();
848
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
849
+ defer link.deinitGlobalLinkPool();
850
+
851
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
852
+ defer tb.deinit();
853
+
854
+ var view = try TextBufferView.init(std.testing.allocator, tb);
855
+ defer view.deinit();
856
+
857
+ try tb.setText("Hello World");
858
+
859
+ _ = view.setLocalSelection(0, 0, 11, 0, null, null);
860
+
861
+ // Shrink focus to 5
862
+ const changed = view.updateLocalSelection(0, 0, 5, 0, null, null);
863
+ try std.testing.expect(changed);
864
+
865
+ const packed_info = view.packSelectionInfo();
866
+ const start = @as(u32, @intCast(packed_info >> 32));
867
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
868
+ try std.testing.expectEqual(@as(u32, 0), start);
869
+ try std.testing.expectEqual(@as(u32, 5), end);
870
+
871
+ var out_buffer: [100]u8 = undefined;
872
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
873
+ const text = out_buffer[0..len];
874
+ try std.testing.expectEqualStrings("Hello", text);
875
+ }
876
+
877
+ test "Selection - updateLocalSelection across multiple lines" {
878
+ const pool = gp.initGlobalPool(std.testing.allocator);
879
+ defer gp.deinitGlobalPool();
880
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
881
+ defer link.deinitGlobalLinkPool();
882
+
883
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
884
+ defer tb.deinit();
885
+
886
+ var view = try TextBufferView.init(std.testing.allocator, tb);
887
+ defer view.deinit();
888
+
889
+ try tb.setText("Line 1\nLine 2\nLine 3");
890
+
891
+ // Start selection at (2, 0)
892
+ _ = view.setLocalSelection(2, 0, 2, 0, null, null);
893
+
894
+ // Extend to (4, 1) - should select from "ne 1\nLine"
895
+ const changed = view.updateLocalSelection(2, 0, 4, 1, null, null);
896
+ try std.testing.expect(changed);
897
+
898
+ var out_buffer: [100]u8 = undefined;
899
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
900
+ const text = out_buffer[0..len];
901
+
902
+ try std.testing.expect(std.mem.indexOf(u8, text, "ne 1") != null);
903
+ try std.testing.expect(std.mem.indexOf(u8, text, "\n") != null);
904
+ try std.testing.expect(std.mem.indexOf(u8, text, "Line") != null);
905
+ }
906
+
907
+ test "Selection - updateLocalSelection backward selection" {
908
+ const pool = gp.initGlobalPool(std.testing.allocator);
909
+ defer gp.deinitGlobalPool();
910
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
911
+ defer link.deinitGlobalLinkPool();
912
+
913
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
914
+ defer tb.deinit();
915
+
916
+ var view = try TextBufferView.init(std.testing.allocator, tb);
917
+ defer view.deinit();
918
+
919
+ try tb.setText("Hello World!");
920
+
921
+ // Set anchor at (11, 0) - after "World"
922
+ _ = view.setLocalSelection(11, 0, 11, 0, null, null);
923
+
924
+ // Move focus backward to (6, 0) - start of "World"
925
+ // Backward selection adds +1 to make it inclusive, so [6, 12) = "World!"
926
+ const changed = view.updateLocalSelection(11, 0, 6, 0, null, null);
927
+ try std.testing.expect(changed);
928
+
929
+ const packed_info = view.packSelectionInfo();
930
+ const start = @as(u32, @intCast(packed_info >> 32));
931
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
932
+ try std.testing.expectEqual(@as(u32, 6), start);
933
+ try std.testing.expectEqual(@as(u32, 12), end);
934
+
935
+ var out_buffer: [100]u8 = undefined;
936
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
937
+ const text = out_buffer[0..len];
938
+ try std.testing.expectEqualStrings("World!", text);
939
+ }
940
+
941
+ test "Selection - updateLocalSelection with wrapped lines" {
942
+ const pool = gp.initGlobalPool(std.testing.allocator);
943
+ defer gp.deinitGlobalPool();
944
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
945
+ defer link.deinitGlobalLinkPool();
946
+
947
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
948
+ defer tb.deinit();
949
+
950
+ var view = try TextBufferView.init(std.testing.allocator, tb);
951
+ defer view.deinit();
952
+
953
+ try tb.setText("ABCDEFGHIJKLMNOPQRST");
954
+
955
+ view.setWrapMode(.char);
956
+ view.setWrapWidth(10);
957
+
958
+ try std.testing.expectEqual(@as(u32, 2), view.getVirtualLineCount());
959
+
960
+ // Start at (0, 0)
961
+ _ = view.setLocalSelection(0, 0, 0, 0, null, null);
962
+
963
+ // Extend to second wrapped line (5, 1)
964
+ const changed = view.updateLocalSelection(0, 0, 5, 1, null, null);
965
+ try std.testing.expect(changed);
966
+
967
+ const packed_info = view.packSelectionInfo();
968
+ const start = @as(u32, @intCast(packed_info >> 32));
969
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
970
+ try std.testing.expectEqual(@as(u32, 0), start);
971
+ try std.testing.expectEqual(@as(u32, 15), end);
972
+
973
+ var out_buffer: [100]u8 = undefined;
974
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
975
+ const text = out_buffer[0..len];
976
+ try std.testing.expectEqualStrings("ABCDEFGHIJKLMNO", text);
977
+ }
978
+
979
+ test "Selection - updateLocalSelection with same focus position maintains selection" {
980
+ const pool = gp.initGlobalPool(std.testing.allocator);
981
+ defer gp.deinitGlobalPool();
982
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
983
+ defer link.deinitGlobalLinkPool();
984
+
985
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
986
+ defer tb.deinit();
987
+
988
+ var view = try TextBufferView.init(std.testing.allocator, tb);
989
+ defer view.deinit();
990
+
991
+ try tb.setText("Hello World");
992
+
993
+ _ = view.setLocalSelection(0, 0, 5, 0, null, null);
994
+
995
+ // Update to same focus position - selection should remain the same
996
+ _ = view.updateLocalSelection(0, 0, 5, 0, null, null);
997
+
998
+ const packed_info = view.packSelectionInfo();
999
+ const start = @as(u32, @intCast(packed_info >> 32));
1000
+ const end = @as(u32, @intCast(packed_info & 0xFFFFFFFF));
1001
+ try std.testing.expectEqual(@as(u32, 0), start);
1002
+ try std.testing.expectEqual(@as(u32, 5), end);
1003
+ }
1004
+
1005
+ test "Selection - updateLocalSelection preserves anchor correctly" {
1006
+ const pool = gp.initGlobalPool(std.testing.allocator);
1007
+ defer gp.deinitGlobalPool();
1008
+ const link_pool = link.initGlobalLinkPool(std.testing.allocator);
1009
+ defer link.deinitGlobalLinkPool();
1010
+
1011
+ var tb = try TextBuffer.init(std.testing.allocator, pool, link_pool, .unicode);
1012
+ defer tb.deinit();
1013
+
1014
+ var view = try TextBufferView.init(std.testing.allocator, tb);
1015
+ defer view.deinit();
1016
+
1017
+ try tb.setText("Line 1\nLine 2\nLine 3");
1018
+
1019
+ // Set anchor at (3, 1) - middle of "Line 2" (at 'e' in "Line")
1020
+ _ = view.setLocalSelection(3, 1, 3, 1, null, null);
1021
+
1022
+ // Update focus multiple times - last one to (6, 2) which is end of "Line 3"
1023
+ _ = view.updateLocalSelection(3, 1, 6, 1, null, null);
1024
+ _ = view.updateLocalSelection(3, 1, 2, 2, null, null);
1025
+ _ = view.updateLocalSelection(3, 1, 6, 2, null, null);
1026
+
1027
+ // Final selection should still have anchor at (3, 1)
1028
+ var out_buffer: [100]u8 = undefined;
1029
+ const len = view.getSelectedTextIntoBuffer(&out_buffer);
1030
+ const text = out_buffer[0..len];
1031
+
1032
+ // Should include "e 2\nLine 3" since anchor is at col 3 of line 1 and focus at end of line 2
1033
+ try std.testing.expect(std.mem.indexOf(u8, text, "e 2") != null);
1034
+ try std.testing.expect(std.mem.indexOf(u8, text, "\nLine 3") != null);
1035
+ }