@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,499 @@
1
+ const std = @import("std");
2
+ const Allocator = std.mem.Allocator;
3
+ const seg_mod = @import("text-buffer-segment.zig");
4
+ const mem_registry_mod = @import("mem-registry.zig");
5
+ const utf8 = @import("utf8.zig");
6
+
7
+ const Segment = seg_mod.Segment;
8
+ const UnifiedRope = seg_mod.UnifiedRope;
9
+ const TextChunk = seg_mod.TextChunk;
10
+ const GraphemeInfo = seg_mod.GraphemeInfo;
11
+ const MemRegistry = mem_registry_mod.MemRegistry;
12
+
13
+ pub const LineInfo = struct {
14
+ line_idx: u32,
15
+ col_offset: u32,
16
+ width_cols: u32,
17
+ seg_start: u32,
18
+ seg_end: u32,
19
+ };
20
+
21
+ pub const Coords = struct {
22
+ row: u32,
23
+ col: u32,
24
+ };
25
+
26
+ /// Note: Takes mutable rope for lazy marker cache rebuilding
27
+ pub fn walkLines(
28
+ rope: *UnifiedRope,
29
+ ctx: *anyopaque,
30
+ callback: *const fn (ctx: *anyopaque, line_info: LineInfo) void,
31
+ include_newlines_in_offset: bool,
32
+ ) void {
33
+ const linestart_count = rope.markerCount(.linestart);
34
+ if (linestart_count == 0) return;
35
+
36
+ var i: u32 = 0;
37
+ while (i < linestart_count) : (i += 1) {
38
+ const marker = rope.getMarker(.linestart, i) orelse continue;
39
+ const line_start_weight = marker.global_weight;
40
+ const width_cols = lineWidthAt(rope, i);
41
+ const seg_end = if (i + 1 < linestart_count) blk: {
42
+ const next_marker = rope.getMarker(.linestart, i + 1) orelse break :blk marker.leaf_index + 1;
43
+ break :blk next_marker.leaf_index;
44
+ } else blk: {
45
+ break :blk rope.count();
46
+ };
47
+
48
+ // Line i has i newlines before it (one after each previous line)
49
+ const col_offset = if (include_newlines_in_offset)
50
+ line_start_weight
51
+ else
52
+ line_start_weight - i;
53
+
54
+ callback(ctx, LineInfo{
55
+ .line_idx = i,
56
+ .col_offset = col_offset,
57
+ .width_cols = width_cols,
58
+ .seg_start = marker.leaf_index,
59
+ .seg_end = seg_end,
60
+ });
61
+ }
62
+ }
63
+
64
+ /// This is the most efficient way to iterate lines and their content
65
+ pub fn walkLinesAndSegments(
66
+ rope: *const UnifiedRope,
67
+ ctx: *anyopaque,
68
+ segment_callback: *const fn (ctx: *anyopaque, line_idx: u32, chunk: *const TextChunk, chunk_idx_in_line: u32) void,
69
+ line_end_callback: *const fn (ctx: *anyopaque, line_info: LineInfo) void,
70
+ ) void {
71
+ if (rope.count() == 0) {
72
+ return;
73
+ }
74
+
75
+ const WalkContext = struct {
76
+ user_ctx: *anyopaque,
77
+ seg_callback: *const fn (ctx: *anyopaque, line_idx: u32, chunk: *const TextChunk, chunk_idx_in_line: u32) void,
78
+ line_callback: *const fn (ctx: *anyopaque, line_info: LineInfo) void,
79
+ current_line_idx: u32 = 0,
80
+ current_col_offset: u32 = 0,
81
+ line_start_seg: u32 = 0,
82
+ current_seg_idx: u32 = 0,
83
+ line_width_cols: u32 = 0,
84
+ chunk_idx_in_line: u32 = 0,
85
+
86
+ fn walker(walk_ctx_ptr: *anyopaque, seg: *const Segment, idx: u32) UnifiedRope.Node.WalkerResult {
87
+ const walk_ctx = @as(*@This(), @ptrCast(@alignCast(walk_ctx_ptr)));
88
+
89
+ if (seg.asText()) |chunk| {
90
+ walk_ctx.seg_callback(walk_ctx.user_ctx, walk_ctx.current_line_idx, chunk, walk_ctx.chunk_idx_in_line);
91
+ walk_ctx.chunk_idx_in_line += 1;
92
+ walk_ctx.line_width_cols += chunk.width;
93
+ } else if (seg.isBreak()) {
94
+ walk_ctx.line_callback(walk_ctx.user_ctx, LineInfo{
95
+ .line_idx = walk_ctx.current_line_idx,
96
+ .col_offset = walk_ctx.current_col_offset,
97
+ .width_cols = walk_ctx.line_width_cols,
98
+ .seg_start = walk_ctx.line_start_seg,
99
+ .seg_end = idx, // Don't include the break
100
+ });
101
+
102
+ walk_ctx.current_line_idx += 1;
103
+ walk_ctx.current_col_offset += walk_ctx.line_width_cols + 1;
104
+ walk_ctx.line_start_seg = idx + 1;
105
+ walk_ctx.line_width_cols = 0;
106
+ walk_ctx.chunk_idx_in_line = 0;
107
+ }
108
+
109
+ walk_ctx.current_seg_idx = idx + 1;
110
+ return .{};
111
+ }
112
+ };
113
+
114
+ var walk_ctx = WalkContext{
115
+ .user_ctx = ctx,
116
+ .seg_callback = segment_callback,
117
+ .line_callback = line_end_callback,
118
+ };
119
+ rope.walk(&walk_ctx, WalkContext.walker) catch {};
120
+
121
+ // Emit final line if we have content after last break OR if we had at least one break
122
+ // (A trailing break creates an empty final line)
123
+ const had_breaks = walk_ctx.current_line_idx > 0;
124
+ const has_content_after_break = walk_ctx.line_start_seg < walk_ctx.current_seg_idx;
125
+
126
+ if (has_content_after_break or had_breaks) {
127
+ line_end_callback(ctx, LineInfo{
128
+ .line_idx = walk_ctx.current_line_idx,
129
+ .col_offset = walk_ctx.current_col_offset,
130
+ .width_cols = walk_ctx.line_width_cols,
131
+ .seg_start = walk_ctx.line_start_seg,
132
+ .seg_end = walk_ctx.current_seg_idx,
133
+ });
134
+ }
135
+ }
136
+
137
+ pub fn getLineCount(rope: *const UnifiedRope) u32 {
138
+ const metrics = rope.root.metrics();
139
+ return metrics.custom.linestart_count;
140
+ }
141
+
142
+ pub fn getMaxLineWidth(rope: *const UnifiedRope) u32 {
143
+ const metrics = rope.root.metrics();
144
+ return metrics.custom.max_line_width;
145
+ }
146
+
147
+ pub fn getTotalWidth(rope: *const UnifiedRope) u32 {
148
+ const metrics = rope.root.metrics();
149
+ return metrics.custom.total_width;
150
+ }
151
+
152
+ /// Optimized O(1) implementation using linestart marker lookups
153
+ /// Note: Rope weight includes newlines (each .brk adds +1), but col is still display width
154
+ /// Takes mutable rope for lazy marker cache rebuilding
155
+ pub fn coordsToOffset(rope: *UnifiedRope, row: u32, col: u32) ?u32 {
156
+ const linestart_count = rope.markerCount(.linestart);
157
+ if (row >= linestart_count) return null;
158
+
159
+ const marker = rope.getMarker(.linestart, row) orelse return null;
160
+ const line_start_weight = marker.global_weight;
161
+ const line_width = lineWidthAt(rope, row);
162
+
163
+ if (col > line_width) return null;
164
+
165
+ return line_start_weight + col;
166
+ }
167
+
168
+ /// Optimized O(log n) implementation using binary search on linestart markers
169
+ /// Note: Rope weight includes newlines, so valid offsets are 0..totalWeight() inclusive
170
+ /// Takes mutable rope for lazy marker cache rebuilding
171
+ /// TODO: Should clamp to min/max offset and always return valid coords
172
+ pub fn offsetToCoords(rope: *UnifiedRope, offset: u32) ?Coords {
173
+ const linestart_count = rope.markerCount(.linestart);
174
+ if (linestart_count == 0) return null;
175
+
176
+ const total_weight = rope.totalWeight();
177
+ if (offset > total_weight) return null;
178
+
179
+ var left: u32 = 0;
180
+ var right: u32 = linestart_count;
181
+
182
+ while (left < right) {
183
+ const mid = left + (right - left) / 2;
184
+ const marker = rope.getMarker(.linestart, mid) orelse return null;
185
+ const line_start_weight = marker.global_weight;
186
+
187
+ if (offset < line_start_weight) {
188
+ right = mid;
189
+ } else {
190
+ const next_line_start_weight = if (mid + 1 < linestart_count) blk: {
191
+ const next_marker = rope.getMarker(.linestart, mid + 1) orelse return null;
192
+ break :blk next_marker.global_weight;
193
+ } else blk: {
194
+ // Last line: ends at total weight
195
+ break :blk total_weight;
196
+ };
197
+
198
+ // Offset belongs to this line if it's before the next line starts
199
+ // (newline offset at end of non-final line maps to col==line_width)
200
+ if (offset < next_line_start_weight or (offset == total_weight and mid + 1 == linestart_count)) {
201
+ return Coords{
202
+ .row = mid,
203
+ .col = offset - line_start_weight,
204
+ };
205
+ }
206
+ left = mid + 1;
207
+ }
208
+ }
209
+
210
+ return null;
211
+ }
212
+
213
+ /// Note: Returns display width only (excludes newline weight)
214
+ /// Takes mutable rope for lazy marker cache rebuilding
215
+ pub fn lineWidthAt(rope: *UnifiedRope, row: u32) u32 {
216
+ const linestart_count = rope.markerCount(.linestart);
217
+ if (row >= linestart_count) return 0;
218
+
219
+ const line_marker = rope.getMarker(.linestart, row) orelse return 0;
220
+ const line_start_weight = line_marker.global_weight;
221
+ if (row + 1 < linestart_count) {
222
+ // Non-final line: width = (next_line_start - current_start - 1_for_newline)
223
+ const next_marker = rope.getMarker(.linestart, row + 1) orelse return 0;
224
+ const next_line_start_weight = next_marker.global_weight;
225
+ // Guard against underflow (adjacent linestart markers or empty line)
226
+ if (next_line_start_weight <= line_start_weight) return 0;
227
+ return next_line_start_weight - line_start_weight - 1;
228
+ } else {
229
+ // Final line: width = total_weight - line_start (total weight includes all previous newlines)
230
+ const total_weight = rope.totalWeight();
231
+ return total_weight - line_start_weight;
232
+ }
233
+ }
234
+
235
+ /// Takes mutable rope for lazy marker cache rebuilding
236
+ pub fn getGraphemeWidthAt(rope: *UnifiedRope, mem_registry: *const MemRegistry, row: u32, col: u32, tab_width: u8, width_method: utf8.WidthMethod) u32 {
237
+ const line_width = lineWidthAt(rope, row);
238
+ if (col >= line_width) return 0;
239
+
240
+ const linestart = rope.getMarker(.linestart, row) orelse return 0;
241
+ var seg_idx = linestart.leaf_index + 1;
242
+ var cols_before: u32 = 0;
243
+
244
+ while (seg_idx < rope.count()) : (seg_idx += 1) {
245
+ const seg = rope.get(seg_idx) orelse break;
246
+ if (seg.isBreak() or seg.isLineStart()) break;
247
+ if (seg.asText()) |chunk| {
248
+ const next_cols = cols_before + chunk.width;
249
+ if (col < next_cols) {
250
+ const local_col: u32 = col - cols_before;
251
+ const bytes = chunk.getBytes(mem_registry);
252
+ const is_ascii = (chunk.flags & TextChunk.Flags.ASCII_ONLY) != 0;
253
+ const pos = utf8.findPosByWidth(bytes, local_col, tab_width, is_ascii, false, width_method);
254
+ if (pos.byte_offset >= bytes.len) return 0; // at end of chunk
255
+ const grapheme_start_col = pos.columns_used;
256
+ const width = utf8.getWidthAt(bytes, pos.byte_offset, tab_width, width_method);
257
+
258
+ // Calculate remaining width: if cursor is in the middle of a wide grapheme,
259
+ // return only the remaining columns to reach the end of the grapheme
260
+ const grapheme_end_col = grapheme_start_col + width;
261
+ const remaining_width = grapheme_end_col - local_col;
262
+ return remaining_width;
263
+ }
264
+ cols_before = next_cols;
265
+ }
266
+ }
267
+ return 0;
268
+ }
269
+
270
+ /// Takes mutable rope for lazy marker cache rebuilding
271
+ pub fn getPrevGraphemeWidth(rope: *UnifiedRope, mem_registry: *const MemRegistry, row: u32, col: u32, tab_width: u8, width_method: utf8.WidthMethod) u32 {
272
+ if (col == 0) return 0;
273
+
274
+ const line_width = lineWidthAt(rope, row);
275
+ const clamped_col: u32 = @min(col, line_width);
276
+
277
+ const linestart = rope.getMarker(.linestart, row) orelse return 0;
278
+ var seg_idx = linestart.leaf_index + 1;
279
+ var cols_before: u32 = 0;
280
+ var prev_chunk: ?struct { chunk: TextChunk, cols_before: u32 } = null;
281
+
282
+ while (seg_idx < rope.count()) : (seg_idx += 1) {
283
+ const seg = rope.get(seg_idx) orelse break;
284
+ if (seg.isBreak() or seg.isLineStart()) break;
285
+ if (seg.asText()) |chunk| {
286
+ const next_cols = cols_before + chunk.width;
287
+
288
+ if (clamped_col <= next_cols) {
289
+ if (clamped_col == cols_before and prev_chunk != null) {
290
+ // Exactly at chunk boundary - get last grapheme from previous chunk
291
+ const pc = prev_chunk.?;
292
+ const bytes = pc.chunk.getBytes(mem_registry);
293
+ const prev = utf8.getPrevGraphemeStart(bytes, bytes.len, tab_width, width_method);
294
+ if (prev) |res| {
295
+ return res.width;
296
+ }
297
+ return 0;
298
+ }
299
+
300
+ const bytes = chunk.getBytes(mem_registry);
301
+ const is_ascii = (chunk.flags & TextChunk.Flags.ASCII_ONLY) != 0;
302
+ const local_col: u32 = clamped_col - cols_before;
303
+
304
+ const here = utf8.findPosByWidth(bytes, local_col, tab_width, is_ascii, false, width_method);
305
+
306
+ const grapheme_start_col = here.columns_used;
307
+
308
+ // Check for integer underflow: if grapheme_start_col > local_col, we're in the middle of a grapheme
309
+ // that spans beyond local_col. This can happen with multi-codepoint graphemes.
310
+ if (grapheme_start_col > local_col) {
311
+ // We're in the middle of a wide grapheme cluster - need to look at previous chunk or grapheme
312
+ if (prev_chunk) |pc| {
313
+ const prev_bytes = pc.chunk.getBytes(mem_registry);
314
+ const prev = utf8.getPrevGraphemeStart(prev_bytes, prev_bytes.len, tab_width, width_method);
315
+ if (prev) |res| return res.width;
316
+ }
317
+ return 0;
318
+ }
319
+
320
+ const offset_into_grapheme = local_col - grapheme_start_col;
321
+
322
+ if (offset_into_grapheme > 0) {
323
+ // We need to jump back: offset_into_grapheme + width of previous grapheme
324
+ const prev = utf8.getPrevGraphemeStart(bytes, @intCast(here.byte_offset), tab_width, width_method);
325
+ if (prev) |res| {
326
+ const total_distance = offset_into_grapheme + res.width;
327
+ return total_distance;
328
+ }
329
+ return offset_into_grapheme;
330
+ }
331
+
332
+ const prev = utf8.getPrevGraphemeStart(bytes, @intCast(here.byte_offset), tab_width, width_method);
333
+ if (prev) |res| {
334
+ return res.width;
335
+ }
336
+ return 0;
337
+ }
338
+
339
+ prev_chunk = .{ .chunk = chunk.*, .cols_before = cols_before };
340
+ cols_before = next_cols;
341
+ }
342
+ }
343
+ return 0;
344
+ }
345
+
346
+ pub const CharOffsetColumnInfo = struct {
347
+ col: u32,
348
+ width: u32,
349
+ };
350
+
351
+ /// char_offset is grapheme-count based (not raw codepoint)
352
+ /// grapheme_idx and col_delta carry incremental state across calls
353
+ pub fn charOffsetToColumn(
354
+ char_offset: u32,
355
+ graphemes: []const GraphemeInfo,
356
+ grapheme_idx: *usize,
357
+ col_delta: *i64,
358
+ ) CharOffsetColumnInfo {
359
+ while (grapheme_idx.* < graphemes.len) {
360
+ const info = graphemes[grapheme_idx.*];
361
+ const info_char_offset = @as(i64, info.col_offset) - col_delta.*;
362
+ if (info_char_offset >= @as(i64, char_offset)) break;
363
+ col_delta.* += @as(i64, info.width) - 1;
364
+ grapheme_idx.* += 1;
365
+ }
366
+
367
+ var break_col_i64 = @as(i64, char_offset) + col_delta.*;
368
+ if (break_col_i64 < 0) break_col_i64 = 0;
369
+ const break_col = @as(u32, @intCast(break_col_i64));
370
+
371
+ var width: u32 = 1;
372
+ if (grapheme_idx.* < graphemes.len) {
373
+ const info = graphemes[grapheme_idx.*];
374
+ const info_char_offset = @as(i64, info.col_offset) - col_delta.*;
375
+ if (info_char_offset == @as(i64, char_offset)) {
376
+ width = @as(u32, info.width);
377
+ }
378
+ }
379
+
380
+ return .{ .col = break_col, .width = width };
381
+ }
382
+
383
+ /// Extract text between display-width offsets into a buffer
384
+ /// Automatically snaps to grapheme boundaries:
385
+ /// - start_offset excludes graphemes that start before it
386
+ /// - end_offset includes graphemes that start before it
387
+ /// Returns number of bytes written to out_buffer
388
+ pub fn extractTextBetweenOffsets(
389
+ rope: *const UnifiedRope,
390
+ mem_registry: *const MemRegistry,
391
+ tab_width: u8,
392
+ start_offset: u32,
393
+ end_offset: u32,
394
+ out_buffer: []u8,
395
+ width_method: utf8.WidthMethod,
396
+ ) usize {
397
+ if (start_offset >= end_offset) return 0;
398
+ if (out_buffer.len == 0) return 0;
399
+
400
+ const line_count = rope.root.metrics().custom.linestart_count;
401
+
402
+ var out_index: usize = 0;
403
+ var col_offset: u32 = 0;
404
+
405
+ _ = width_method; // Just ignore for now, will use .unicode as default
406
+
407
+ const Context = struct {
408
+ rope: *const UnifiedRope,
409
+ mem_registry: *const MemRegistry,
410
+ tab_width: u8,
411
+ out_buffer: []u8,
412
+ out_index: *usize,
413
+ col_offset: *u32,
414
+ start: u32,
415
+ end: u32,
416
+ line_count: u32,
417
+ line_had_content: bool = false,
418
+
419
+ fn segment_callback(ctx_ptr: *anyopaque, line_idx: u32, chunk: *const TextChunk, chunk_idx_in_line: u32) void {
420
+ _ = line_idx;
421
+ _ = chunk_idx_in_line;
422
+ const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_ptr)));
423
+
424
+ const chunk_start_offset = ctx.col_offset.*;
425
+ const chunk_end_offset = chunk_start_offset + chunk.width;
426
+
427
+ // Skip chunk if it's entirely outside range
428
+ if (chunk_end_offset <= ctx.start or chunk_start_offset >= ctx.end) {
429
+ ctx.col_offset.* = chunk_end_offset;
430
+ return;
431
+ }
432
+
433
+ ctx.line_had_content = true;
434
+
435
+ const chunk_bytes = chunk.getBytes(ctx.mem_registry);
436
+ const is_ascii_only = (chunk.flags & TextChunk.Flags.ASCII_ONLY) != 0;
437
+
438
+ const local_start_col: u32 = if (ctx.start > chunk_start_offset) ctx.start - chunk_start_offset else 0;
439
+ const local_end_col: u32 = @min(ctx.end - chunk_start_offset, chunk.width);
440
+
441
+ var byte_start: u32 = 0;
442
+ var byte_end: u32 = @intCast(chunk_bytes.len);
443
+
444
+ if (local_start_col > 0) {
445
+ const start_result = utf8.findPosByWidth(chunk_bytes, local_start_col, ctx.tab_width, is_ascii_only, false, .unicode);
446
+ byte_start = start_result.byte_offset;
447
+ }
448
+
449
+ if (local_end_col < chunk.width) {
450
+ const end_result = utf8.findPosByWidth(chunk_bytes, local_end_col, ctx.tab_width, is_ascii_only, true, .unicode);
451
+ byte_end = end_result.byte_offset;
452
+ }
453
+
454
+ if (byte_start < byte_end and byte_start < chunk_bytes.len) {
455
+ const actual_end = @min(byte_end, @as(u32, @intCast(chunk_bytes.len)));
456
+ const selected_bytes = chunk_bytes[byte_start..actual_end];
457
+ const copy_len = @min(selected_bytes.len, ctx.out_buffer.len - ctx.out_index.*);
458
+
459
+ if (copy_len > 0) {
460
+ @memcpy(ctx.out_buffer[ctx.out_index.* .. ctx.out_index.* + copy_len], selected_bytes[0..copy_len]);
461
+ ctx.out_index.* += copy_len;
462
+ }
463
+ }
464
+
465
+ ctx.col_offset.* = chunk_end_offset;
466
+ }
467
+
468
+ fn line_end_callback(ctx_ptr: *anyopaque, line_info: LineInfo) void {
469
+ const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_ptr)));
470
+
471
+ // Add newline if we had content and range extends beyond this line's newline
472
+ if (ctx.line_had_content and line_info.line_idx < ctx.line_count - 1 and ctx.col_offset.* + 1 < ctx.end and ctx.out_index.* < ctx.out_buffer.len) {
473
+ ctx.out_buffer[ctx.out_index.*] = '\n';
474
+ ctx.out_index.* += 1;
475
+ }
476
+
477
+ // Account for newline in display offset
478
+ ctx.col_offset.* += 1;
479
+
480
+ ctx.line_had_content = false;
481
+ }
482
+ };
483
+
484
+ var ctx = Context{
485
+ .rope = rope,
486
+ .mem_registry = mem_registry,
487
+ .tab_width = tab_width,
488
+ .out_buffer = out_buffer,
489
+ .out_index = &out_index,
490
+ .col_offset = &col_offset,
491
+ .start = start_offset,
492
+ .end = end_offset,
493
+ .line_count = line_count,
494
+ };
495
+
496
+ walkLinesAndSegments(rope, &ctx, Context.segment_callback, Context.line_end_callback);
497
+
498
+ return out_index;
499
+ }