@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
package/src/zig.ts ADDED
@@ -0,0 +1,3884 @@
1
+ import { dlopen, toArrayBuffer, JSCallback, ptr, type Pointer } from "bun:ffi"
2
+ import { existsSync, writeFileSync } from "fs"
3
+ import { EventEmitter } from "events"
4
+ import {
5
+ type CursorStyle,
6
+ type CursorStyleOptions,
7
+ type TargetChannel,
8
+ type DebugOverlayCorner,
9
+ type WidthMethod,
10
+ type Highlight,
11
+ type LineInfo,
12
+ type MousePointerStyle,
13
+ } from "./types.js"
14
+ export type { LineInfo, AllocatorStats, BuildOptions }
15
+
16
+ import { RGBA } from "./lib/RGBA.js"
17
+ import { OptimizedBuffer } from "./buffer.js"
18
+ import { TextBuffer } from "./text-buffer.js"
19
+ import { env, registerEnvVar } from "./lib/env.js"
20
+ import {
21
+ StyledChunkStruct,
22
+ HighlightStruct,
23
+ LogicalCursorStruct,
24
+ VisualCursorStruct,
25
+ TerminalCapabilitiesStruct,
26
+ EncodedCharStruct,
27
+ LineInfoStruct,
28
+ MeasureResultStruct,
29
+ CursorStateStruct,
30
+ CursorStyleOptionsStruct,
31
+ GridDrawOptionsStruct,
32
+ NativeSpanFeedOptionsStruct,
33
+ NativeSpanFeedStatsStruct,
34
+ ReserveInfoStruct,
35
+ BuildOptionsStruct,
36
+ AllocatorStatsStruct,
37
+ } from "./zig-structs.js"
38
+ import type {
39
+ NativeSpanFeedOptions,
40
+ NativeSpanFeedStats,
41
+ ReserveInfo,
42
+ BuildOptions,
43
+ AllocatorStats,
44
+ } from "./zig-structs.js"
45
+ import { isBunfsPath } from "./lib/bunfs.js"
46
+
47
+ const module = await import(`@fairyhunter13/opentui-core-${process.platform}-${process.arch}/index.ts`)
48
+ let targetLibPath = module.default
49
+
50
+ if (isBunfsPath(targetLibPath)) {
51
+ targetLibPath = targetLibPath.replace("../", "")
52
+ }
53
+
54
+ if (!existsSync(targetLibPath)) {
55
+ throw new Error(`opentui is not supported on the current platform: ${process.platform}-${process.arch}`)
56
+ }
57
+
58
+ registerEnvVar({
59
+ name: "OTUI_DEBUG_FFI",
60
+ description: "Enable debug logging for the FFI bindings.",
61
+ type: "boolean",
62
+ default: false,
63
+ })
64
+
65
+ registerEnvVar({
66
+ name: "OTUI_TRACE_FFI",
67
+ description: "Enable tracing for the FFI bindings.",
68
+ type: "boolean",
69
+ default: false,
70
+ })
71
+
72
+ // Env vars used in terminal.zig
73
+ registerEnvVar({
74
+ name: "OPENTUI_FORCE_WCWIDTH",
75
+ description: "Use wcwidth for character width calculations",
76
+ type: "boolean",
77
+ default: false,
78
+ })
79
+ registerEnvVar({
80
+ name: "OPENTUI_FORCE_UNICODE",
81
+ description: "Force Mode 2026 Unicode support in terminal capabilities",
82
+ type: "boolean",
83
+ default: false,
84
+ })
85
+ registerEnvVar({
86
+ name: "OPENTUI_GRAPHICS",
87
+ description: "Enable Kitty graphics protocol detection",
88
+ type: "boolean",
89
+ default: true,
90
+ })
91
+ registerEnvVar({
92
+ name: "OPENTUI_FORCE_NOZWJ",
93
+ description: "Use no_zwj width method (Unicode without ZWJ joining)",
94
+ type: "boolean",
95
+ default: false,
96
+ })
97
+
98
+ // Cursor & mouse pointer style mappings (avoid recreation on each call)
99
+ const CURSOR_STYLE_TO_ID = { block: 0, line: 1, underline: 2, default: 3 } as const
100
+ const CURSOR_ID_TO_STYLE = ["block", "line", "underline", "default"] as const
101
+ const MOUSE_STYLE_TO_ID = { default: 0, pointer: 1, text: 2, crosshair: 3, move: 4, "not-allowed": 5 } as const
102
+
103
+ // Global singleton state for FFI tracing to prevent duplicate exit handlers
104
+ let globalTraceSymbols: Record<string, number[]> | null = null
105
+ let globalFFILogPath: string | null = null
106
+ let exitHandlerRegistered = false
107
+
108
+ function toPointer(value: number | bigint): Pointer {
109
+ if (typeof value === "bigint") {
110
+ if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
111
+ throw new Error("Pointer exceeds safe integer range")
112
+ }
113
+ return Number(value) as Pointer
114
+ }
115
+ return value as Pointer
116
+ }
117
+
118
+ function toNumber(value: number | bigint): number {
119
+ return typeof value === "bigint" ? Number(value) : value
120
+ }
121
+
122
+ function getOpenTUILib(libPath?: string) {
123
+ const resolvedLibPath = libPath || targetLibPath
124
+
125
+ const rawSymbols = dlopen(resolvedLibPath, {
126
+ // Logging
127
+ setLogCallback: {
128
+ args: ["ptr"],
129
+ returns: "void",
130
+ },
131
+ // Event bus
132
+ setEventCallback: {
133
+ args: ["ptr"],
134
+ returns: "void",
135
+ },
136
+ // Renderer management
137
+ createRenderer: {
138
+ args: ["u32", "u32", "bool", "bool"],
139
+ returns: "ptr",
140
+ },
141
+ setTerminalEnvVar: {
142
+ args: ["ptr", "ptr", "usize", "ptr", "usize"],
143
+ returns: "bool",
144
+ },
145
+ destroyRenderer: {
146
+ args: ["ptr"],
147
+ returns: "void",
148
+ },
149
+ setUseThread: {
150
+ args: ["ptr", "bool"],
151
+ returns: "void",
152
+ },
153
+ setBackgroundColor: {
154
+ args: ["ptr", "ptr"],
155
+ returns: "void",
156
+ },
157
+ setRenderOffset: {
158
+ args: ["ptr", "u32"],
159
+ returns: "void",
160
+ },
161
+ updateStats: {
162
+ args: ["ptr", "f64", "u32", "f64"],
163
+ returns: "void",
164
+ },
165
+ updateMemoryStats: {
166
+ args: ["ptr", "u32", "u32", "u32"],
167
+ returns: "void",
168
+ },
169
+ render: {
170
+ args: ["ptr", "bool"],
171
+ returns: "void",
172
+ },
173
+ getNextBuffer: {
174
+ args: ["ptr"],
175
+ returns: "ptr",
176
+ },
177
+ getCurrentBuffer: {
178
+ args: ["ptr"],
179
+ returns: "ptr",
180
+ },
181
+
182
+ queryPixelResolution: {
183
+ args: ["ptr"],
184
+ returns: "void",
185
+ },
186
+
187
+ createOptimizedBuffer: {
188
+ args: ["u32", "u32", "bool", "u8", "ptr", "usize"],
189
+ returns: "ptr",
190
+ },
191
+ destroyOptimizedBuffer: {
192
+ args: ["ptr"],
193
+ returns: "void",
194
+ },
195
+
196
+ drawFrameBuffer: {
197
+ args: ["ptr", "i32", "i32", "ptr", "u32", "u32", "u32", "u32"],
198
+ returns: "void",
199
+ },
200
+ getBufferWidth: {
201
+ args: ["ptr"],
202
+ returns: "u32",
203
+ },
204
+ getBufferHeight: {
205
+ args: ["ptr"],
206
+ returns: "u32",
207
+ },
208
+ bufferClear: {
209
+ args: ["ptr", "ptr"],
210
+ returns: "void",
211
+ },
212
+ bufferGetCharPtr: {
213
+ args: ["ptr"],
214
+ returns: "ptr",
215
+ },
216
+ bufferGetFgPtr: {
217
+ args: ["ptr"],
218
+ returns: "ptr",
219
+ },
220
+ bufferGetBgPtr: {
221
+ args: ["ptr"],
222
+ returns: "ptr",
223
+ },
224
+ bufferGetAttributesPtr: {
225
+ args: ["ptr"],
226
+ returns: "ptr",
227
+ },
228
+ bufferGetRespectAlpha: {
229
+ args: ["ptr"],
230
+ returns: "bool",
231
+ },
232
+ bufferSetRespectAlpha: {
233
+ args: ["ptr", "bool"],
234
+ returns: "void",
235
+ },
236
+ bufferGetId: {
237
+ args: ["ptr", "ptr", "usize"],
238
+ returns: "usize",
239
+ },
240
+ bufferGetRealCharSize: {
241
+ args: ["ptr"],
242
+ returns: "u32",
243
+ },
244
+ bufferWriteResolvedChars: {
245
+ args: ["ptr", "ptr", "usize", "bool"],
246
+ returns: "u32",
247
+ },
248
+
249
+ bufferDrawText: {
250
+ args: ["ptr", "ptr", "u32", "u32", "u32", "ptr", "ptr", "u32"],
251
+ returns: "void",
252
+ },
253
+ bufferSetCellWithAlphaBlending: {
254
+ args: ["ptr", "u32", "u32", "u32", "ptr", "ptr", "u32"],
255
+ returns: "void",
256
+ },
257
+ bufferSetCell: {
258
+ args: ["ptr", "u32", "u32", "u32", "ptr", "ptr", "u32"],
259
+ returns: "void",
260
+ },
261
+ bufferFillRect: {
262
+ args: ["ptr", "u32", "u32", "u32", "u32", "ptr"],
263
+ returns: "void",
264
+ },
265
+ bufferColorMatrix: {
266
+ args: ["ptr", "ptr", "ptr", "usize", "f32", "u8"],
267
+ returns: "void",
268
+ },
269
+ bufferColorMatrixUniform: {
270
+ args: ["ptr", "ptr", "f32", "u8"],
271
+ returns: "void",
272
+ },
273
+ bufferResize: {
274
+ args: ["ptr", "u32", "u32"],
275
+ returns: "void",
276
+ },
277
+
278
+ // Link API
279
+ linkAlloc: {
280
+ args: ["ptr", "u32"],
281
+ returns: "u32",
282
+ },
283
+ linkGetUrl: {
284
+ args: ["u32", "ptr", "u32"],
285
+ returns: "u32",
286
+ },
287
+ attributesWithLink: {
288
+ args: ["u32", "u32"],
289
+ returns: "u32",
290
+ },
291
+ attributesGetLinkId: {
292
+ args: ["u32"],
293
+ returns: "u32",
294
+ },
295
+
296
+ resizeRenderer: {
297
+ args: ["ptr", "u32", "u32"],
298
+ returns: "void",
299
+ },
300
+
301
+ // Cursor functions (now renderer-scoped)
302
+ setCursorPosition: {
303
+ args: ["ptr", "i32", "i32", "bool"],
304
+ returns: "void",
305
+ },
306
+ setCursorColor: {
307
+ args: ["ptr", "ptr"],
308
+ returns: "void",
309
+ },
310
+ getCursorState: {
311
+ args: ["ptr", "ptr"],
312
+ returns: "void",
313
+ },
314
+
315
+ // Cursor and mouse pointer style (combined)
316
+ setCursorStyleOptions: {
317
+ args: ["ptr", "ptr"],
318
+ returns: "void",
319
+ },
320
+
321
+ // Debug overlay
322
+ setDebugOverlay: {
323
+ args: ["ptr", "bool", "u8"],
324
+ returns: "void",
325
+ },
326
+
327
+ // Terminal control
328
+ clearTerminal: {
329
+ args: ["ptr"],
330
+ returns: "void",
331
+ },
332
+ setTerminalTitle: {
333
+ args: ["ptr", "ptr", "usize"],
334
+ returns: "void",
335
+ },
336
+ copyToClipboardOSC52: {
337
+ args: ["ptr", "u8", "ptr", "usize"],
338
+ returns: "bool",
339
+ },
340
+ clearClipboardOSC52: {
341
+ args: ["ptr", "u8"],
342
+ returns: "bool",
343
+ },
344
+
345
+ bufferDrawSuperSampleBuffer: {
346
+ args: ["ptr", "u32", "u32", "ptr", "usize", "u8", "u32"],
347
+ returns: "void",
348
+ },
349
+ bufferDrawPackedBuffer: {
350
+ args: ["ptr", "ptr", "usize", "u32", "u32", "u32", "u32"],
351
+ returns: "void",
352
+ },
353
+ bufferDrawGrayscaleBuffer: {
354
+ args: ["ptr", "i32", "i32", "ptr", "u32", "u32", "ptr", "ptr"],
355
+ returns: "void",
356
+ },
357
+ bufferDrawGrayscaleBufferSupersampled: {
358
+ args: ["ptr", "i32", "i32", "ptr", "u32", "u32", "ptr", "ptr"],
359
+ returns: "void",
360
+ },
361
+ bufferDrawGrid: {
362
+ args: ["ptr", "ptr", "ptr", "ptr", "ptr", "u32", "ptr", "u32", "ptr"],
363
+ returns: "void",
364
+ },
365
+ bufferDrawBox: {
366
+ args: ["ptr", "i32", "i32", "u32", "u32", "ptr", "u32", "ptr", "ptr", "ptr", "u32", "ptr", "u32"],
367
+ returns: "void",
368
+ },
369
+ bufferPushScissorRect: {
370
+ args: ["ptr", "i32", "i32", "u32", "u32"],
371
+ returns: "void",
372
+ },
373
+ bufferPopScissorRect: {
374
+ args: ["ptr"],
375
+ returns: "void",
376
+ },
377
+ bufferClearScissorRects: {
378
+ args: ["ptr"],
379
+ returns: "void",
380
+ },
381
+ bufferPushOpacity: {
382
+ args: ["ptr", "f32"],
383
+ returns: "void",
384
+ },
385
+ bufferPopOpacity: {
386
+ args: ["ptr"],
387
+ returns: "void",
388
+ },
389
+ bufferGetCurrentOpacity: {
390
+ args: ["ptr"],
391
+ returns: "f32",
392
+ },
393
+ bufferClearOpacity: {
394
+ args: ["ptr"],
395
+ returns: "void",
396
+ },
397
+
398
+ addToHitGrid: {
399
+ args: ["ptr", "i32", "i32", "u32", "u32", "u32"],
400
+ returns: "void",
401
+ },
402
+ clearCurrentHitGrid: {
403
+ args: ["ptr"],
404
+ returns: "void",
405
+ },
406
+ hitGridPushScissorRect: {
407
+ args: ["ptr", "i32", "i32", "u32", "u32"],
408
+ returns: "void",
409
+ },
410
+ hitGridPopScissorRect: {
411
+ args: ["ptr"],
412
+ returns: "void",
413
+ },
414
+ hitGridClearScissorRects: {
415
+ args: ["ptr"],
416
+ returns: "void",
417
+ },
418
+ addToCurrentHitGridClipped: {
419
+ args: ["ptr", "i32", "i32", "u32", "u32", "u32"],
420
+ returns: "void",
421
+ },
422
+ checkHit: {
423
+ args: ["ptr", "u32", "u32"],
424
+ returns: "u32",
425
+ },
426
+ getHitGridDirty: {
427
+ args: ["ptr"],
428
+ returns: "bool",
429
+ },
430
+ dumpHitGrid: {
431
+ args: ["ptr"],
432
+ returns: "void",
433
+ },
434
+ dumpBuffers: {
435
+ args: ["ptr", "i64"],
436
+ returns: "void",
437
+ },
438
+ dumpStdoutBuffer: {
439
+ args: ["ptr", "i64"],
440
+ returns: "void",
441
+ },
442
+ restoreTerminalModes: {
443
+ args: ["ptr"],
444
+ returns: "void",
445
+ },
446
+ enableMouse: {
447
+ args: ["ptr", "bool"],
448
+ returns: "void",
449
+ },
450
+ disableMouse: {
451
+ args: ["ptr"],
452
+ returns: "void",
453
+ },
454
+ enableKittyKeyboard: {
455
+ args: ["ptr", "u8"],
456
+ returns: "void",
457
+ },
458
+ disableKittyKeyboard: {
459
+ args: ["ptr"],
460
+ returns: "void",
461
+ },
462
+ setKittyKeyboardFlags: {
463
+ args: ["ptr", "u8"],
464
+ returns: "void",
465
+ },
466
+ getKittyKeyboardFlags: {
467
+ args: ["ptr"],
468
+ returns: "u8",
469
+ },
470
+ setupTerminal: {
471
+ args: ["ptr", "bool"],
472
+ returns: "void",
473
+ },
474
+ suspendRenderer: {
475
+ args: ["ptr"],
476
+ returns: "void",
477
+ },
478
+ resumeRenderer: {
479
+ args: ["ptr"],
480
+ returns: "void",
481
+ },
482
+ writeOut: {
483
+ args: ["ptr", "ptr", "u64"],
484
+ returns: "void",
485
+ },
486
+
487
+ // TextBuffer functions
488
+ createTextBuffer: {
489
+ args: ["u8"],
490
+ returns: "ptr",
491
+ },
492
+ destroyTextBuffer: {
493
+ args: ["ptr"],
494
+ returns: "void",
495
+ },
496
+ textBufferGetLength: {
497
+ args: ["ptr"],
498
+ returns: "u32",
499
+ },
500
+ textBufferGetByteSize: {
501
+ args: ["ptr"],
502
+ returns: "u32",
503
+ },
504
+
505
+ textBufferReset: {
506
+ args: ["ptr"],
507
+ returns: "void",
508
+ },
509
+ textBufferClear: {
510
+ args: ["ptr"],
511
+ returns: "void",
512
+ },
513
+ textBufferSetDefaultFg: {
514
+ args: ["ptr", "ptr"],
515
+ returns: "void",
516
+ },
517
+ textBufferSetDefaultBg: {
518
+ args: ["ptr", "ptr"],
519
+ returns: "void",
520
+ },
521
+ textBufferSetDefaultAttributes: {
522
+ args: ["ptr", "ptr"],
523
+ returns: "void",
524
+ },
525
+ textBufferResetDefaults: {
526
+ args: ["ptr"],
527
+ returns: "void",
528
+ },
529
+ textBufferGetTabWidth: {
530
+ args: ["ptr"],
531
+ returns: "u8",
532
+ },
533
+ textBufferSetTabWidth: {
534
+ args: ["ptr", "u8"],
535
+ returns: "void",
536
+ },
537
+ textBufferRegisterMemBuffer: {
538
+ args: ["ptr", "ptr", "usize", "bool"],
539
+ returns: "u16",
540
+ },
541
+ textBufferReplaceMemBuffer: {
542
+ args: ["ptr", "u8", "ptr", "usize", "bool"],
543
+ returns: "bool",
544
+ },
545
+ textBufferClearMemRegistry: {
546
+ args: ["ptr"],
547
+ returns: "void",
548
+ },
549
+ textBufferSetTextFromMem: {
550
+ args: ["ptr", "u8"],
551
+ returns: "void",
552
+ },
553
+ textBufferAppend: {
554
+ args: ["ptr", "ptr", "usize"],
555
+ returns: "void",
556
+ },
557
+ textBufferAppendFromMemId: {
558
+ args: ["ptr", "u8"],
559
+ returns: "void",
560
+ },
561
+ textBufferLoadFile: {
562
+ args: ["ptr", "ptr", "usize"],
563
+ returns: "bool",
564
+ },
565
+ textBufferSetStyledText: {
566
+ args: ["ptr", "ptr", "usize"],
567
+ returns: "void",
568
+ },
569
+ textBufferGetLineCount: {
570
+ args: ["ptr"],
571
+ returns: "u32",
572
+ },
573
+ textBufferGetPlainText: {
574
+ args: ["ptr", "ptr", "usize"],
575
+ returns: "usize",
576
+ },
577
+ textBufferAddHighlightByCharRange: {
578
+ args: ["ptr", "ptr"],
579
+ returns: "void",
580
+ },
581
+ textBufferAddHighlight: {
582
+ args: ["ptr", "u32", "ptr"],
583
+ returns: "void",
584
+ },
585
+ textBufferRemoveHighlightsByRef: {
586
+ args: ["ptr", "u16"],
587
+ returns: "void",
588
+ },
589
+ textBufferClearLineHighlights: {
590
+ args: ["ptr", "u32"],
591
+ returns: "void",
592
+ },
593
+ textBufferClearAllHighlights: {
594
+ args: ["ptr"],
595
+ returns: "void",
596
+ },
597
+ textBufferSetSyntaxStyle: {
598
+ args: ["ptr", "ptr"],
599
+ returns: "void",
600
+ },
601
+ textBufferGetLineHighlightsPtr: {
602
+ args: ["ptr", "u32", "ptr"],
603
+ returns: "ptr",
604
+ },
605
+ textBufferFreeLineHighlights: {
606
+ args: ["ptr", "usize"],
607
+ returns: "void",
608
+ },
609
+ textBufferGetHighlightCount: {
610
+ args: ["ptr"],
611
+ returns: "u32",
612
+ },
613
+ textBufferGetTextRange: {
614
+ args: ["ptr", "u32", "u32", "ptr", "usize"],
615
+ returns: "usize",
616
+ },
617
+ textBufferGetTextRangeByCoords: {
618
+ args: ["ptr", "u32", "u32", "u32", "u32", "ptr", "usize"],
619
+ returns: "usize",
620
+ },
621
+
622
+ // TextBufferView functions
623
+ createTextBufferView: {
624
+ args: ["ptr"],
625
+ returns: "ptr",
626
+ },
627
+ destroyTextBufferView: {
628
+ args: ["ptr"],
629
+ returns: "void",
630
+ },
631
+ textBufferViewSetSelection: {
632
+ args: ["ptr", "u32", "u32", "ptr", "ptr"],
633
+ returns: "void",
634
+ },
635
+ textBufferViewResetSelection: {
636
+ args: ["ptr"],
637
+ returns: "void",
638
+ },
639
+ textBufferViewGetSelectionInfo: {
640
+ args: ["ptr"],
641
+ returns: "u64",
642
+ },
643
+ textBufferViewSetLocalSelection: {
644
+ args: ["ptr", "i32", "i32", "i32", "i32", "ptr", "ptr"],
645
+ returns: "bool",
646
+ },
647
+ textBufferViewUpdateSelection: {
648
+ args: ["ptr", "u32", "ptr", "ptr"],
649
+ returns: "void",
650
+ },
651
+ textBufferViewUpdateLocalSelection: {
652
+ args: ["ptr", "i32", "i32", "i32", "i32", "ptr", "ptr"],
653
+ returns: "bool",
654
+ },
655
+ textBufferViewResetLocalSelection: {
656
+ args: ["ptr"],
657
+ returns: "void",
658
+ },
659
+ textBufferViewSetWrapWidth: {
660
+ args: ["ptr", "u32"],
661
+ returns: "void",
662
+ },
663
+ textBufferViewSetWrapMode: {
664
+ args: ["ptr", "u8"],
665
+ returns: "void",
666
+ },
667
+ textBufferViewSetViewportSize: {
668
+ args: ["ptr", "u32", "u32"],
669
+ returns: "void",
670
+ },
671
+ textBufferViewSetViewport: {
672
+ args: ["ptr", "u32", "u32", "u32", "u32"],
673
+ returns: "void",
674
+ },
675
+ textBufferViewGetVirtualLineCount: {
676
+ args: ["ptr"],
677
+ returns: "u32",
678
+ },
679
+ textBufferViewGetLineInfoDirect: {
680
+ args: ["ptr", "ptr"],
681
+ returns: "void",
682
+ },
683
+ textBufferViewGetLogicalLineInfoDirect: {
684
+ args: ["ptr", "ptr"],
685
+ returns: "void",
686
+ },
687
+ textBufferViewGetSelectedText: {
688
+ args: ["ptr", "ptr", "usize"],
689
+ returns: "usize",
690
+ },
691
+ textBufferViewGetPlainText: {
692
+ args: ["ptr", "ptr", "usize"],
693
+ returns: "usize",
694
+ },
695
+ textBufferViewSetTabIndicator: {
696
+ args: ["ptr", "u32"],
697
+ returns: "void",
698
+ },
699
+ textBufferViewSetTabIndicatorColor: {
700
+ args: ["ptr", "ptr"],
701
+ returns: "void",
702
+ },
703
+ textBufferViewSetTruncate: {
704
+ args: ["ptr", "bool"],
705
+ returns: "void",
706
+ },
707
+ textBufferViewMeasureForDimensions: {
708
+ args: ["ptr", "u32", "u32", "ptr"],
709
+ returns: "bool",
710
+ },
711
+ bufferDrawTextBufferView: {
712
+ args: ["ptr", "ptr", "i32", "i32"],
713
+ returns: "void",
714
+ },
715
+ bufferDrawEditorView: {
716
+ args: ["ptr", "ptr", "i32", "i32"],
717
+ returns: "void",
718
+ },
719
+
720
+ // EditorView functions
721
+ createEditorView: {
722
+ args: ["ptr", "u32", "u32"],
723
+ returns: "ptr",
724
+ },
725
+ destroyEditorView: {
726
+ args: ["ptr"],
727
+ returns: "void",
728
+ },
729
+ editorViewSetViewportSize: {
730
+ args: ["ptr", "u32", "u32"],
731
+ returns: "void",
732
+ },
733
+ editorViewSetViewport: {
734
+ args: ["ptr", "u32", "u32", "u32", "u32", "bool"],
735
+ returns: "void",
736
+ },
737
+ editorViewGetViewport: {
738
+ args: ["ptr", "ptr", "ptr", "ptr", "ptr"],
739
+ returns: "void",
740
+ },
741
+ editorViewSetScrollMargin: {
742
+ args: ["ptr", "f32"],
743
+ returns: "void",
744
+ },
745
+ editorViewSetWrapMode: {
746
+ args: ["ptr", "u8"],
747
+ returns: "void",
748
+ },
749
+ editorViewGetVirtualLineCount: {
750
+ args: ["ptr"],
751
+ returns: "u32",
752
+ },
753
+ editorViewGetTotalVirtualLineCount: {
754
+ args: ["ptr"],
755
+ returns: "u32",
756
+ },
757
+ editorViewGetTextBufferView: {
758
+ args: ["ptr"],
759
+ returns: "ptr",
760
+ },
761
+ editorViewGetLineInfoDirect: {
762
+ args: ["ptr", "ptr"],
763
+ returns: "void",
764
+ },
765
+ editorViewGetLogicalLineInfoDirect: {
766
+ args: ["ptr", "ptr"],
767
+ returns: "void",
768
+ },
769
+
770
+ // EditBuffer functions
771
+ createEditBuffer: {
772
+ args: ["u8"],
773
+ returns: "ptr",
774
+ },
775
+ destroyEditBuffer: {
776
+ args: ["ptr"],
777
+ returns: "void",
778
+ },
779
+ editBufferSetText: {
780
+ args: ["ptr", "ptr", "usize"],
781
+ returns: "void",
782
+ },
783
+ editBufferSetTextFromMem: {
784
+ args: ["ptr", "u8"],
785
+ returns: "void",
786
+ },
787
+ editBufferReplaceText: {
788
+ args: ["ptr", "ptr", "usize"],
789
+ returns: "void",
790
+ },
791
+ editBufferReplaceTextFromMem: {
792
+ args: ["ptr", "u8"],
793
+ returns: "void",
794
+ },
795
+ editBufferGetText: {
796
+ args: ["ptr", "ptr", "usize"],
797
+ returns: "usize",
798
+ },
799
+ editBufferInsertChar: {
800
+ args: ["ptr", "ptr", "usize"],
801
+ returns: "void",
802
+ },
803
+ editBufferInsertText: {
804
+ args: ["ptr", "ptr", "usize"],
805
+ returns: "void",
806
+ },
807
+ editBufferDeleteChar: {
808
+ args: ["ptr"],
809
+ returns: "void",
810
+ },
811
+ editBufferDeleteCharBackward: {
812
+ args: ["ptr"],
813
+ returns: "void",
814
+ },
815
+ editBufferDeleteRange: {
816
+ args: ["ptr", "u32", "u32", "u32", "u32"],
817
+ returns: "void",
818
+ },
819
+ editBufferNewLine: {
820
+ args: ["ptr"],
821
+ returns: "void",
822
+ },
823
+ editBufferDeleteLine: {
824
+ args: ["ptr"],
825
+ returns: "void",
826
+ },
827
+ editBufferMoveCursorLeft: {
828
+ args: ["ptr"],
829
+ returns: "void",
830
+ },
831
+ editBufferMoveCursorRight: {
832
+ args: ["ptr"],
833
+ returns: "void",
834
+ },
835
+ editBufferMoveCursorUp: {
836
+ args: ["ptr"],
837
+ returns: "void",
838
+ },
839
+ editBufferMoveCursorDown: {
840
+ args: ["ptr"],
841
+ returns: "void",
842
+ },
843
+ editBufferGotoLine: {
844
+ args: ["ptr", "u32"],
845
+ returns: "void",
846
+ },
847
+ editBufferSetCursor: {
848
+ args: ["ptr", "u32", "u32"],
849
+ returns: "void",
850
+ },
851
+ editBufferSetCursorToLineCol: {
852
+ args: ["ptr", "u32", "u32"],
853
+ returns: "void",
854
+ },
855
+ editBufferSetCursorByOffset: {
856
+ args: ["ptr", "u32"],
857
+ returns: "void",
858
+ },
859
+ editBufferGetCursorPosition: {
860
+ args: ["ptr", "ptr"],
861
+ returns: "void",
862
+ },
863
+ editBufferGetId: {
864
+ args: ["ptr"],
865
+ returns: "u16",
866
+ },
867
+ editBufferGetTextBuffer: {
868
+ args: ["ptr"],
869
+ returns: "ptr",
870
+ },
871
+ editBufferDebugLogRope: {
872
+ args: ["ptr"],
873
+ returns: "void",
874
+ },
875
+ editBufferUndo: {
876
+ args: ["ptr", "ptr", "usize"],
877
+ returns: "usize",
878
+ },
879
+ editBufferRedo: {
880
+ args: ["ptr", "ptr", "usize"],
881
+ returns: "usize",
882
+ },
883
+ editBufferCanUndo: {
884
+ args: ["ptr"],
885
+ returns: "bool",
886
+ },
887
+ editBufferCanRedo: {
888
+ args: ["ptr"],
889
+ returns: "bool",
890
+ },
891
+ editBufferClearHistory: {
892
+ args: ["ptr"],
893
+ returns: "void",
894
+ },
895
+ editBufferClear: {
896
+ args: ["ptr"],
897
+ returns: "void",
898
+ },
899
+ editBufferGetNextWordBoundary: {
900
+ args: ["ptr", "ptr"],
901
+ returns: "void",
902
+ },
903
+ editBufferGetPrevWordBoundary: {
904
+ args: ["ptr", "ptr"],
905
+ returns: "void",
906
+ },
907
+ editBufferGetEOL: {
908
+ args: ["ptr", "ptr"],
909
+ returns: "void",
910
+ },
911
+ editBufferOffsetToPosition: {
912
+ args: ["ptr", "u32", "ptr"],
913
+ returns: "bool",
914
+ },
915
+ editBufferPositionToOffset: {
916
+ args: ["ptr", "u32", "u32"],
917
+ returns: "u32",
918
+ },
919
+ editBufferGetLineStartOffset: {
920
+ args: ["ptr", "u32"],
921
+ returns: "u32",
922
+ },
923
+ editBufferGetTextRange: {
924
+ args: ["ptr", "u32", "u32", "ptr", "usize"],
925
+ returns: "usize",
926
+ },
927
+ editBufferGetTextRangeByCoords: {
928
+ args: ["ptr", "u32", "u32", "u32", "u32", "ptr", "usize"],
929
+ returns: "usize",
930
+ },
931
+
932
+ // EditorView selection and editing methods
933
+ editorViewSetSelection: {
934
+ args: ["ptr", "u32", "u32", "ptr", "ptr"],
935
+ returns: "void",
936
+ },
937
+ editorViewResetSelection: {
938
+ args: ["ptr"],
939
+ returns: "void",
940
+ },
941
+ editorViewGetSelection: {
942
+ args: ["ptr"],
943
+ returns: "u64",
944
+ },
945
+ editorViewSetLocalSelection: {
946
+ args: ["ptr", "i32", "i32", "i32", "i32", "ptr", "ptr", "bool", "bool"],
947
+ returns: "bool",
948
+ },
949
+ editorViewUpdateSelection: {
950
+ args: ["ptr", "u32", "ptr", "ptr"],
951
+ returns: "void",
952
+ },
953
+ editorViewUpdateLocalSelection: {
954
+ args: ["ptr", "i32", "i32", "i32", "i32", "ptr", "ptr", "bool", "bool"],
955
+ returns: "bool",
956
+ },
957
+ editorViewResetLocalSelection: {
958
+ args: ["ptr"],
959
+ returns: "void",
960
+ },
961
+ editorViewGetSelectedTextBytes: {
962
+ args: ["ptr", "ptr", "usize"],
963
+ returns: "usize",
964
+ },
965
+ editorViewGetCursor: {
966
+ args: ["ptr", "ptr", "ptr"],
967
+ returns: "void",
968
+ },
969
+ editorViewGetText: {
970
+ args: ["ptr", "ptr", "usize"],
971
+ returns: "usize",
972
+ },
973
+
974
+ // EditorView VisualCursor methods
975
+ editorViewGetVisualCursor: {
976
+ args: ["ptr", "ptr"],
977
+ returns: "void",
978
+ },
979
+
980
+ editorViewMoveUpVisual: {
981
+ args: ["ptr"],
982
+ returns: "void",
983
+ },
984
+ editorViewMoveDownVisual: {
985
+ args: ["ptr"],
986
+ returns: "void",
987
+ },
988
+ editorViewDeleteSelectedText: {
989
+ args: ["ptr"],
990
+ returns: "void",
991
+ },
992
+ editorViewSetCursorByOffset: {
993
+ args: ["ptr", "u32"],
994
+ returns: "void",
995
+ },
996
+ editorViewGetNextWordBoundary: {
997
+ args: ["ptr", "ptr"],
998
+ returns: "void",
999
+ },
1000
+ editorViewGetPrevWordBoundary: {
1001
+ args: ["ptr", "ptr"],
1002
+ returns: "void",
1003
+ },
1004
+ editorViewGetEOL: {
1005
+ args: ["ptr", "ptr"],
1006
+ returns: "void",
1007
+ },
1008
+ editorViewGetVisualSOL: {
1009
+ args: ["ptr", "ptr"],
1010
+ returns: "void",
1011
+ },
1012
+ editorViewGetVisualEOL: {
1013
+ args: ["ptr", "ptr"],
1014
+ returns: "void",
1015
+ },
1016
+ editorViewSetPlaceholderStyledText: {
1017
+ args: ["ptr", "ptr", "usize"],
1018
+ returns: "void",
1019
+ },
1020
+ editorViewSetTabIndicator: {
1021
+ args: ["ptr", "u32"],
1022
+ returns: "void",
1023
+ },
1024
+ editorViewSetTabIndicatorColor: {
1025
+ args: ["ptr", "ptr"],
1026
+ returns: "void",
1027
+ },
1028
+
1029
+ getArenaAllocatedBytes: {
1030
+ args: [],
1031
+ returns: "usize",
1032
+ },
1033
+ getBuildOptions: {
1034
+ args: ["ptr"],
1035
+ returns: "void",
1036
+ },
1037
+ getAllocatorStats: {
1038
+ args: ["ptr"],
1039
+ returns: "void",
1040
+ },
1041
+
1042
+ // SyntaxStyle functions
1043
+ createSyntaxStyle: {
1044
+ args: [],
1045
+ returns: "ptr",
1046
+ },
1047
+ destroySyntaxStyle: {
1048
+ args: ["ptr"],
1049
+ returns: "void",
1050
+ },
1051
+ syntaxStyleRegister: {
1052
+ args: ["ptr", "ptr", "usize", "ptr", "ptr", "u8"],
1053
+ returns: "u32",
1054
+ },
1055
+ syntaxStyleResolveByName: {
1056
+ args: ["ptr", "ptr", "usize"],
1057
+ returns: "u32",
1058
+ },
1059
+ syntaxStyleGetStyleCount: {
1060
+ args: ["ptr"],
1061
+ returns: "usize",
1062
+ },
1063
+
1064
+ // Terminal capability functions
1065
+ getTerminalCapabilities: {
1066
+ args: ["ptr", "ptr"],
1067
+ returns: "void",
1068
+ },
1069
+ processCapabilityResponse: {
1070
+ args: ["ptr", "ptr", "usize"],
1071
+ returns: "void",
1072
+ },
1073
+
1074
+ // Unicode encoding API
1075
+ encodeUnicode: {
1076
+ args: ["ptr", "usize", "ptr", "ptr", "u8"],
1077
+ returns: "bool",
1078
+ },
1079
+ freeUnicode: {
1080
+ args: ["ptr", "usize"],
1081
+ returns: "void",
1082
+ },
1083
+ bufferDrawChar: {
1084
+ args: ["ptr", "u32", "u32", "u32", "ptr", "ptr", "u32"],
1085
+ returns: "void",
1086
+ },
1087
+
1088
+ // NativeSpanFeed
1089
+ createNativeSpanFeed: {
1090
+ args: ["ptr"],
1091
+ returns: "ptr",
1092
+ },
1093
+ attachNativeSpanFeed: {
1094
+ args: ["ptr"],
1095
+ returns: "i32",
1096
+ },
1097
+ destroyNativeSpanFeed: {
1098
+ args: ["ptr"],
1099
+ returns: "void",
1100
+ },
1101
+ streamWrite: {
1102
+ args: ["ptr", "ptr", "u64"],
1103
+ returns: "i32",
1104
+ },
1105
+ streamCommit: {
1106
+ args: ["ptr"],
1107
+ returns: "i32",
1108
+ },
1109
+ streamDrainSpans: {
1110
+ args: ["ptr", "ptr", "u32"],
1111
+ returns: "u32",
1112
+ },
1113
+ streamClose: {
1114
+ args: ["ptr"],
1115
+ returns: "i32",
1116
+ },
1117
+ streamReserve: {
1118
+ args: ["ptr", "u32", "ptr"],
1119
+ returns: "i32",
1120
+ },
1121
+ streamCommitReserved: {
1122
+ args: ["ptr", "u32"],
1123
+ returns: "i32",
1124
+ },
1125
+ streamSetOptions: {
1126
+ args: ["ptr", "ptr"],
1127
+ returns: "i32",
1128
+ },
1129
+ streamGetStats: {
1130
+ args: ["ptr", "ptr"],
1131
+ returns: "i32",
1132
+ },
1133
+ streamSetCallback: {
1134
+ args: ["ptr", "ptr"],
1135
+ returns: "void",
1136
+ },
1137
+ })
1138
+
1139
+ if (env.OTUI_DEBUG_FFI || env.OTUI_TRACE_FFI) {
1140
+ return {
1141
+ symbols: convertToDebugSymbols(rawSymbols.symbols),
1142
+ }
1143
+ }
1144
+
1145
+ return rawSymbols
1146
+ }
1147
+
1148
+ function convertToDebugSymbols<T extends Record<string, any>>(symbols: T): T {
1149
+ // Initialize global state on first call
1150
+ if (!globalTraceSymbols) {
1151
+ globalTraceSymbols = {}
1152
+ }
1153
+
1154
+ // Initialize global debug log path on first call
1155
+ if (env.OTUI_DEBUG_FFI && !globalFFILogPath) {
1156
+ const now = new Date()
1157
+ const timestamp = now.toISOString().replace(/[:.]/g, "-").replace(/T/, "_").split("Z")[0]
1158
+ globalFFILogPath = `ffi_otui_debug_${timestamp}.log`
1159
+ }
1160
+
1161
+ const debugSymbols: Record<string, any> = {}
1162
+ let hasTracing = false
1163
+
1164
+ Object.entries(symbols).forEach(([key, value]) => {
1165
+ debugSymbols[key] = value
1166
+ })
1167
+
1168
+ if (env.OTUI_DEBUG_FFI && globalFFILogPath) {
1169
+ const logPath = globalFFILogPath
1170
+ const writeSync = (msg: string) => {
1171
+ writeFileSync(logPath, msg + "\n", { flag: "a" })
1172
+ }
1173
+
1174
+ Object.entries(symbols).forEach(([key, value]) => {
1175
+ if (typeof value === "function") {
1176
+ debugSymbols[key] = (...args: any[]) => {
1177
+ writeSync(`${key}(${args.map((arg) => String(arg)).join(", ")})`)
1178
+ const result = value(...args)
1179
+ writeSync(`${key} returned: ${String(result)}`)
1180
+ return result
1181
+ }
1182
+ }
1183
+ })
1184
+ }
1185
+
1186
+ if (env.OTUI_TRACE_FFI) {
1187
+ hasTracing = true
1188
+ Object.entries(symbols).forEach(([key, value]) => {
1189
+ if (typeof value === "function") {
1190
+ // Initialize trace array for this symbol if not exists
1191
+ if (!globalTraceSymbols![key]) {
1192
+ globalTraceSymbols![key] = []
1193
+ }
1194
+
1195
+ const originalFunc = debugSymbols[key]
1196
+ debugSymbols[key] = (...args: any[]) => {
1197
+ const start = performance.now()
1198
+ const result = originalFunc(...args)
1199
+ const end = performance.now()
1200
+ globalTraceSymbols![key].push(end - start)
1201
+ return result
1202
+ }
1203
+ }
1204
+ })
1205
+ }
1206
+
1207
+ // Register exit handler only once
1208
+ if ((env.OTUI_DEBUG_FFI || env.OTUI_TRACE_FFI) && !exitHandlerRegistered) {
1209
+ exitHandlerRegistered = true
1210
+
1211
+ process.on("exit", () => {
1212
+ if (globalTraceSymbols) {
1213
+ const allStats: Array<{
1214
+ name: string
1215
+ count: number
1216
+ total: number
1217
+ average: number
1218
+ min: number
1219
+ max: number
1220
+ median: number
1221
+ p90: number
1222
+ p99: number
1223
+ }> = []
1224
+
1225
+ for (const [key, timings] of Object.entries(globalTraceSymbols)) {
1226
+ if (!Array.isArray(timings) || timings.length === 0) {
1227
+ continue
1228
+ }
1229
+
1230
+ const sortedTimings = [...timings].sort((a, b) => a - b)
1231
+ const count = sortedTimings.length
1232
+
1233
+ const total = sortedTimings.reduce((acc, t) => acc + t, 0)
1234
+ const average = total / count
1235
+ const min = sortedTimings[0]
1236
+ const max = sortedTimings[count - 1]
1237
+
1238
+ const medianIndex = Math.floor(count / 2)
1239
+ const p90Index = Math.floor(count * 0.9)
1240
+ const p99Index = Math.floor(count * 0.99)
1241
+
1242
+ const median = sortedTimings[medianIndex]
1243
+ const p90 = sortedTimings[Math.min(p90Index, count - 1)]
1244
+ const p99 = sortedTimings[Math.min(p99Index, count - 1)]
1245
+
1246
+ allStats.push({
1247
+ name: key,
1248
+ count,
1249
+ total,
1250
+ average,
1251
+ min,
1252
+ max,
1253
+ median,
1254
+ p90,
1255
+ p99,
1256
+ })
1257
+ }
1258
+
1259
+ allStats.sort((a, b) => b.total - a.total)
1260
+
1261
+ const lines: string[] = []
1262
+ lines.push("\n--- OpenTUI FFI Call Performance ---")
1263
+ lines.push("Sorted by total time spent (descending)")
1264
+ lines.push(
1265
+ "-------------------------------------------------------------------------------------------------------------------------",
1266
+ )
1267
+
1268
+ if (allStats.length === 0) {
1269
+ lines.push("No trace data collected or all symbols had zero calls.")
1270
+ } else {
1271
+ const nameHeader = "Symbol"
1272
+ const callsHeader = "Calls"
1273
+ const totalHeader = "Total (ms)"
1274
+ const avgHeader = "Avg (ms)"
1275
+ const minHeader = "Min (ms)"
1276
+ const maxHeader = "Max (ms)"
1277
+ const medHeader = "Med (ms)"
1278
+ const p90Header = "P90 (ms)"
1279
+ const p99Header = "P99 (ms)"
1280
+
1281
+ const nameWidth = Math.max(nameHeader.length, ...allStats.map((s) => s.name.length))
1282
+ const countWidth = Math.max(callsHeader.length, ...allStats.map((s) => String(s.count).length))
1283
+ const totalWidth = Math.max(totalHeader.length, ...allStats.map((s) => s.total.toFixed(2).length))
1284
+ const avgWidth = Math.max(avgHeader.length, ...allStats.map((s) => s.average.toFixed(2).length))
1285
+ const statWidthMin = Math.max(minHeader.length, ...allStats.map((s) => s.min.toFixed(2).length))
1286
+ const statWidthMax = Math.max(maxHeader.length, ...allStats.map((s) => s.max.toFixed(2).length))
1287
+ const medianWidth = Math.max(medHeader.length, ...allStats.map((s) => s.median.toFixed(2).length))
1288
+ const p90Width = Math.max(p90Header.length, ...allStats.map((s) => s.p90.toFixed(2).length))
1289
+ const p99Width = Math.max(p99Header.length, ...allStats.map((s) => s.p99.toFixed(2).length))
1290
+
1291
+ lines.push(
1292
+ `${nameHeader.padEnd(nameWidth)} | ` +
1293
+ `${callsHeader.padStart(countWidth)} | ` +
1294
+ `${totalHeader.padStart(totalWidth)} | ` +
1295
+ `${avgHeader.padStart(avgWidth)} | ` +
1296
+ `${minHeader.padStart(statWidthMin)} | ` +
1297
+ `${maxHeader.padStart(statWidthMax)} | ` +
1298
+ `${medHeader.padStart(medianWidth)} | ` +
1299
+ `${p90Header.padStart(p90Width)} | ` +
1300
+ `${p99Header.padStart(p99Width)}`,
1301
+ )
1302
+ lines.push(
1303
+ `${"-".repeat(nameWidth)}-+-${"-".repeat(countWidth)}-+-${"-".repeat(totalWidth)}-+-${"-".repeat(avgWidth)}-+-${"-".repeat(statWidthMin)}-+-${"-".repeat(statWidthMax)}-+-${"-".repeat(medianWidth)}-+-${"-".repeat(p90Width)}-+-${"-".repeat(p99Width)}`,
1304
+ )
1305
+
1306
+ allStats.forEach((stat) => {
1307
+ lines.push(
1308
+ `${stat.name.padEnd(nameWidth)} | ` +
1309
+ `${String(stat.count).padStart(countWidth)} | ` +
1310
+ `${stat.total.toFixed(2).padStart(totalWidth)} | ` +
1311
+ `${stat.average.toFixed(2).padStart(avgWidth)} | ` +
1312
+ `${stat.min.toFixed(2).padStart(statWidthMin)} | ` +
1313
+ `${stat.max.toFixed(2).padStart(statWidthMax)} | ` +
1314
+ `${stat.median.toFixed(2).padStart(medianWidth)} | ` +
1315
+ `${stat.p90.toFixed(2).padStart(p90Width)} | ` +
1316
+ `${stat.p99.toFixed(2).padStart(p99Width)}`,
1317
+ )
1318
+ })
1319
+ }
1320
+ lines.push(
1321
+ "-------------------------------------------------------------------------------------------------------------------------",
1322
+ )
1323
+
1324
+ const output = lines.join("\n")
1325
+ console.log(output)
1326
+
1327
+ try {
1328
+ const now = new Date()
1329
+ const timestamp = now.toISOString().replace(/[:.]/g, "-").replace(/T/, "_").split("Z")[0]
1330
+ const traceFilePath = `ffi_otui_trace_${timestamp}.log`
1331
+ Bun.write(traceFilePath, output)
1332
+ } catch (e) {
1333
+ console.error("Failed to write FFI trace file:", e)
1334
+ }
1335
+ }
1336
+ })
1337
+ }
1338
+
1339
+ return debugSymbols as T
1340
+ }
1341
+
1342
+ // Log levels matching Zig's LogLevel enum
1343
+ export enum LogLevel {
1344
+ Error = 0,
1345
+ Warn = 1,
1346
+ Info = 2,
1347
+ Debug = 3,
1348
+ }
1349
+
1350
+ /**
1351
+ * VisualCursor represents a cursor position with both visual and logical coordinates.
1352
+ * Visual coordinates (visualRow, visualCol) are VIEWPORT-RELATIVE.
1353
+ * This means visualRow=0 is the first visible line in the viewport, not the first line in the document.
1354
+ * Logical coordinates (logicalRow, logicalCol) are document-absolute.
1355
+ */
1356
+ export interface VisualCursor {
1357
+ visualRow: number // Viewport-relative row (0 = top of viewport)
1358
+ visualCol: number // Viewport-relative column (0 = left edge of viewport when not wrapping)
1359
+ logicalRow: number // Document-absolute row
1360
+ logicalCol: number // Document-absolute column
1361
+ offset: number // Global display-width offset from buffer start
1362
+ }
1363
+
1364
+ export interface LogicalCursor {
1365
+ row: number
1366
+ col: number
1367
+ offset: number
1368
+ }
1369
+
1370
+ export interface CursorState {
1371
+ x: number
1372
+ y: number
1373
+ visible: boolean
1374
+ style: CursorStyle
1375
+ blinking: boolean
1376
+ color: RGBA
1377
+ }
1378
+
1379
+ export type NativeSpanFeedEventHandler = (eventId: number, arg0: Pointer, arg1: number | bigint) => void
1380
+
1381
+ export interface RenderLib {
1382
+ createRenderer: (width: number, height: number, options?: { testing?: boolean; remote?: boolean }) => Pointer | null
1383
+ setTerminalEnvVar: (renderer: Pointer, key: string, value: string) => boolean
1384
+ destroyRenderer: (renderer: Pointer) => void
1385
+ setUseThread: (renderer: Pointer, useThread: boolean) => void
1386
+ setBackgroundColor: (renderer: Pointer, color: RGBA) => void
1387
+ setRenderOffset: (renderer: Pointer, offset: number) => void
1388
+ updateStats: (renderer: Pointer, time: number, fps: number, frameCallbackTime: number) => void
1389
+ updateMemoryStats: (renderer: Pointer, heapUsed: number, heapTotal: number, arrayBuffers: number) => void
1390
+ render: (renderer: Pointer, force: boolean) => void
1391
+ getNextBuffer: (renderer: Pointer) => OptimizedBuffer
1392
+ getCurrentBuffer: (renderer: Pointer) => OptimizedBuffer
1393
+ createOptimizedBuffer: (
1394
+ width: number,
1395
+ height: number,
1396
+ widthMethod: WidthMethod,
1397
+ respectAlpha?: boolean,
1398
+ id?: string,
1399
+ ) => OptimizedBuffer
1400
+ destroyOptimizedBuffer: (bufferPtr: Pointer) => void
1401
+ drawFrameBuffer: (
1402
+ targetBufferPtr: Pointer,
1403
+ destX: number,
1404
+ destY: number,
1405
+ bufferPtr: Pointer,
1406
+ sourceX?: number,
1407
+ sourceY?: number,
1408
+ sourceWidth?: number,
1409
+ sourceHeight?: number,
1410
+ ) => void
1411
+ getBufferWidth: (buffer: Pointer) => number
1412
+ getBufferHeight: (buffer: Pointer) => number
1413
+ bufferClear: (buffer: Pointer, color: RGBA) => void
1414
+ bufferGetCharPtr: (buffer: Pointer) => Pointer
1415
+ bufferGetFgPtr: (buffer: Pointer) => Pointer
1416
+ bufferGetBgPtr: (buffer: Pointer) => Pointer
1417
+ bufferGetAttributesPtr: (buffer: Pointer) => Pointer
1418
+ bufferGetRespectAlpha: (buffer: Pointer) => boolean
1419
+ bufferSetRespectAlpha: (buffer: Pointer, respectAlpha: boolean) => void
1420
+ bufferGetId: (buffer: Pointer) => string
1421
+ bufferGetRealCharSize: (buffer: Pointer) => number
1422
+ bufferWriteResolvedChars: (buffer: Pointer, outputBuffer: Uint8Array, addLineBreaks: boolean) => number
1423
+ bufferDrawText: (
1424
+ buffer: Pointer,
1425
+ text: string,
1426
+ x: number,
1427
+ y: number,
1428
+ color: RGBA,
1429
+ bgColor?: RGBA,
1430
+ attributes?: number,
1431
+ ) => void
1432
+ bufferSetCellWithAlphaBlending: (
1433
+ buffer: Pointer,
1434
+ x: number,
1435
+ y: number,
1436
+ char: string,
1437
+ color: RGBA,
1438
+ bgColor: RGBA,
1439
+ attributes?: number,
1440
+ ) => void
1441
+ bufferSetCell: (
1442
+ buffer: Pointer,
1443
+ x: number,
1444
+ y: number,
1445
+ char: string,
1446
+ color: RGBA,
1447
+ bgColor: RGBA,
1448
+ attributes?: number,
1449
+ ) => void
1450
+ bufferFillRect: (buffer: Pointer, x: number, y: number, width: number, height: number, color: RGBA) => void
1451
+ bufferColorMatrix: (
1452
+ buffer: Pointer,
1453
+ matrixPtr: Pointer,
1454
+ cellMaskPtr: Pointer,
1455
+ cellMaskCount: number,
1456
+ strength: number,
1457
+ target: TargetChannel,
1458
+ ) => void
1459
+ bufferColorMatrixUniform: (buffer: Pointer, matrixPtr: Pointer, strength: number, target: TargetChannel) => void
1460
+ bufferDrawSuperSampleBuffer: (
1461
+ buffer: Pointer,
1462
+ x: number,
1463
+ y: number,
1464
+ pixelDataPtr: Pointer,
1465
+ pixelDataLength: number,
1466
+ format: "bgra8unorm" | "rgba8unorm",
1467
+ alignedBytesPerRow: number,
1468
+ ) => void
1469
+ bufferDrawPackedBuffer: (
1470
+ buffer: Pointer,
1471
+ dataPtr: Pointer,
1472
+ dataLen: number,
1473
+ posX: number,
1474
+ posY: number,
1475
+ terminalWidthCells: number,
1476
+ terminalHeightCells: number,
1477
+ ) => void
1478
+ bufferDrawGrayscaleBuffer: (
1479
+ buffer: Pointer,
1480
+ posX: number,
1481
+ posY: number,
1482
+ intensitiesPtr: Pointer,
1483
+ srcWidth: number,
1484
+ srcHeight: number,
1485
+ fg: RGBA | null,
1486
+ bg: RGBA | null,
1487
+ ) => void
1488
+ bufferDrawGrayscaleBufferSupersampled: (
1489
+ buffer: Pointer,
1490
+ posX: number,
1491
+ posY: number,
1492
+ intensitiesPtr: Pointer,
1493
+ srcWidth: number,
1494
+ srcHeight: number,
1495
+ fg: RGBA | null,
1496
+ bg: RGBA | null,
1497
+ ) => void
1498
+ bufferDrawGrid: (
1499
+ buffer: Pointer,
1500
+ borderChars: Uint32Array,
1501
+ borderFg: RGBA,
1502
+ borderBg: RGBA,
1503
+ columnOffsets: Int32Array,
1504
+ columnCount: number,
1505
+ rowOffsets: Int32Array,
1506
+ rowCount: number,
1507
+ options: { drawInner: boolean; drawOuter: boolean },
1508
+ ) => void
1509
+ bufferDrawBox: (
1510
+ buffer: Pointer,
1511
+ x: number,
1512
+ y: number,
1513
+ width: number,
1514
+ height: number,
1515
+ borderChars: Uint32Array,
1516
+ packedOptions: number,
1517
+ borderColor: RGBA,
1518
+ backgroundColor: RGBA,
1519
+ title: string | null,
1520
+ bottomTitle: string | null,
1521
+ ) => void
1522
+ bufferResize: (buffer: Pointer, width: number, height: number) => void
1523
+ resizeRenderer: (renderer: Pointer, width: number, height: number) => void
1524
+ setCursorPosition: (renderer: Pointer, x: number, y: number, visible: boolean) => void
1525
+ setCursorColor: (renderer: Pointer, color: RGBA) => void
1526
+ getCursorState: (renderer: Pointer) => CursorState
1527
+ setCursorStyleOptions: (renderer: Pointer, options: CursorStyleOptions) => void
1528
+ setDebugOverlay: (renderer: Pointer, enabled: boolean, corner: DebugOverlayCorner) => void
1529
+ clearTerminal: (renderer: Pointer) => void
1530
+ setTerminalTitle: (renderer: Pointer, title: string) => void
1531
+ copyToClipboardOSC52: (renderer: Pointer, target: number, payload: Uint8Array) => boolean
1532
+ clearClipboardOSC52: (renderer: Pointer, target: number) => boolean
1533
+ addToHitGrid: (renderer: Pointer, x: number, y: number, width: number, height: number, id: number) => void
1534
+ clearCurrentHitGrid: (renderer: Pointer) => void
1535
+ hitGridPushScissorRect: (renderer: Pointer, x: number, y: number, width: number, height: number) => void
1536
+ hitGridPopScissorRect: (renderer: Pointer) => void
1537
+ hitGridClearScissorRects: (renderer: Pointer) => void
1538
+ addToCurrentHitGridClipped: (
1539
+ renderer: Pointer,
1540
+ x: number,
1541
+ y: number,
1542
+ width: number,
1543
+ height: number,
1544
+ id: number,
1545
+ ) => void
1546
+ checkHit: (renderer: Pointer, x: number, y: number) => number
1547
+ getHitGridDirty: (renderer: Pointer) => boolean
1548
+ dumpHitGrid: (renderer: Pointer) => void
1549
+ dumpBuffers: (renderer: Pointer, timestamp?: number) => void
1550
+ dumpStdoutBuffer: (renderer: Pointer, timestamp?: number) => void
1551
+ restoreTerminalModes: (renderer: Pointer) => void
1552
+ enableMouse: (renderer: Pointer, enableMovement: boolean) => void
1553
+ disableMouse: (renderer: Pointer) => void
1554
+ enableKittyKeyboard: (renderer: Pointer, flags: number) => void
1555
+ disableKittyKeyboard: (renderer: Pointer) => void
1556
+ setKittyKeyboardFlags: (renderer: Pointer, flags: number) => void
1557
+ getKittyKeyboardFlags: (renderer: Pointer) => number
1558
+ setupTerminal: (renderer: Pointer, useAlternateScreen: boolean) => void
1559
+ suspendRenderer: (renderer: Pointer) => void
1560
+ resumeRenderer: (renderer: Pointer) => void
1561
+ queryPixelResolution: (renderer: Pointer) => void
1562
+ writeOut: (renderer: Pointer, data: string | Uint8Array) => void
1563
+
1564
+ // TextBuffer methods
1565
+ createTextBuffer: (widthMethod: WidthMethod) => TextBuffer
1566
+ destroyTextBuffer: (buffer: Pointer) => void
1567
+ textBufferGetLength: (buffer: Pointer) => number
1568
+ textBufferGetByteSize: (buffer: Pointer) => number
1569
+
1570
+ textBufferReset: (buffer: Pointer) => void
1571
+ textBufferClear: (buffer: Pointer) => void
1572
+ textBufferRegisterMemBuffer: (buffer: Pointer, bytes: Uint8Array, owned?: boolean) => number
1573
+ textBufferReplaceMemBuffer: (buffer: Pointer, memId: number, bytes: Uint8Array, owned?: boolean) => boolean
1574
+ textBufferClearMemRegistry: (buffer: Pointer) => void
1575
+ textBufferSetTextFromMem: (buffer: Pointer, memId: number) => void
1576
+ textBufferAppend: (buffer: Pointer, bytes: Uint8Array) => void
1577
+ textBufferAppendFromMemId: (buffer: Pointer, memId: number) => void
1578
+ textBufferLoadFile: (buffer: Pointer, path: string) => boolean
1579
+ textBufferSetStyledText: (
1580
+ buffer: Pointer,
1581
+ chunks: Array<{ text: string; fg?: RGBA | null; bg?: RGBA | null; attributes?: number; link?: { url: string } }>,
1582
+ ) => void
1583
+ textBufferSetDefaultFg: (buffer: Pointer, fg: RGBA | null) => void
1584
+ textBufferSetDefaultBg: (buffer: Pointer, bg: RGBA | null) => void
1585
+ textBufferSetDefaultAttributes: (buffer: Pointer, attributes: number | null) => void
1586
+ textBufferResetDefaults: (buffer: Pointer) => void
1587
+ textBufferGetTabWidth: (buffer: Pointer) => number
1588
+ textBufferSetTabWidth: (buffer: Pointer, width: number) => void
1589
+ textBufferGetLineCount: (buffer: Pointer) => number
1590
+ getPlainTextBytes: (buffer: Pointer, maxLength: number) => Uint8Array | null
1591
+ textBufferGetTextRange: (
1592
+ buffer: Pointer,
1593
+ startOffset: number,
1594
+ endOffset: number,
1595
+ maxLength: number,
1596
+ ) => Uint8Array | null
1597
+ textBufferGetTextRangeByCoords: (
1598
+ buffer: Pointer,
1599
+ startRow: number,
1600
+ startCol: number,
1601
+ endRow: number,
1602
+ endCol: number,
1603
+ maxLength: number,
1604
+ ) => Uint8Array | null
1605
+
1606
+ // TextBufferView methods
1607
+ createTextBufferView: (textBuffer: Pointer) => Pointer
1608
+ destroyTextBufferView: (view: Pointer) => void
1609
+ textBufferViewSetSelection: (
1610
+ view: Pointer,
1611
+ start: number,
1612
+ end: number,
1613
+ bgColor: RGBA | null,
1614
+ fgColor: RGBA | null,
1615
+ ) => void
1616
+ textBufferViewResetSelection: (view: Pointer) => void
1617
+ textBufferViewGetSelection: (view: Pointer) => { start: number; end: number } | null
1618
+ textBufferViewSetLocalSelection: (
1619
+ view: Pointer,
1620
+ anchorX: number,
1621
+ anchorY: number,
1622
+ focusX: number,
1623
+ focusY: number,
1624
+ bgColor: RGBA | null,
1625
+ fgColor: RGBA | null,
1626
+ ) => boolean
1627
+ textBufferViewUpdateSelection: (view: Pointer, end: number, bgColor: RGBA | null, fgColor: RGBA | null) => void
1628
+ textBufferViewUpdateLocalSelection: (
1629
+ view: Pointer,
1630
+ anchorX: number,
1631
+ anchorY: number,
1632
+ focusX: number,
1633
+ focusY: number,
1634
+ bgColor: RGBA | null,
1635
+ fgColor: RGBA | null,
1636
+ ) => boolean
1637
+ textBufferViewResetLocalSelection: (view: Pointer) => void
1638
+ textBufferViewSetWrapWidth: (view: Pointer, width: number) => void
1639
+ textBufferViewSetWrapMode: (view: Pointer, mode: "none" | "char" | "word") => void
1640
+ textBufferViewSetViewportSize: (view: Pointer, width: number, height: number) => void
1641
+ textBufferViewSetViewport: (view: Pointer, x: number, y: number, width: number, height: number) => void
1642
+ textBufferViewGetLineInfo: (view: Pointer) => LineInfo
1643
+ textBufferViewGetLogicalLineInfo: (view: Pointer) => LineInfo
1644
+ textBufferViewGetSelectedTextBytes: (view: Pointer, maxLength: number) => Uint8Array | null
1645
+ textBufferViewGetPlainTextBytes: (view: Pointer, maxLength: number) => Uint8Array | null
1646
+ textBufferViewSetTabIndicator: (view: Pointer, indicator: number) => void
1647
+ textBufferViewSetTabIndicatorColor: (view: Pointer, color: RGBA) => void
1648
+ textBufferViewSetTruncate: (view: Pointer, truncate: boolean) => void
1649
+ textBufferViewMeasureForDimensions: (
1650
+ view: Pointer,
1651
+ width: number,
1652
+ height: number,
1653
+ ) => { lineCount: number; widthColsMax: number } | null
1654
+ textBufferViewGetVirtualLineCount: (view: Pointer) => number
1655
+
1656
+ readonly encoder: TextEncoder
1657
+ readonly decoder: TextDecoder
1658
+ bufferDrawTextBufferView: (buffer: Pointer, view: Pointer, x: number, y: number) => void
1659
+ bufferDrawEditorView: (buffer: Pointer, view: Pointer, x: number, y: number) => void
1660
+
1661
+ // EditBuffer methods
1662
+ createEditBuffer: (widthMethod: WidthMethod) => Pointer
1663
+ destroyEditBuffer: (buffer: Pointer) => void
1664
+ editBufferSetText: (buffer: Pointer, textBytes: Uint8Array) => void
1665
+ editBufferSetTextFromMem: (buffer: Pointer, memId: number) => void
1666
+ editBufferReplaceText: (buffer: Pointer, textBytes: Uint8Array) => void
1667
+ editBufferReplaceTextFromMem: (buffer: Pointer, memId: number) => void
1668
+ editBufferGetText: (buffer: Pointer, maxLength: number) => Uint8Array | null
1669
+ editBufferInsertChar: (buffer: Pointer, char: string) => void
1670
+ editBufferInsertText: (buffer: Pointer, text: string) => void
1671
+ editBufferDeleteChar: (buffer: Pointer) => void
1672
+ editBufferDeleteCharBackward: (buffer: Pointer) => void
1673
+ editBufferDeleteRange: (buffer: Pointer, startLine: number, startCol: number, endLine: number, endCol: number) => void
1674
+ editBufferNewLine: (buffer: Pointer) => void
1675
+ editBufferDeleteLine: (buffer: Pointer) => void
1676
+ editBufferMoveCursorLeft: (buffer: Pointer) => void
1677
+ editBufferMoveCursorRight: (buffer: Pointer) => void
1678
+ editBufferMoveCursorUp: (buffer: Pointer) => void
1679
+ editBufferMoveCursorDown: (buffer: Pointer) => void
1680
+ editBufferGotoLine: (buffer: Pointer, line: number) => void
1681
+ editBufferSetCursor: (buffer: Pointer, line: number, col: number) => void
1682
+ editBufferSetCursorToLineCol: (buffer: Pointer, line: number, col: number) => void
1683
+ editBufferSetCursorByOffset: (buffer: Pointer, offset: number) => void
1684
+ editBufferGetCursorPosition: (buffer: Pointer) => LogicalCursor
1685
+ editBufferGetId: (buffer: Pointer) => number
1686
+ editBufferGetTextBuffer: (buffer: Pointer) => Pointer
1687
+ editBufferDebugLogRope: (buffer: Pointer) => void
1688
+ editBufferUndo: (buffer: Pointer, maxLength: number) => Uint8Array | null
1689
+ editBufferRedo: (buffer: Pointer, maxLength: number) => Uint8Array | null
1690
+ editBufferCanUndo: (buffer: Pointer) => boolean
1691
+ editBufferCanRedo: (buffer: Pointer) => boolean
1692
+ editBufferClearHistory: (buffer: Pointer) => void
1693
+ editBufferClear: (buffer: Pointer) => void
1694
+ editBufferGetNextWordBoundary: (buffer: Pointer) => { row: number; col: number; offset: number }
1695
+ editBufferGetPrevWordBoundary: (buffer: Pointer) => { row: number; col: number; offset: number }
1696
+ editBufferGetEOL: (buffer: Pointer) => { row: number; col: number; offset: number }
1697
+ editBufferOffsetToPosition: (buffer: Pointer, offset: number) => { row: number; col: number; offset: number } | null
1698
+ editBufferPositionToOffset: (buffer: Pointer, row: number, col: number) => number
1699
+ editBufferGetLineStartOffset: (buffer: Pointer, row: number) => number
1700
+ editBufferGetTextRange: (
1701
+ buffer: Pointer,
1702
+ startOffset: number,
1703
+ endOffset: number,
1704
+ maxLength: number,
1705
+ ) => Uint8Array | null
1706
+ editBufferGetTextRangeByCoords: (
1707
+ buffer: Pointer,
1708
+ startRow: number,
1709
+ startCol: number,
1710
+ endRow: number,
1711
+ endCol: number,
1712
+ maxLength: number,
1713
+ ) => Uint8Array | null
1714
+
1715
+ // EditorView methods
1716
+ createEditorView: (editBufferPtr: Pointer, viewportWidth: number, viewportHeight: number) => Pointer
1717
+ destroyEditorView: (view: Pointer) => void
1718
+ editorViewSetViewportSize: (view: Pointer, width: number, height: number) => void
1719
+ editorViewSetViewport: (
1720
+ view: Pointer,
1721
+ x: number,
1722
+ y: number,
1723
+ width: number,
1724
+ height: number,
1725
+ moveCursor: boolean,
1726
+ ) => void
1727
+ editorViewGetViewport: (view: Pointer) => { offsetY: number; offsetX: number; height: number; width: number }
1728
+ editorViewSetScrollMargin: (view: Pointer, margin: number) => void
1729
+ editorViewSetWrapMode: (view: Pointer, mode: "none" | "char" | "word") => void
1730
+ editorViewGetVirtualLineCount: (view: Pointer) => number
1731
+ editorViewGetTotalVirtualLineCount: (view: Pointer) => number
1732
+ editorViewGetTextBufferView: (view: Pointer) => Pointer
1733
+ editorViewSetSelection: (
1734
+ view: Pointer,
1735
+ start: number,
1736
+ end: number,
1737
+ bgColor: RGBA | null,
1738
+ fgColor: RGBA | null,
1739
+ ) => void
1740
+ editorViewResetSelection: (view: Pointer) => void
1741
+ editorViewGetSelection: (view: Pointer) => { start: number; end: number } | null
1742
+ editorViewSetLocalSelection: (
1743
+ view: Pointer,
1744
+ anchorX: number,
1745
+ anchorY: number,
1746
+ focusX: number,
1747
+ focusY: number,
1748
+ bgColor: RGBA | null,
1749
+ fgColor: RGBA | null,
1750
+ updateCursor: boolean,
1751
+ followCursor: boolean,
1752
+ ) => boolean
1753
+
1754
+ editorViewUpdateSelection: (view: Pointer, end: number, bgColor: RGBA | null, fgColor: RGBA | null) => void
1755
+ editorViewUpdateLocalSelection: (
1756
+ view: Pointer,
1757
+ anchorX: number,
1758
+ anchorY: number,
1759
+ focusX: number,
1760
+ focusY: number,
1761
+ bgColor: RGBA | null,
1762
+ fgColor: RGBA | null,
1763
+ updateCursor: boolean,
1764
+ followCursor: boolean,
1765
+ ) => boolean
1766
+
1767
+ editorViewResetLocalSelection: (view: Pointer) => void
1768
+ editorViewGetSelectedTextBytes: (view: Pointer, maxLength: number) => Uint8Array | null
1769
+ editorViewGetCursor: (view: Pointer) => { row: number; col: number }
1770
+ editorViewGetText: (view: Pointer, maxLength: number) => Uint8Array | null
1771
+ editorViewGetVisualCursor: (view: Pointer) => VisualCursor
1772
+ editorViewMoveUpVisual: (view: Pointer) => void
1773
+ editorViewMoveDownVisual: (view: Pointer) => void
1774
+ editorViewDeleteSelectedText: (view: Pointer) => void
1775
+ editorViewSetCursorByOffset: (view: Pointer, offset: number) => void
1776
+ editorViewGetNextWordBoundary: (view: Pointer) => VisualCursor
1777
+ editorViewGetPrevWordBoundary: (view: Pointer) => VisualCursor
1778
+ editorViewGetEOL: (view: Pointer) => VisualCursor
1779
+ editorViewGetVisualSOL: (view: Pointer) => VisualCursor
1780
+ editorViewGetVisualEOL: (view: Pointer) => VisualCursor
1781
+ editorViewGetLineInfo: (view: Pointer) => LineInfo
1782
+ editorViewGetLogicalLineInfo: (view: Pointer) => LineInfo
1783
+ editorViewSetPlaceholderStyledText: (
1784
+ view: Pointer,
1785
+ chunks: Array<{ text: string; fg?: RGBA | null; bg?: RGBA | null; attributes?: number }>,
1786
+ ) => void
1787
+ editorViewSetTabIndicator: (view: Pointer, indicator: number) => void
1788
+ editorViewSetTabIndicatorColor: (view: Pointer, color: RGBA) => void
1789
+
1790
+ bufferPushScissorRect: (buffer: Pointer, x: number, y: number, width: number, height: number) => void
1791
+ bufferPopScissorRect: (buffer: Pointer) => void
1792
+ bufferClearScissorRects: (buffer: Pointer) => void
1793
+ bufferPushOpacity: (buffer: Pointer, opacity: number) => void
1794
+ bufferPopOpacity: (buffer: Pointer) => void
1795
+ bufferGetCurrentOpacity: (buffer: Pointer) => number
1796
+ bufferClearOpacity: (buffer: Pointer) => void
1797
+ textBufferAddHighlightByCharRange: (buffer: Pointer, highlight: Highlight) => void
1798
+ textBufferAddHighlight: (buffer: Pointer, lineIdx: number, highlight: Highlight) => void
1799
+ textBufferRemoveHighlightsByRef: (buffer: Pointer, hlRef: number) => void
1800
+ textBufferClearLineHighlights: (buffer: Pointer, lineIdx: number) => void
1801
+ textBufferClearAllHighlights: (buffer: Pointer) => void
1802
+ textBufferSetSyntaxStyle: (buffer: Pointer, style: Pointer | null) => void
1803
+ textBufferGetLineHighlights: (buffer: Pointer, lineIdx: number) => Array<Highlight>
1804
+ textBufferGetHighlightCount: (buffer: Pointer) => number
1805
+
1806
+ getArenaAllocatedBytes: () => number
1807
+ getBuildOptions: () => BuildOptions
1808
+ getAllocatorStats: () => AllocatorStats
1809
+
1810
+ createSyntaxStyle: () => Pointer
1811
+ destroySyntaxStyle: (style: Pointer) => void
1812
+ syntaxStyleRegister: (style: Pointer, name: string, fg: RGBA | null, bg: RGBA | null, attributes: number) => number
1813
+ syntaxStyleResolveByName: (style: Pointer, name: string) => number | null
1814
+ syntaxStyleGetStyleCount: (style: Pointer) => number
1815
+
1816
+ getTerminalCapabilities: (renderer: Pointer) => any
1817
+ processCapabilityResponse: (renderer: Pointer, response: string) => void
1818
+
1819
+ encodeUnicode: (
1820
+ text: string,
1821
+ widthMethod: WidthMethod,
1822
+ ) => { ptr: Pointer; data: Array<{ width: number; char: number }> } | null
1823
+ freeUnicode: (encoded: { ptr: Pointer; data: Array<{ width: number; char: number }> }) => void
1824
+ bufferDrawChar: (buffer: Pointer, char: number, x: number, y: number, fg: RGBA, bg: RGBA, attributes?: number) => void
1825
+
1826
+ registerNativeSpanFeedStream: (stream: Pointer, handler: NativeSpanFeedEventHandler) => void
1827
+ unregisterNativeSpanFeedStream: (stream: Pointer) => void
1828
+ createNativeSpanFeed: (options?: NativeSpanFeedOptions | null) => Pointer
1829
+ attachNativeSpanFeed: (stream: Pointer) => number
1830
+ destroyNativeSpanFeed: (stream: Pointer) => void
1831
+ streamWrite: (stream: Pointer, data: Uint8Array | string) => number
1832
+ streamCommit: (stream: Pointer) => number
1833
+ streamDrainSpans: (stream: Pointer, outBuffer: Uint8Array, maxSpans: number) => number
1834
+ streamClose: (stream: Pointer) => number
1835
+ streamSetOptions: (stream: Pointer, options: NativeSpanFeedOptions) => number
1836
+ streamGetStats: (stream: Pointer) => NativeSpanFeedStats | null
1837
+ streamReserve: (stream: Pointer, minLen: number) => { status: number; info: ReserveInfo | null }
1838
+ streamCommitReserved: (stream: Pointer, length: number) => number
1839
+
1840
+ onNativeEvent: (name: string, handler: (data: ArrayBuffer) => void) => void
1841
+ onceNativeEvent: (name: string, handler: (data: ArrayBuffer) => void) => void
1842
+ offNativeEvent: (name: string, handler: (data: ArrayBuffer) => void) => void
1843
+ onAnyNativeEvent: (handler: (name: string, data: ArrayBuffer) => void) => void
1844
+ }
1845
+
1846
+ class FFIRenderLib implements RenderLib {
1847
+ private opentui: ReturnType<typeof getOpenTUILib>
1848
+ public readonly encoder: TextEncoder = new TextEncoder()
1849
+ public readonly decoder: TextDecoder = new TextDecoder()
1850
+ private logCallbackWrapper: any // Store the FFI callback wrapper
1851
+ private eventCallbackWrapper: any // Store the FFI event callback wrapper
1852
+ private _nativeEvents: EventEmitter = new EventEmitter()
1853
+ private _anyEventHandlers: Array<(name: string, data: ArrayBuffer) => void> = []
1854
+ private nativeSpanFeedCallbackWrapper: JSCallback | null = null
1855
+ private nativeSpanFeedHandlers = new Map<Pointer, NativeSpanFeedEventHandler>()
1856
+
1857
+ constructor(libPath?: string) {
1858
+ this.opentui = getOpenTUILib(libPath)
1859
+ this.setupLogging()
1860
+ this.setupEventBus()
1861
+ }
1862
+
1863
+ private setupLogging() {
1864
+ if (this.logCallbackWrapper) {
1865
+ return
1866
+ }
1867
+
1868
+ const logCallback = new JSCallback(
1869
+ (level: number, msgPtr: Pointer, msgLenBigInt: bigint | number) => {
1870
+ try {
1871
+ const msgLen = typeof msgLenBigInt === "bigint" ? Number(msgLenBigInt) : msgLenBigInt
1872
+
1873
+ if (msgLen === 0 || !msgPtr) {
1874
+ return
1875
+ }
1876
+
1877
+ const msgBuffer = toArrayBuffer(msgPtr, 0, msgLen)
1878
+ const msgBytes = new Uint8Array(msgBuffer)
1879
+ const message = this.decoder.decode(msgBytes)
1880
+
1881
+ switch (level) {
1882
+ case LogLevel.Error:
1883
+ console.error(message)
1884
+ break
1885
+ case LogLevel.Warn:
1886
+ console.warn(message)
1887
+ break
1888
+ case LogLevel.Info:
1889
+ console.info(message)
1890
+ break
1891
+ case LogLevel.Debug:
1892
+ console.debug(message)
1893
+ break
1894
+ default:
1895
+ console.log(message)
1896
+ }
1897
+ } catch (error) {
1898
+ console.error("Error in Zig log callback:", error)
1899
+ }
1900
+ },
1901
+ {
1902
+ args: ["u8", "ptr", "usize"],
1903
+ returns: "void",
1904
+ },
1905
+ )
1906
+
1907
+ this.logCallbackWrapper = logCallback
1908
+
1909
+ if (!logCallback.ptr) {
1910
+ throw new Error("Failed to create log callback")
1911
+ }
1912
+
1913
+ this.setLogCallback(logCallback.ptr)
1914
+ }
1915
+
1916
+ private setLogCallback(callbackPtr: Pointer) {
1917
+ this.opentui.symbols.setLogCallback(callbackPtr)
1918
+ }
1919
+
1920
+ private setupEventBus() {
1921
+ if (this.eventCallbackWrapper) {
1922
+ return
1923
+ }
1924
+
1925
+ const eventCallback = new JSCallback(
1926
+ (namePtr: Pointer, nameLenBigInt: bigint | number, dataPtr: Pointer, dataLenBigInt: bigint | number) => {
1927
+ try {
1928
+ const nameLen = typeof nameLenBigInt === "bigint" ? Number(nameLenBigInt) : nameLenBigInt
1929
+ const dataLen = typeof dataLenBigInt === "bigint" ? Number(dataLenBigInt) : dataLenBigInt
1930
+
1931
+ if (nameLen === 0 || !namePtr) {
1932
+ return
1933
+ }
1934
+
1935
+ const nameBuffer = toArrayBuffer(namePtr, 0, nameLen)
1936
+ const nameBytes = new Uint8Array(nameBuffer)
1937
+ const eventName = this.decoder.decode(nameBytes)
1938
+
1939
+ let eventData: ArrayBuffer
1940
+ if (dataLen > 0 && dataPtr) {
1941
+ eventData = toArrayBuffer(dataPtr, 0, dataLen).slice()
1942
+ } else {
1943
+ eventData = new ArrayBuffer(0)
1944
+ }
1945
+
1946
+ queueMicrotask(() => {
1947
+ this._nativeEvents.emit(eventName, eventData)
1948
+
1949
+ for (const handler of this._anyEventHandlers) {
1950
+ handler(eventName, eventData)
1951
+ }
1952
+ })
1953
+ } catch (error) {
1954
+ console.error("Error in native event callback:", error)
1955
+ }
1956
+ },
1957
+ {
1958
+ args: ["ptr", "usize", "ptr", "usize"],
1959
+ returns: "void",
1960
+ },
1961
+ )
1962
+
1963
+ this.eventCallbackWrapper = eventCallback
1964
+
1965
+ if (!eventCallback.ptr) {
1966
+ throw new Error("Failed to create event callback")
1967
+ }
1968
+
1969
+ this.setEventCallback(eventCallback.ptr)
1970
+ }
1971
+
1972
+ private ensureNativeSpanFeedCallback(): JSCallback {
1973
+ if (this.nativeSpanFeedCallbackWrapper) {
1974
+ return this.nativeSpanFeedCallbackWrapper
1975
+ }
1976
+
1977
+ const callback = new JSCallback(
1978
+ (streamPtr: Pointer, eventId: number, arg0: Pointer, arg1: number | bigint) => {
1979
+ const handler = this.nativeSpanFeedHandlers.get(toPointer(streamPtr))
1980
+ if (handler) {
1981
+ handler(eventId, arg0, arg1)
1982
+ }
1983
+ },
1984
+ {
1985
+ args: ["ptr", "u32", "ptr", "u64"],
1986
+ returns: "void",
1987
+ },
1988
+ )
1989
+
1990
+ this.nativeSpanFeedCallbackWrapper = callback
1991
+
1992
+ if (!callback.ptr) {
1993
+ throw new Error("Failed to create native span feed callback")
1994
+ }
1995
+
1996
+ return callback
1997
+ }
1998
+
1999
+ private setEventCallback(callbackPtr: Pointer) {
2000
+ this.opentui.symbols.setEventCallback(callbackPtr)
2001
+ }
2002
+
2003
+ public createRenderer(width: number, height: number, options: { testing?: boolean; remote?: boolean } = {}) {
2004
+ const testing = options.testing ?? false
2005
+ const remote = options.remote ?? false
2006
+ return this.opentui.symbols.createRenderer(width, height, testing, remote)
2007
+ }
2008
+
2009
+ public setTerminalEnvVar(renderer: Pointer, key: string, value: string): boolean {
2010
+ const keyBytes = this.encoder.encode(key)
2011
+ const valueBytes = this.encoder.encode(value)
2012
+ return this.opentui.symbols.setTerminalEnvVar(renderer, keyBytes, keyBytes.length, valueBytes, valueBytes.length)
2013
+ }
2014
+
2015
+ public destroyRenderer(renderer: Pointer): void {
2016
+ this.opentui.symbols.destroyRenderer(renderer)
2017
+ }
2018
+
2019
+ public setUseThread(renderer: Pointer, useThread: boolean) {
2020
+ this.opentui.symbols.setUseThread(renderer, useThread)
2021
+ }
2022
+
2023
+ public setBackgroundColor(renderer: Pointer, color: RGBA) {
2024
+ this.opentui.symbols.setBackgroundColor(renderer, color.buffer)
2025
+ }
2026
+
2027
+ public setRenderOffset(renderer: Pointer, offset: number) {
2028
+ this.opentui.symbols.setRenderOffset(renderer, offset)
2029
+ }
2030
+
2031
+ public updateStats(renderer: Pointer, time: number, fps: number, frameCallbackTime: number) {
2032
+ this.opentui.symbols.updateStats(renderer, time, fps, frameCallbackTime)
2033
+ }
2034
+
2035
+ public updateMemoryStats(renderer: Pointer, heapUsed: number, heapTotal: number, arrayBuffers: number) {
2036
+ this.opentui.symbols.updateMemoryStats(renderer, heapUsed, heapTotal, arrayBuffers)
2037
+ }
2038
+
2039
+ public getNextBuffer(renderer: Pointer): OptimizedBuffer {
2040
+ const bufferPtr = this.opentui.symbols.getNextBuffer(renderer)
2041
+ if (!bufferPtr) {
2042
+ throw new Error("Failed to get next buffer")
2043
+ }
2044
+
2045
+ const width = this.opentui.symbols.getBufferWidth(bufferPtr)
2046
+ const height = this.opentui.symbols.getBufferHeight(bufferPtr)
2047
+
2048
+ return new OptimizedBuffer(this, bufferPtr, width, height, { id: "next buffer", widthMethod: "unicode" })
2049
+ }
2050
+
2051
+ public getCurrentBuffer(renderer: Pointer): OptimizedBuffer {
2052
+ const bufferPtr = this.opentui.symbols.getCurrentBuffer(renderer)
2053
+ if (!bufferPtr) {
2054
+ throw new Error("Failed to get current buffer")
2055
+ }
2056
+
2057
+ const width = this.opentui.symbols.getBufferWidth(bufferPtr)
2058
+ const height = this.opentui.symbols.getBufferHeight(bufferPtr)
2059
+
2060
+ return new OptimizedBuffer(this, bufferPtr, width, height, { id: "current buffer", widthMethod: "unicode" })
2061
+ }
2062
+
2063
+ public bufferGetCharPtr(buffer: Pointer): Pointer {
2064
+ const ptr = this.opentui.symbols.bufferGetCharPtr(buffer)
2065
+ if (!ptr) {
2066
+ throw new Error("Failed to get char pointer")
2067
+ }
2068
+ return ptr
2069
+ }
2070
+
2071
+ public bufferGetFgPtr(buffer: Pointer): Pointer {
2072
+ const ptr = this.opentui.symbols.bufferGetFgPtr(buffer)
2073
+ if (!ptr) {
2074
+ throw new Error("Failed to get fg pointer")
2075
+ }
2076
+ return ptr
2077
+ }
2078
+
2079
+ public bufferGetBgPtr(buffer: Pointer): Pointer {
2080
+ const ptr = this.opentui.symbols.bufferGetBgPtr(buffer)
2081
+ if (!ptr) {
2082
+ throw new Error("Failed to get bg pointer")
2083
+ }
2084
+ return ptr
2085
+ }
2086
+
2087
+ public bufferGetAttributesPtr(buffer: Pointer): Pointer {
2088
+ const ptr = this.opentui.symbols.bufferGetAttributesPtr(buffer)
2089
+ if (!ptr) {
2090
+ throw new Error("Failed to get attributes pointer")
2091
+ }
2092
+ return ptr
2093
+ }
2094
+
2095
+ public bufferGetRespectAlpha(buffer: Pointer): boolean {
2096
+ return this.opentui.symbols.bufferGetRespectAlpha(buffer)
2097
+ }
2098
+
2099
+ public bufferSetRespectAlpha(buffer: Pointer, respectAlpha: boolean): void {
2100
+ this.opentui.symbols.bufferSetRespectAlpha(buffer, respectAlpha)
2101
+ }
2102
+
2103
+ public bufferGetId(buffer: Pointer): string {
2104
+ const maxLen = 256
2105
+ const outBuffer = new Uint8Array(maxLen)
2106
+ const actualLen = this.opentui.symbols.bufferGetId(buffer, outBuffer, maxLen)
2107
+ const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen
2108
+ return this.decoder.decode(outBuffer.slice(0, len))
2109
+ }
2110
+
2111
+ public bufferGetRealCharSize(buffer: Pointer): number {
2112
+ return this.opentui.symbols.bufferGetRealCharSize(buffer)
2113
+ }
2114
+
2115
+ public bufferWriteResolvedChars(buffer: Pointer, outputBuffer: Uint8Array, addLineBreaks: boolean): number {
2116
+ const bytesWritten = this.opentui.symbols.bufferWriteResolvedChars(
2117
+ buffer,
2118
+ outputBuffer,
2119
+ outputBuffer.length,
2120
+ addLineBreaks,
2121
+ )
2122
+ return typeof bytesWritten === "bigint" ? Number(bytesWritten) : bytesWritten
2123
+ }
2124
+
2125
+ public getBufferWidth(buffer: Pointer): number {
2126
+ return this.opentui.symbols.getBufferWidth(buffer)
2127
+ }
2128
+
2129
+ public getBufferHeight(buffer: Pointer): number {
2130
+ return this.opentui.symbols.getBufferHeight(buffer)
2131
+ }
2132
+
2133
+ public bufferClear(buffer: Pointer, color: RGBA) {
2134
+ this.opentui.symbols.bufferClear(buffer, color.buffer)
2135
+ }
2136
+
2137
+ public bufferDrawText(
2138
+ buffer: Pointer,
2139
+ text: string,
2140
+ x: number,
2141
+ y: number,
2142
+ color: RGBA,
2143
+ bgColor?: RGBA,
2144
+ attributes?: number,
2145
+ ) {
2146
+ const textBytes = this.encoder.encode(text)
2147
+ const textLength = textBytes.byteLength
2148
+ const bg = bgColor ? bgColor.buffer : null
2149
+ const fg = color.buffer
2150
+
2151
+ this.opentui.symbols.bufferDrawText(buffer, textBytes, textLength, x, y, fg, bg, attributes ?? 0)
2152
+ }
2153
+
2154
+ public bufferSetCellWithAlphaBlending(
2155
+ buffer: Pointer,
2156
+ x: number,
2157
+ y: number,
2158
+ char: string,
2159
+ color: RGBA,
2160
+ bgColor: RGBA,
2161
+ attributes?: number,
2162
+ ) {
2163
+ const charPtr = char.codePointAt(0) ?? " ".codePointAt(0)!
2164
+ const bg = bgColor.buffer
2165
+ const fg = color.buffer
2166
+
2167
+ this.opentui.symbols.bufferSetCellWithAlphaBlending(buffer, x, y, charPtr, fg, bg, attributes ?? 0)
2168
+ }
2169
+
2170
+ public bufferSetCell(
2171
+ buffer: Pointer,
2172
+ x: number,
2173
+ y: number,
2174
+ char: string,
2175
+ color: RGBA,
2176
+ bgColor: RGBA,
2177
+ attributes?: number,
2178
+ ) {
2179
+ const charPtr = char.codePointAt(0) ?? " ".codePointAt(0)!
2180
+ const bg = bgColor.buffer
2181
+ const fg = color.buffer
2182
+
2183
+ this.opentui.symbols.bufferSetCell(buffer, x, y, charPtr, fg, bg, attributes ?? 0)
2184
+ }
2185
+
2186
+ public bufferFillRect(buffer: Pointer, x: number, y: number, width: number, height: number, color: RGBA) {
2187
+ const bg = color.buffer
2188
+ this.opentui.symbols.bufferFillRect(buffer, x, y, width, height, bg)
2189
+ }
2190
+
2191
+ public bufferColorMatrix(
2192
+ buffer: Pointer,
2193
+ matrixPtr: Pointer,
2194
+ cellMaskPtr: Pointer,
2195
+ cellMaskCount: number,
2196
+ strength: number,
2197
+ target: TargetChannel,
2198
+ ): void {
2199
+ this.opentui.symbols.bufferColorMatrix(buffer, matrixPtr, cellMaskPtr, cellMaskCount, strength, target)
2200
+ }
2201
+
2202
+ public bufferColorMatrixUniform(buffer: Pointer, matrixPtr: Pointer, strength: number, target: TargetChannel): void {
2203
+ this.opentui.symbols.bufferColorMatrixUniform(buffer, matrixPtr, strength, target)
2204
+ }
2205
+
2206
+ public bufferDrawSuperSampleBuffer(
2207
+ buffer: Pointer,
2208
+ x: number,
2209
+ y: number,
2210
+ pixelDataPtr: Pointer,
2211
+ pixelDataLength: number,
2212
+ format: "bgra8unorm" | "rgba8unorm",
2213
+ alignedBytesPerRow: number,
2214
+ ): void {
2215
+ const formatId = format === "bgra8unorm" ? 0 : 1
2216
+ this.opentui.symbols.bufferDrawSuperSampleBuffer(
2217
+ buffer,
2218
+ x,
2219
+ y,
2220
+ pixelDataPtr,
2221
+ pixelDataLength,
2222
+ formatId,
2223
+ alignedBytesPerRow,
2224
+ )
2225
+ }
2226
+
2227
+ public bufferDrawPackedBuffer(
2228
+ buffer: Pointer,
2229
+ dataPtr: Pointer,
2230
+ dataLen: number,
2231
+ posX: number,
2232
+ posY: number,
2233
+ terminalWidthCells: number,
2234
+ terminalHeightCells: number,
2235
+ ): void {
2236
+ this.opentui.symbols.bufferDrawPackedBuffer(
2237
+ buffer,
2238
+ dataPtr,
2239
+ dataLen,
2240
+ posX,
2241
+ posY,
2242
+ terminalWidthCells,
2243
+ terminalHeightCells,
2244
+ )
2245
+ }
2246
+
2247
+ public bufferDrawGrayscaleBuffer(
2248
+ buffer: Pointer,
2249
+ posX: number,
2250
+ posY: number,
2251
+ intensitiesPtr: Pointer,
2252
+ srcWidth: number,
2253
+ srcHeight: number,
2254
+ fg: RGBA | null,
2255
+ bg: RGBA | null,
2256
+ ): void {
2257
+ this.opentui.symbols.bufferDrawGrayscaleBuffer(
2258
+ buffer,
2259
+ posX,
2260
+ posY,
2261
+ intensitiesPtr,
2262
+ srcWidth,
2263
+ srcHeight,
2264
+ fg?.buffer ?? null,
2265
+ bg?.buffer ?? null,
2266
+ )
2267
+ }
2268
+
2269
+ public bufferDrawGrayscaleBufferSupersampled(
2270
+ buffer: Pointer,
2271
+ posX: number,
2272
+ posY: number,
2273
+ intensitiesPtr: Pointer,
2274
+ srcWidth: number,
2275
+ srcHeight: number,
2276
+ fg: RGBA | null,
2277
+ bg: RGBA | null,
2278
+ ): void {
2279
+ this.opentui.symbols.bufferDrawGrayscaleBufferSupersampled(
2280
+ buffer,
2281
+ posX,
2282
+ posY,
2283
+ intensitiesPtr,
2284
+ srcWidth,
2285
+ srcHeight,
2286
+ fg?.buffer ?? null,
2287
+ bg?.buffer ?? null,
2288
+ )
2289
+ }
2290
+
2291
+ public bufferDrawGrid(
2292
+ buffer: Pointer,
2293
+ borderChars: Uint32Array,
2294
+ borderFg: RGBA,
2295
+ borderBg: RGBA,
2296
+ columnOffsets: Int32Array,
2297
+ columnCount: number,
2298
+ rowOffsets: Int32Array,
2299
+ rowCount: number,
2300
+ options: { drawInner: boolean; drawOuter: boolean },
2301
+ ): void {
2302
+ const optionsBuffer = GridDrawOptionsStruct.pack({
2303
+ drawInner: options.drawInner,
2304
+ drawOuter: options.drawOuter,
2305
+ })
2306
+
2307
+ this.opentui.symbols.bufferDrawGrid(
2308
+ buffer,
2309
+ borderChars,
2310
+ borderFg.buffer,
2311
+ borderBg.buffer,
2312
+ columnOffsets,
2313
+ columnCount,
2314
+ rowOffsets,
2315
+ rowCount,
2316
+ ptr(optionsBuffer),
2317
+ )
2318
+ }
2319
+
2320
+ public bufferDrawBox(
2321
+ buffer: Pointer,
2322
+ x: number,
2323
+ y: number,
2324
+ width: number,
2325
+ height: number,
2326
+ borderChars: Uint32Array,
2327
+ packedOptions: number,
2328
+ borderColor: RGBA,
2329
+ backgroundColor: RGBA,
2330
+ title: string | null,
2331
+ bottomTitle: string | null,
2332
+ ): void {
2333
+ const titleBytes = title ? this.encoder.encode(title) : null
2334
+ const titleLen = title ? titleBytes!.length : 0
2335
+ const titlePtr = title ? titleBytes : null
2336
+
2337
+ const bottomTitleBytes = bottomTitle ? this.encoder.encode(bottomTitle) : null
2338
+ const bottomTitleLen = bottomTitle ? bottomTitleBytes!.length : 0
2339
+ const bottomTitlePtr = bottomTitle ? bottomTitleBytes : null
2340
+
2341
+ this.opentui.symbols.bufferDrawBox(
2342
+ buffer,
2343
+ x,
2344
+ y,
2345
+ width,
2346
+ height,
2347
+ borderChars,
2348
+ packedOptions,
2349
+ borderColor.buffer,
2350
+ backgroundColor.buffer,
2351
+ titlePtr,
2352
+ titleLen,
2353
+ bottomTitlePtr,
2354
+ bottomTitleLen,
2355
+ )
2356
+ }
2357
+
2358
+ public bufferResize(buffer: Pointer, width: number, height: number): void {
2359
+ this.opentui.symbols.bufferResize(buffer, width, height)
2360
+ }
2361
+
2362
+ // Link API
2363
+ public linkAlloc(url: string): number {
2364
+ const urlBytes = this.encoder.encode(url)
2365
+ return this.opentui.symbols.linkAlloc(urlBytes, urlBytes.length)
2366
+ }
2367
+
2368
+ public linkGetUrl(linkId: number, maxLen: number = 512): string {
2369
+ const outBuffer = new Uint8Array(maxLen)
2370
+ const actualLen = this.opentui.symbols.linkGetUrl(linkId, outBuffer, maxLen)
2371
+ return this.decoder.decode(outBuffer.slice(0, actualLen))
2372
+ }
2373
+
2374
+ public attributesWithLink(baseAttributes: number, linkId: number): number {
2375
+ return this.opentui.symbols.attributesWithLink(baseAttributes, linkId)
2376
+ }
2377
+
2378
+ public attributesGetLinkId(attributes: number): number {
2379
+ return this.opentui.symbols.attributesGetLinkId(attributes)
2380
+ }
2381
+
2382
+ public resizeRenderer(renderer: Pointer, width: number, height: number) {
2383
+ this.opentui.symbols.resizeRenderer(renderer, width, height)
2384
+ }
2385
+
2386
+ public setCursorPosition(renderer: Pointer, x: number, y: number, visible: boolean) {
2387
+ this.opentui.symbols.setCursorPosition(renderer, x, y, visible)
2388
+ }
2389
+
2390
+ public setCursorColor(renderer: Pointer, color: RGBA) {
2391
+ this.opentui.symbols.setCursorColor(renderer, color.buffer)
2392
+ }
2393
+
2394
+ public getCursorState(renderer: Pointer): CursorState {
2395
+ const cursorBuffer = new ArrayBuffer(CursorStateStruct.size)
2396
+ this.opentui.symbols.getCursorState(renderer, ptr(cursorBuffer))
2397
+ const struct = CursorStateStruct.unpack(cursorBuffer)
2398
+
2399
+ return {
2400
+ x: struct.x,
2401
+ y: struct.y,
2402
+ visible: struct.visible,
2403
+ style: CURSOR_ID_TO_STYLE[struct.style] ?? "block",
2404
+ blinking: struct.blinking,
2405
+ color: RGBA.fromValues(struct.r, struct.g, struct.b, struct.a),
2406
+ }
2407
+ }
2408
+
2409
+ public setCursorStyleOptions(renderer: Pointer, options: CursorStyleOptions): void {
2410
+ const style = options.style != null ? CURSOR_STYLE_TO_ID[options.style] : 255
2411
+ const blinking = options.blinking != null ? (options.blinking ? 1 : 0) : 255
2412
+ const cursor = options.cursor != null ? MOUSE_STYLE_TO_ID[options.cursor] : 255
2413
+
2414
+ const buffer = CursorStyleOptionsStruct.pack({ style, blinking, color: options.color, cursor })
2415
+ this.opentui.symbols.setCursorStyleOptions(renderer, ptr(buffer))
2416
+ }
2417
+
2418
+ public render(renderer: Pointer, force: boolean) {
2419
+ this.opentui.symbols.render(renderer, force)
2420
+ }
2421
+
2422
+ public createOptimizedBuffer(
2423
+ width: number,
2424
+ height: number,
2425
+ widthMethod: WidthMethod,
2426
+ respectAlpha: boolean = false,
2427
+ id?: string,
2428
+ ): OptimizedBuffer {
2429
+ if (Number.isNaN(width) || Number.isNaN(height)) {
2430
+ console.error(new Error(`Invalid dimensions for OptimizedBuffer: ${width}x${height}`).stack)
2431
+ }
2432
+
2433
+ const widthMethodCode = widthMethod === "wcwidth" ? 0 : 1
2434
+ const idToUse = id || "unnamed buffer"
2435
+ const idBytes = this.encoder.encode(idToUse)
2436
+ const bufferPtr = this.opentui.symbols.createOptimizedBuffer(
2437
+ width,
2438
+ height,
2439
+ respectAlpha,
2440
+ widthMethodCode,
2441
+ idBytes,
2442
+ idBytes.length,
2443
+ )
2444
+ if (!bufferPtr) {
2445
+ throw new Error(`Failed to create optimized buffer: ${width}x${height}`)
2446
+ }
2447
+
2448
+ return new OptimizedBuffer(this, bufferPtr, width, height, { respectAlpha, id, widthMethod })
2449
+ }
2450
+
2451
+ public destroyOptimizedBuffer(bufferPtr: Pointer) {
2452
+ this.opentui.symbols.destroyOptimizedBuffer(bufferPtr)
2453
+ }
2454
+
2455
+ public drawFrameBuffer(
2456
+ targetBufferPtr: Pointer,
2457
+ destX: number,
2458
+ destY: number,
2459
+ bufferPtr: Pointer,
2460
+ sourceX?: number,
2461
+ sourceY?: number,
2462
+ sourceWidth?: number,
2463
+ sourceHeight?: number,
2464
+ ) {
2465
+ const srcX = sourceX ?? 0
2466
+ const srcY = sourceY ?? 0
2467
+ const srcWidth = sourceWidth ?? 0
2468
+ const srcHeight = sourceHeight ?? 0
2469
+ this.opentui.symbols.drawFrameBuffer(targetBufferPtr, destX, destY, bufferPtr, srcX, srcY, srcWidth, srcHeight)
2470
+ }
2471
+
2472
+ public setDebugOverlay(renderer: Pointer, enabled: boolean, corner: DebugOverlayCorner) {
2473
+ this.opentui.symbols.setDebugOverlay(renderer, enabled, corner)
2474
+ }
2475
+
2476
+ public clearTerminal(renderer: Pointer) {
2477
+ this.opentui.symbols.clearTerminal(renderer)
2478
+ }
2479
+
2480
+ public setTerminalTitle(renderer: Pointer, title: string) {
2481
+ const titleBytes = this.encoder.encode(title)
2482
+ this.opentui.symbols.setTerminalTitle(renderer, titleBytes, titleBytes.length)
2483
+ }
2484
+
2485
+ public copyToClipboardOSC52(renderer: Pointer, target: number, payload: Uint8Array): boolean {
2486
+ return this.opentui.symbols.copyToClipboardOSC52(renderer, target, payload, payload.length)
2487
+ }
2488
+
2489
+ public clearClipboardOSC52(renderer: Pointer, target: number): boolean {
2490
+ return this.opentui.symbols.clearClipboardOSC52(renderer, target)
2491
+ }
2492
+
2493
+ public addToHitGrid(renderer: Pointer, x: number, y: number, width: number, height: number, id: number) {
2494
+ this.opentui.symbols.addToHitGrid(renderer, x, y, width, height, id)
2495
+ }
2496
+
2497
+ public clearCurrentHitGrid(renderer: Pointer) {
2498
+ this.opentui.symbols.clearCurrentHitGrid(renderer)
2499
+ }
2500
+
2501
+ public hitGridPushScissorRect(renderer: Pointer, x: number, y: number, width: number, height: number) {
2502
+ this.opentui.symbols.hitGridPushScissorRect(renderer, x, y, width, height)
2503
+ }
2504
+
2505
+ public hitGridPopScissorRect(renderer: Pointer) {
2506
+ this.opentui.symbols.hitGridPopScissorRect(renderer)
2507
+ }
2508
+
2509
+ public hitGridClearScissorRects(renderer: Pointer) {
2510
+ this.opentui.symbols.hitGridClearScissorRects(renderer)
2511
+ }
2512
+
2513
+ public addToCurrentHitGridClipped(
2514
+ renderer: Pointer,
2515
+ x: number,
2516
+ y: number,
2517
+ width: number,
2518
+ height: number,
2519
+ id: number,
2520
+ ) {
2521
+ this.opentui.symbols.addToCurrentHitGridClipped(renderer, x, y, width, height, id)
2522
+ }
2523
+
2524
+ public checkHit(renderer: Pointer, x: number, y: number): number {
2525
+ return this.opentui.symbols.checkHit(renderer, x, y)
2526
+ }
2527
+
2528
+ public getHitGridDirty(renderer: Pointer): boolean {
2529
+ return this.opentui.symbols.getHitGridDirty(renderer)
2530
+ }
2531
+
2532
+ public dumpHitGrid(renderer: Pointer): void {
2533
+ this.opentui.symbols.dumpHitGrid(renderer)
2534
+ }
2535
+
2536
+ public dumpBuffers(renderer: Pointer, timestamp?: number): void {
2537
+ const ts = timestamp ?? Date.now()
2538
+ this.opentui.symbols.dumpBuffers(renderer, ts)
2539
+ }
2540
+
2541
+ public dumpStdoutBuffer(renderer: Pointer, timestamp?: number): void {
2542
+ const ts = timestamp ?? Date.now()
2543
+ this.opentui.symbols.dumpStdoutBuffer(renderer, ts)
2544
+ }
2545
+
2546
+ public restoreTerminalModes(renderer: Pointer): void {
2547
+ this.opentui.symbols.restoreTerminalModes(renderer)
2548
+ }
2549
+
2550
+ public enableMouse(renderer: Pointer, enableMovement: boolean): void {
2551
+ this.opentui.symbols.enableMouse(renderer, enableMovement)
2552
+ }
2553
+
2554
+ public disableMouse(renderer: Pointer): void {
2555
+ this.opentui.symbols.disableMouse(renderer)
2556
+ }
2557
+
2558
+ public enableKittyKeyboard(renderer: Pointer, flags: number): void {
2559
+ this.opentui.symbols.enableKittyKeyboard(renderer, flags)
2560
+ }
2561
+
2562
+ public disableKittyKeyboard(renderer: Pointer): void {
2563
+ this.opentui.symbols.disableKittyKeyboard(renderer)
2564
+ }
2565
+
2566
+ public setKittyKeyboardFlags(renderer: Pointer, flags: number): void {
2567
+ this.opentui.symbols.setKittyKeyboardFlags(renderer, flags)
2568
+ }
2569
+
2570
+ public getKittyKeyboardFlags(renderer: Pointer): number {
2571
+ return this.opentui.symbols.getKittyKeyboardFlags(renderer)
2572
+ }
2573
+
2574
+ public setupTerminal(renderer: Pointer, useAlternateScreen: boolean): void {
2575
+ this.opentui.symbols.setupTerminal(renderer, useAlternateScreen)
2576
+ }
2577
+
2578
+ public suspendRenderer(renderer: Pointer): void {
2579
+ this.opentui.symbols.suspendRenderer(renderer)
2580
+ }
2581
+
2582
+ public resumeRenderer(renderer: Pointer): void {
2583
+ this.opentui.symbols.resumeRenderer(renderer)
2584
+ }
2585
+
2586
+ public queryPixelResolution(renderer: Pointer): void {
2587
+ this.opentui.symbols.queryPixelResolution(renderer)
2588
+ }
2589
+
2590
+ /**
2591
+ * Write data to stdout, synchronizing with the render thread if necessary.
2592
+ * This should be used for ALL stdout writes to avoid race conditions when
2593
+ * the render thread is active.
2594
+ */
2595
+ public writeOut(renderer: Pointer, data: string | Uint8Array): void {
2596
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data
2597
+ if (bytes.length === 0) return
2598
+ this.opentui.symbols.writeOut(renderer, ptr(bytes), bytes.length)
2599
+ }
2600
+
2601
+ // TextBuffer methods
2602
+ public createTextBuffer(widthMethod: WidthMethod): TextBuffer {
2603
+ const widthMethodCode = widthMethod === "wcwidth" ? 0 : 1
2604
+ const bufferPtr = this.opentui.symbols.createTextBuffer(widthMethodCode)
2605
+ if (!bufferPtr) {
2606
+ throw new Error(`Failed to create TextBuffer`)
2607
+ }
2608
+
2609
+ return new TextBuffer(this, bufferPtr)
2610
+ }
2611
+
2612
+ public destroyTextBuffer(buffer: Pointer): void {
2613
+ this.opentui.symbols.destroyTextBuffer(buffer)
2614
+ }
2615
+
2616
+ public textBufferGetLength(buffer: Pointer): number {
2617
+ return this.opentui.symbols.textBufferGetLength(buffer)
2618
+ }
2619
+
2620
+ public textBufferGetByteSize(buffer: Pointer): number {
2621
+ return this.opentui.symbols.textBufferGetByteSize(buffer)
2622
+ }
2623
+
2624
+ public textBufferReset(buffer: Pointer): void {
2625
+ this.opentui.symbols.textBufferReset(buffer)
2626
+ }
2627
+
2628
+ public textBufferClear(buffer: Pointer): void {
2629
+ this.opentui.symbols.textBufferClear(buffer)
2630
+ }
2631
+
2632
+ public textBufferSetDefaultFg(buffer: Pointer, fg: RGBA | null): void {
2633
+ const fgPtr = fg ? fg.buffer : null
2634
+ this.opentui.symbols.textBufferSetDefaultFg(buffer, fgPtr)
2635
+ }
2636
+
2637
+ public textBufferSetDefaultBg(buffer: Pointer, bg: RGBA | null): void {
2638
+ const bgPtr = bg ? bg.buffer : null
2639
+ this.opentui.symbols.textBufferSetDefaultBg(buffer, bgPtr)
2640
+ }
2641
+
2642
+ public textBufferSetDefaultAttributes(buffer: Pointer, attributes: number | null): void {
2643
+ const attrValue = attributes === null ? null : new Uint8Array([attributes])
2644
+ this.opentui.symbols.textBufferSetDefaultAttributes(buffer, attrValue)
2645
+ }
2646
+
2647
+ public textBufferResetDefaults(buffer: Pointer): void {
2648
+ this.opentui.symbols.textBufferResetDefaults(buffer)
2649
+ }
2650
+
2651
+ public textBufferGetTabWidth(buffer: Pointer): number {
2652
+ return this.opentui.symbols.textBufferGetTabWidth(buffer)
2653
+ }
2654
+
2655
+ public textBufferSetTabWidth(buffer: Pointer, width: number): void {
2656
+ this.opentui.symbols.textBufferSetTabWidth(buffer, width)
2657
+ }
2658
+
2659
+ public textBufferRegisterMemBuffer(buffer: Pointer, bytes: Uint8Array, owned: boolean = false): number {
2660
+ const result = this.opentui.symbols.textBufferRegisterMemBuffer(buffer, bytes, bytes.length, owned)
2661
+ if (result === 0xffff) {
2662
+ throw new Error("Failed to register memory buffer")
2663
+ }
2664
+ return result
2665
+ }
2666
+
2667
+ public textBufferReplaceMemBuffer(
2668
+ buffer: Pointer,
2669
+ memId: number,
2670
+ bytes: Uint8Array,
2671
+ owned: boolean = false,
2672
+ ): boolean {
2673
+ return this.opentui.symbols.textBufferReplaceMemBuffer(buffer, memId, bytes, bytes.length, owned)
2674
+ }
2675
+
2676
+ public textBufferClearMemRegistry(buffer: Pointer): void {
2677
+ this.opentui.symbols.textBufferClearMemRegistry(buffer)
2678
+ }
2679
+
2680
+ public textBufferSetTextFromMem(buffer: Pointer, memId: number): void {
2681
+ this.opentui.symbols.textBufferSetTextFromMem(buffer, memId)
2682
+ }
2683
+
2684
+ public textBufferAppend(buffer: Pointer, bytes: Uint8Array): void {
2685
+ this.opentui.symbols.textBufferAppend(buffer, bytes, bytes.length)
2686
+ }
2687
+
2688
+ public textBufferAppendFromMemId(buffer: Pointer, memId: number): void {
2689
+ this.opentui.symbols.textBufferAppendFromMemId(buffer, memId)
2690
+ }
2691
+
2692
+ public textBufferLoadFile(buffer: Pointer, path: string): boolean {
2693
+ const pathBytes = this.encoder.encode(path)
2694
+ return this.opentui.symbols.textBufferLoadFile(buffer, pathBytes, pathBytes.length)
2695
+ }
2696
+
2697
+ public textBufferSetStyledText(
2698
+ buffer: Pointer,
2699
+ chunks: Array<{ text: string; fg?: RGBA | null; bg?: RGBA | null; attributes?: number; link?: { url: string } }>,
2700
+ ): void {
2701
+ if (chunks.length === 0) {
2702
+ this.textBufferClear(buffer)
2703
+ return
2704
+ }
2705
+
2706
+ const chunksBuffer = StyledChunkStruct.packList(chunks)
2707
+ this.opentui.symbols.textBufferSetStyledText(buffer, ptr(chunksBuffer), chunks.length)
2708
+ }
2709
+
2710
+ public textBufferGetLineCount(buffer: Pointer): number {
2711
+ return this.opentui.symbols.textBufferGetLineCount(buffer)
2712
+ }
2713
+
2714
+ private textBufferGetPlainText(buffer: Pointer, outPtr: Pointer, maxLen: number): number {
2715
+ const result = this.opentui.symbols.textBufferGetPlainText(buffer, outPtr, maxLen)
2716
+ return typeof result === "bigint" ? Number(result) : result
2717
+ }
2718
+
2719
+ public getPlainTextBytes(buffer: Pointer, maxLength: number): Uint8Array | null {
2720
+ const outBuffer = new Uint8Array(maxLength)
2721
+
2722
+ const actualLen = this.textBufferGetPlainText(buffer, ptr(outBuffer), maxLength)
2723
+
2724
+ if (actualLen === 0) {
2725
+ return null
2726
+ }
2727
+
2728
+ return outBuffer.slice(0, actualLen)
2729
+ }
2730
+
2731
+ public textBufferGetTextRange(
2732
+ buffer: Pointer,
2733
+ startOffset: number,
2734
+ endOffset: number,
2735
+ maxLength: number,
2736
+ ): Uint8Array | null {
2737
+ const outBuffer = new Uint8Array(maxLength)
2738
+
2739
+ const actualLen = this.opentui.symbols.textBufferGetTextRange(
2740
+ buffer,
2741
+ startOffset,
2742
+ endOffset,
2743
+ ptr(outBuffer),
2744
+ maxLength,
2745
+ )
2746
+
2747
+ const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen
2748
+
2749
+ if (len === 0) {
2750
+ return null
2751
+ }
2752
+
2753
+ return outBuffer.slice(0, len)
2754
+ }
2755
+
2756
+ public textBufferGetTextRangeByCoords(
2757
+ buffer: Pointer,
2758
+ startRow: number,
2759
+ startCol: number,
2760
+ endRow: number,
2761
+ endCol: number,
2762
+ maxLength: number,
2763
+ ): Uint8Array | null {
2764
+ const outBuffer = new Uint8Array(maxLength)
2765
+
2766
+ const actualLen = this.opentui.symbols.textBufferGetTextRangeByCoords(
2767
+ buffer,
2768
+ startRow,
2769
+ startCol,
2770
+ endRow,
2771
+ endCol,
2772
+ ptr(outBuffer),
2773
+ maxLength,
2774
+ )
2775
+
2776
+ const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen
2777
+
2778
+ if (len === 0) {
2779
+ return null
2780
+ }
2781
+
2782
+ return outBuffer.slice(0, len)
2783
+ }
2784
+
2785
+ // TextBufferView methods
2786
+ public createTextBufferView(textBuffer: Pointer): Pointer {
2787
+ const viewPtr = this.opentui.symbols.createTextBufferView(textBuffer)
2788
+ if (!viewPtr) {
2789
+ throw new Error("Failed to create TextBufferView")
2790
+ }
2791
+ return viewPtr
2792
+ }
2793
+
2794
+ public destroyTextBufferView(view: Pointer): void {
2795
+ this.opentui.symbols.destroyTextBufferView(view)
2796
+ }
2797
+
2798
+ public textBufferViewSetSelection(
2799
+ view: Pointer,
2800
+ start: number,
2801
+ end: number,
2802
+ bgColor: RGBA | null,
2803
+ fgColor: RGBA | null,
2804
+ ): void {
2805
+ const bg = bgColor ? bgColor.buffer : null
2806
+ const fg = fgColor ? fgColor.buffer : null
2807
+ this.opentui.symbols.textBufferViewSetSelection(view, start, end, bg, fg)
2808
+ }
2809
+
2810
+ public textBufferViewResetSelection(view: Pointer): void {
2811
+ this.opentui.symbols.textBufferViewResetSelection(view)
2812
+ }
2813
+
2814
+ public textBufferViewGetSelection(view: Pointer): { start: number; end: number } | null {
2815
+ const packedInfo = this.textBufferViewGetSelectionInfo(view)
2816
+
2817
+ // Check for no selection marker (0xFFFFFFFF_FFFFFFFF)
2818
+ if (packedInfo === 0xffff_ffff_ffff_ffffn) {
2819
+ return null
2820
+ }
2821
+
2822
+ const start = Number(packedInfo >> 32n)
2823
+ const end = Number(packedInfo & 0xffff_ffffn)
2824
+
2825
+ return { start, end }
2826
+ }
2827
+
2828
+ private textBufferViewGetSelectionInfo(view: Pointer): bigint {
2829
+ return this.opentui.symbols.textBufferViewGetSelectionInfo(view)
2830
+ }
2831
+
2832
+ public textBufferViewSetLocalSelection(
2833
+ view: Pointer,
2834
+ anchorX: number,
2835
+ anchorY: number,
2836
+ focusX: number,
2837
+ focusY: number,
2838
+ bgColor: RGBA | null,
2839
+ fgColor: RGBA | null,
2840
+ ): boolean {
2841
+ const bg = bgColor ? bgColor.buffer : null
2842
+ const fg = fgColor ? fgColor.buffer : null
2843
+ return this.opentui.symbols.textBufferViewSetLocalSelection(view, anchorX, anchorY, focusX, focusY, bg, fg)
2844
+ }
2845
+
2846
+ public textBufferViewUpdateSelection(view: Pointer, end: number, bgColor: RGBA | null, fgColor: RGBA | null): void {
2847
+ const bg = bgColor ? bgColor.buffer : null
2848
+ const fg = fgColor ? fgColor.buffer : null
2849
+ this.opentui.symbols.textBufferViewUpdateSelection(view, end, bg, fg)
2850
+ }
2851
+
2852
+ public textBufferViewUpdateLocalSelection(
2853
+ view: Pointer,
2854
+ anchorX: number,
2855
+ anchorY: number,
2856
+ focusX: number,
2857
+ focusY: number,
2858
+ bgColor: RGBA | null,
2859
+ fgColor: RGBA | null,
2860
+ ): boolean {
2861
+ const bg = bgColor ? bgColor.buffer : null
2862
+ const fg = fgColor ? fgColor.buffer : null
2863
+ return this.opentui.symbols.textBufferViewUpdateLocalSelection(view, anchorX, anchorY, focusX, focusY, bg, fg)
2864
+ }
2865
+
2866
+ public textBufferViewResetLocalSelection(view: Pointer): void {
2867
+ this.opentui.symbols.textBufferViewResetLocalSelection(view)
2868
+ }
2869
+
2870
+ public textBufferViewSetWrapWidth(view: Pointer, width: number): void {
2871
+ this.opentui.symbols.textBufferViewSetWrapWidth(view, width)
2872
+ }
2873
+
2874
+ public textBufferViewSetWrapMode(view: Pointer, mode: "none" | "char" | "word"): void {
2875
+ const modeValue = mode === "none" ? 0 : mode === "char" ? 1 : 2
2876
+ this.opentui.symbols.textBufferViewSetWrapMode(view, modeValue)
2877
+ }
2878
+
2879
+ public textBufferViewSetViewportSize(view: Pointer, width: number, height: number): void {
2880
+ this.opentui.symbols.textBufferViewSetViewportSize(view, width, height)
2881
+ }
2882
+
2883
+ public textBufferViewSetViewport(view: Pointer, x: number, y: number, width: number, height: number): void {
2884
+ this.opentui.symbols.textBufferViewSetViewport(view, x, y, width, height)
2885
+ }
2886
+
2887
+ public textBufferViewGetLineInfo(view: Pointer): LineInfo {
2888
+ const outBuffer = new ArrayBuffer(LineInfoStruct.size)
2889
+ this.textBufferViewGetLineInfoDirect(view, ptr(outBuffer))
2890
+ const struct = LineInfoStruct.unpack(outBuffer)
2891
+
2892
+ const lineStartCols = struct.startCols as number[]
2893
+ const lineWidthCols = struct.widthCols as number[]
2894
+ const lineWidthColsMax = struct.widthColsMax
2895
+
2896
+ return {
2897
+ lineStartCols,
2898
+ lineWidthCols,
2899
+ lineWidthColsMax,
2900
+ lineSources: struct.sources as number[],
2901
+ lineWraps: struct.wraps as number[],
2902
+ }
2903
+ }
2904
+
2905
+ public textBufferViewGetLogicalLineInfo(view: Pointer): LineInfo {
2906
+ const outBuffer = new ArrayBuffer(LineInfoStruct.size)
2907
+ this.textBufferViewGetLogicalLineInfoDirect(view, ptr(outBuffer))
2908
+ const struct = LineInfoStruct.unpack(outBuffer)
2909
+
2910
+ const lineStartCols = struct.startCols as number[]
2911
+ const lineWidthCols = struct.widthCols as number[]
2912
+ const lineWidthColsMax = struct.widthColsMax
2913
+
2914
+ return {
2915
+ lineStartCols,
2916
+ lineWidthCols,
2917
+ lineWidthColsMax,
2918
+ lineSources: struct.sources as number[],
2919
+ lineWraps: struct.wraps as number[],
2920
+ }
2921
+ }
2922
+
2923
+ public textBufferViewGetVirtualLineCount(view: Pointer): number {
2924
+ return this.opentui.symbols.textBufferViewGetVirtualLineCount(view)
2925
+ }
2926
+
2927
+ private textBufferViewGetLineInfoDirect(view: Pointer, outPtr: Pointer): void {
2928
+ this.opentui.symbols.textBufferViewGetLineInfoDirect(view, outPtr)
2929
+ }
2930
+
2931
+ private textBufferViewGetLogicalLineInfoDirect(view: Pointer, outPtr: Pointer): void {
2932
+ this.opentui.symbols.textBufferViewGetLogicalLineInfoDirect(view, outPtr)
2933
+ }
2934
+
2935
+ private textBufferViewGetSelectedText(view: Pointer, outPtr: Pointer, maxLen: number): number {
2936
+ const result = this.opentui.symbols.textBufferViewGetSelectedText(view, outPtr, maxLen)
2937
+ return typeof result === "bigint" ? Number(result) : result
2938
+ }
2939
+
2940
+ private textBufferViewGetPlainText(view: Pointer, outPtr: Pointer, maxLen: number): number {
2941
+ const result = this.opentui.symbols.textBufferViewGetPlainText(view, outPtr, maxLen)
2942
+ return typeof result === "bigint" ? Number(result) : result
2943
+ }
2944
+
2945
+ public textBufferViewGetSelectedTextBytes(view: Pointer, maxLength: number): Uint8Array | null {
2946
+ const outBuffer = new Uint8Array(maxLength)
2947
+
2948
+ const actualLen = this.textBufferViewGetSelectedText(view, ptr(outBuffer), maxLength)
2949
+
2950
+ if (actualLen === 0) {
2951
+ return null
2952
+ }
2953
+
2954
+ return outBuffer.slice(0, actualLen)
2955
+ }
2956
+
2957
+ public textBufferViewGetPlainTextBytes(view: Pointer, maxLength: number): Uint8Array | null {
2958
+ const outBuffer = new Uint8Array(maxLength)
2959
+
2960
+ const actualLen = this.textBufferViewGetPlainText(view, ptr(outBuffer), maxLength)
2961
+
2962
+ if (actualLen === 0) {
2963
+ return null
2964
+ }
2965
+
2966
+ return outBuffer.slice(0, actualLen)
2967
+ }
2968
+
2969
+ public textBufferViewSetTabIndicator(view: Pointer, indicator: number): void {
2970
+ this.opentui.symbols.textBufferViewSetTabIndicator(view, indicator)
2971
+ }
2972
+
2973
+ public textBufferViewSetTabIndicatorColor(view: Pointer, color: RGBA): void {
2974
+ this.opentui.symbols.textBufferViewSetTabIndicatorColor(view, color.buffer)
2975
+ }
2976
+
2977
+ public textBufferViewSetTruncate(view: Pointer, truncate: boolean): void {
2978
+ this.opentui.symbols.textBufferViewSetTruncate(view, truncate)
2979
+ }
2980
+
2981
+ public textBufferViewMeasureForDimensions(
2982
+ view: Pointer,
2983
+ width: number,
2984
+ height: number,
2985
+ ): { lineCount: number; widthColsMax: number } | null {
2986
+ const resultBuffer = new ArrayBuffer(MeasureResultStruct.size)
2987
+ const resultPtr = ptr(new Uint8Array(resultBuffer))
2988
+ const success = this.opentui.symbols.textBufferViewMeasureForDimensions(view, width, height, resultPtr)
2989
+ if (!success) {
2990
+ return null
2991
+ }
2992
+ const result = MeasureResultStruct.unpack(resultBuffer)
2993
+ return result
2994
+ }
2995
+
2996
+ public textBufferAddHighlightByCharRange(buffer: Pointer, highlight: Highlight): void {
2997
+ const packedHighlight = HighlightStruct.pack(highlight)
2998
+ this.opentui.symbols.textBufferAddHighlightByCharRange(buffer, ptr(packedHighlight))
2999
+ }
3000
+
3001
+ public textBufferAddHighlight(buffer: Pointer, lineIdx: number, highlight: Highlight): void {
3002
+ const packedHighlight = HighlightStruct.pack(highlight)
3003
+ this.opentui.symbols.textBufferAddHighlight(buffer, lineIdx, ptr(packedHighlight))
3004
+ }
3005
+
3006
+ public textBufferRemoveHighlightsByRef(buffer: Pointer, hlRef: number): void {
3007
+ this.opentui.symbols.textBufferRemoveHighlightsByRef(buffer, hlRef)
3008
+ }
3009
+
3010
+ public textBufferClearLineHighlights(buffer: Pointer, lineIdx: number): void {
3011
+ this.opentui.symbols.textBufferClearLineHighlights(buffer, lineIdx)
3012
+ }
3013
+
3014
+ public textBufferClearAllHighlights(buffer: Pointer): void {
3015
+ this.opentui.symbols.textBufferClearAllHighlights(buffer)
3016
+ }
3017
+
3018
+ public textBufferSetSyntaxStyle(buffer: Pointer, style: Pointer | null): void {
3019
+ this.opentui.symbols.textBufferSetSyntaxStyle(buffer, style)
3020
+ }
3021
+
3022
+ public textBufferGetLineHighlights(buffer: Pointer, lineIdx: number): Array<Highlight> {
3023
+ const outCountBuf = new BigUint64Array(1)
3024
+
3025
+ const nativePtr = this.opentui.symbols.textBufferGetLineHighlightsPtr(buffer, lineIdx, ptr(outCountBuf))
3026
+ if (!nativePtr) return []
3027
+
3028
+ const count = Number(outCountBuf[0])
3029
+ const byteLen = count * HighlightStruct.size
3030
+ const raw = toArrayBuffer(nativePtr, 0, byteLen)
3031
+ const results = HighlightStruct.unpackList(raw, count)
3032
+
3033
+ this.opentui.symbols.textBufferFreeLineHighlights(nativePtr, count)
3034
+
3035
+ return results
3036
+ }
3037
+
3038
+ public textBufferGetHighlightCount(buffer: Pointer): number {
3039
+ return this.opentui.symbols.textBufferGetHighlightCount(buffer)
3040
+ }
3041
+
3042
+ public getArenaAllocatedBytes(): number {
3043
+ const result = this.opentui.symbols.getArenaAllocatedBytes()
3044
+ return typeof result === "bigint" ? Number(result) : result
3045
+ }
3046
+
3047
+ public getBuildOptions(): BuildOptions {
3048
+ const optionsBuffer = new ArrayBuffer(BuildOptionsStruct.size)
3049
+ this.opentui.symbols.getBuildOptions(ptr(optionsBuffer))
3050
+ const options = BuildOptionsStruct.unpack(optionsBuffer)
3051
+
3052
+ return {
3053
+ gpaSafeStats: !!options.gpaSafeStats,
3054
+ gpaMemoryLimitTracking: !!options.gpaMemoryLimitTracking,
3055
+ }
3056
+ }
3057
+
3058
+ public getAllocatorStats(): AllocatorStats {
3059
+ const statsBuffer = new ArrayBuffer(AllocatorStatsStruct.size)
3060
+ this.opentui.symbols.getAllocatorStats(ptr(statsBuffer))
3061
+ const stats = AllocatorStatsStruct.unpack(statsBuffer)
3062
+
3063
+ return {
3064
+ totalRequestedBytes: toNumber(stats.totalRequestedBytes),
3065
+ activeAllocations: toNumber(stats.activeAllocations),
3066
+ smallAllocations: toNumber(stats.smallAllocations),
3067
+ largeAllocations: toNumber(stats.largeAllocations),
3068
+ requestedBytesValid: !!stats.requestedBytesValid,
3069
+ }
3070
+ }
3071
+
3072
+ public bufferDrawTextBufferView(buffer: Pointer, view: Pointer, x: number, y: number): void {
3073
+ this.opentui.symbols.bufferDrawTextBufferView(buffer, view, x, y)
3074
+ }
3075
+
3076
+ public bufferDrawEditorView(buffer: Pointer, view: Pointer, x: number, y: number): void {
3077
+ this.opentui.symbols.bufferDrawEditorView(buffer, view, x, y)
3078
+ }
3079
+
3080
+ // EditorView methods
3081
+ public createEditorView(editBufferPtr: Pointer, viewportWidth: number, viewportHeight: number): Pointer {
3082
+ const viewPtr = this.opentui.symbols.createEditorView(editBufferPtr, viewportWidth, viewportHeight)
3083
+ if (!viewPtr) {
3084
+ throw new Error("Failed to create EditorView")
3085
+ }
3086
+ return viewPtr
3087
+ }
3088
+
3089
+ public destroyEditorView(view: Pointer): void {
3090
+ this.opentui.symbols.destroyEditorView(view)
3091
+ }
3092
+
3093
+ public editorViewSetViewportSize(view: Pointer, width: number, height: number): void {
3094
+ this.opentui.symbols.editorViewSetViewportSize(view, width, height)
3095
+ }
3096
+
3097
+ public editorViewSetViewport(
3098
+ view: Pointer,
3099
+ x: number,
3100
+ y: number,
3101
+ width: number,
3102
+ height: number,
3103
+ moveCursor: boolean,
3104
+ ): void {
3105
+ this.opentui.symbols.editorViewSetViewport(view, x, y, width, height, moveCursor)
3106
+ }
3107
+
3108
+ public editorViewGetViewport(view: Pointer): { offsetY: number; offsetX: number; height: number; width: number } {
3109
+ const x = new Uint32Array(1)
3110
+ const y = new Uint32Array(1)
3111
+ const width = new Uint32Array(1)
3112
+ const height = new Uint32Array(1)
3113
+
3114
+ this.opentui.symbols.editorViewGetViewport(view, ptr(x), ptr(y), ptr(width), ptr(height))
3115
+
3116
+ return {
3117
+ offsetX: x[0],
3118
+ offsetY: y[0],
3119
+ width: width[0],
3120
+ height: height[0],
3121
+ }
3122
+ }
3123
+
3124
+ public editorViewSetScrollMargin(view: Pointer, margin: number): void {
3125
+ this.opentui.symbols.editorViewSetScrollMargin(view, margin)
3126
+ }
3127
+
3128
+ public editorViewSetWrapMode(view: Pointer, mode: "none" | "char" | "word"): void {
3129
+ const modeValue = mode === "none" ? 0 : mode === "char" ? 1 : 2
3130
+ this.opentui.symbols.editorViewSetWrapMode(view, modeValue)
3131
+ }
3132
+
3133
+ public editorViewGetVirtualLineCount(view: Pointer): number {
3134
+ return this.opentui.symbols.editorViewGetVirtualLineCount(view)
3135
+ }
3136
+
3137
+ public editorViewGetTotalVirtualLineCount(view: Pointer): number {
3138
+ return this.opentui.symbols.editorViewGetTotalVirtualLineCount(view)
3139
+ }
3140
+
3141
+ public editorViewGetTextBufferView(view: Pointer): Pointer {
3142
+ const result = this.opentui.symbols.editorViewGetTextBufferView(view)
3143
+ if (!result) {
3144
+ throw new Error("Failed to get TextBufferView from EditorView")
3145
+ }
3146
+ return result
3147
+ }
3148
+
3149
+ public editorViewGetLineInfo(view: Pointer): LineInfo {
3150
+ const outBuffer = new ArrayBuffer(LineInfoStruct.size)
3151
+ this.opentui.symbols.editorViewGetLineInfoDirect(view, ptr(outBuffer))
3152
+ const struct = LineInfoStruct.unpack(outBuffer)
3153
+
3154
+ const lineStartCols = struct.startCols as number[]
3155
+ const lineWidthCols = struct.widthCols as number[]
3156
+ const lineWidthColsMax = struct.widthColsMax
3157
+
3158
+ return {
3159
+ lineStartCols,
3160
+ lineWidthCols,
3161
+ lineWidthColsMax,
3162
+ lineSources: struct.sources as number[],
3163
+ lineWraps: struct.wraps as number[],
3164
+ }
3165
+ }
3166
+
3167
+ public editorViewGetLogicalLineInfo(view: Pointer): LineInfo {
3168
+ const outBuffer = new ArrayBuffer(LineInfoStruct.size)
3169
+ this.opentui.symbols.editorViewGetLogicalLineInfoDirect(view, ptr(outBuffer))
3170
+ const struct = LineInfoStruct.unpack(outBuffer)
3171
+
3172
+ const lineStartCols = struct.startCols as number[]
3173
+ const lineWidthCols = struct.widthCols as number[]
3174
+ const lineWidthColsMax = struct.widthColsMax
3175
+
3176
+ return {
3177
+ lineStartCols,
3178
+ lineWidthCols,
3179
+ lineWidthColsMax,
3180
+ lineSources: struct.sources as number[],
3181
+ lineWraps: struct.wraps as number[],
3182
+ }
3183
+ }
3184
+
3185
+ // EditBuffer implementations
3186
+ public createEditBuffer(widthMethod: WidthMethod): Pointer {
3187
+ const widthMethodCode = widthMethod === "wcwidth" ? 0 : 1
3188
+ const bufferPtr = this.opentui.symbols.createEditBuffer(widthMethodCode)
3189
+ if (!bufferPtr) {
3190
+ throw new Error("Failed to create EditBuffer")
3191
+ }
3192
+ return bufferPtr
3193
+ }
3194
+
3195
+ public destroyEditBuffer(buffer: Pointer): void {
3196
+ this.opentui.symbols.destroyEditBuffer(buffer)
3197
+ }
3198
+
3199
+ public editBufferSetText(buffer: Pointer, textBytes: Uint8Array): void {
3200
+ this.opentui.symbols.editBufferSetText(buffer, textBytes, textBytes.length)
3201
+ }
3202
+
3203
+ public editBufferSetTextFromMem(buffer: Pointer, memId: number): void {
3204
+ this.opentui.symbols.editBufferSetTextFromMem(buffer, memId)
3205
+ }
3206
+
3207
+ public editBufferReplaceText(buffer: Pointer, textBytes: Uint8Array): void {
3208
+ this.opentui.symbols.editBufferReplaceText(buffer, textBytes, textBytes.length)
3209
+ }
3210
+
3211
+ public editBufferReplaceTextFromMem(buffer: Pointer, memId: number): void {
3212
+ this.opentui.symbols.editBufferReplaceTextFromMem(buffer, memId)
3213
+ }
3214
+
3215
+ public editBufferGetText(buffer: Pointer, maxLength: number): Uint8Array | null {
3216
+ const outBuffer = new Uint8Array(maxLength)
3217
+ const actualLen = this.opentui.symbols.editBufferGetText(buffer, ptr(outBuffer), maxLength)
3218
+ const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen
3219
+ if (len === 0) return null
3220
+ return outBuffer.slice(0, len)
3221
+ }
3222
+
3223
+ public editBufferInsertChar(buffer: Pointer, char: string): void {
3224
+ const charBytes = this.encoder.encode(char)
3225
+ this.opentui.symbols.editBufferInsertChar(buffer, charBytes, charBytes.length)
3226
+ }
3227
+
3228
+ public editBufferInsertText(buffer: Pointer, text: string): void {
3229
+ const textBytes = this.encoder.encode(text)
3230
+ this.opentui.symbols.editBufferInsertText(buffer, textBytes, textBytes.length)
3231
+ }
3232
+
3233
+ public editBufferDeleteChar(buffer: Pointer): void {
3234
+ this.opentui.symbols.editBufferDeleteChar(buffer)
3235
+ }
3236
+
3237
+ public editBufferDeleteCharBackward(buffer: Pointer): void {
3238
+ this.opentui.symbols.editBufferDeleteCharBackward(buffer)
3239
+ }
3240
+
3241
+ public editBufferDeleteRange(
3242
+ buffer: Pointer,
3243
+ startLine: number,
3244
+ startCol: number,
3245
+ endLine: number,
3246
+ endCol: number,
3247
+ ): void {
3248
+ this.opentui.symbols.editBufferDeleteRange(buffer, startLine, startCol, endLine, endCol)
3249
+ }
3250
+
3251
+ public editBufferNewLine(buffer: Pointer): void {
3252
+ this.opentui.symbols.editBufferNewLine(buffer)
3253
+ }
3254
+
3255
+ public editBufferDeleteLine(buffer: Pointer): void {
3256
+ this.opentui.symbols.editBufferDeleteLine(buffer)
3257
+ }
3258
+
3259
+ public editBufferMoveCursorLeft(buffer: Pointer): void {
3260
+ this.opentui.symbols.editBufferMoveCursorLeft(buffer)
3261
+ }
3262
+
3263
+ public editBufferMoveCursorRight(buffer: Pointer): void {
3264
+ this.opentui.symbols.editBufferMoveCursorRight(buffer)
3265
+ }
3266
+
3267
+ public editBufferMoveCursorUp(buffer: Pointer): void {
3268
+ this.opentui.symbols.editBufferMoveCursorUp(buffer)
3269
+ }
3270
+
3271
+ public editBufferMoveCursorDown(buffer: Pointer): void {
3272
+ this.opentui.symbols.editBufferMoveCursorDown(buffer)
3273
+ }
3274
+
3275
+ public editBufferGotoLine(buffer: Pointer, line: number): void {
3276
+ this.opentui.symbols.editBufferGotoLine(buffer, line)
3277
+ }
3278
+
3279
+ public editBufferSetCursor(buffer: Pointer, line: number, byteOffset: number): void {
3280
+ this.opentui.symbols.editBufferSetCursor(buffer, line, byteOffset)
3281
+ }
3282
+
3283
+ public editBufferSetCursorToLineCol(buffer: Pointer, line: number, col: number): void {
3284
+ this.opentui.symbols.editBufferSetCursorToLineCol(buffer, line, col)
3285
+ }
3286
+
3287
+ public editBufferSetCursorByOffset(buffer: Pointer, offset: number): void {
3288
+ this.opentui.symbols.editBufferSetCursorByOffset(buffer, offset)
3289
+ }
3290
+
3291
+ public editBufferGetCursorPosition(buffer: Pointer): LogicalCursor {
3292
+ const cursorBuffer = new ArrayBuffer(LogicalCursorStruct.size)
3293
+ this.opentui.symbols.editBufferGetCursorPosition(buffer, ptr(cursorBuffer))
3294
+ return LogicalCursorStruct.unpack(cursorBuffer)
3295
+ }
3296
+
3297
+ public editBufferGetId(buffer: Pointer): number {
3298
+ return this.opentui.symbols.editBufferGetId(buffer)
3299
+ }
3300
+
3301
+ public editBufferGetTextBuffer(buffer: Pointer): Pointer {
3302
+ const result = this.opentui.symbols.editBufferGetTextBuffer(buffer)
3303
+ if (!result) {
3304
+ throw new Error("Failed to get TextBuffer from EditBuffer")
3305
+ }
3306
+ return result
3307
+ }
3308
+
3309
+ public editBufferDebugLogRope(buffer: Pointer): void {
3310
+ this.opentui.symbols.editBufferDebugLogRope(buffer)
3311
+ }
3312
+
3313
+ public editBufferUndo(buffer: Pointer, maxLength: number): Uint8Array | null {
3314
+ const outBuffer = new Uint8Array(maxLength)
3315
+ const actualLen = this.opentui.symbols.editBufferUndo(buffer, ptr(outBuffer), maxLength)
3316
+ const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen
3317
+ if (len === 0) return null
3318
+ return outBuffer.slice(0, len)
3319
+ }
3320
+
3321
+ public editBufferRedo(buffer: Pointer, maxLength: number): Uint8Array | null {
3322
+ const outBuffer = new Uint8Array(maxLength)
3323
+ const actualLen = this.opentui.symbols.editBufferRedo(buffer, ptr(outBuffer), maxLength)
3324
+ const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen
3325
+ if (len === 0) return null
3326
+ return outBuffer.slice(0, len)
3327
+ }
3328
+
3329
+ public editBufferCanUndo(buffer: Pointer): boolean {
3330
+ return this.opentui.symbols.editBufferCanUndo(buffer)
3331
+ }
3332
+
3333
+ public editBufferCanRedo(buffer: Pointer): boolean {
3334
+ return this.opentui.symbols.editBufferCanRedo(buffer)
3335
+ }
3336
+
3337
+ public editBufferClearHistory(buffer: Pointer): void {
3338
+ this.opentui.symbols.editBufferClearHistory(buffer)
3339
+ }
3340
+
3341
+ public editBufferClear(buffer: Pointer): void {
3342
+ this.opentui.symbols.editBufferClear(buffer)
3343
+ }
3344
+
3345
+ public editBufferGetNextWordBoundary(buffer: Pointer): LogicalCursor {
3346
+ const cursorBuffer = new ArrayBuffer(LogicalCursorStruct.size)
3347
+ this.opentui.symbols.editBufferGetNextWordBoundary(buffer, ptr(cursorBuffer))
3348
+ return LogicalCursorStruct.unpack(cursorBuffer)
3349
+ }
3350
+
3351
+ public editBufferGetPrevWordBoundary(buffer: Pointer): LogicalCursor {
3352
+ const cursorBuffer = new ArrayBuffer(LogicalCursorStruct.size)
3353
+ this.opentui.symbols.editBufferGetPrevWordBoundary(buffer, ptr(cursorBuffer))
3354
+ return LogicalCursorStruct.unpack(cursorBuffer)
3355
+ }
3356
+
3357
+ public editBufferGetEOL(buffer: Pointer): LogicalCursor {
3358
+ const cursorBuffer = new ArrayBuffer(LogicalCursorStruct.size)
3359
+ this.opentui.symbols.editBufferGetEOL(buffer, ptr(cursorBuffer))
3360
+ return LogicalCursorStruct.unpack(cursorBuffer)
3361
+ }
3362
+
3363
+ public editBufferOffsetToPosition(buffer: Pointer, offset: number): LogicalCursor | null {
3364
+ const cursorBuffer = new ArrayBuffer(LogicalCursorStruct.size)
3365
+ const success = this.opentui.symbols.editBufferOffsetToPosition(buffer, offset, ptr(cursorBuffer))
3366
+ if (!success) return null
3367
+ return LogicalCursorStruct.unpack(cursorBuffer)
3368
+ }
3369
+
3370
+ public editBufferPositionToOffset(buffer: Pointer, row: number, col: number): number {
3371
+ return this.opentui.symbols.editBufferPositionToOffset(buffer, row, col)
3372
+ }
3373
+
3374
+ public editBufferGetLineStartOffset(buffer: Pointer, row: number): number {
3375
+ return this.opentui.symbols.editBufferGetLineStartOffset(buffer, row)
3376
+ }
3377
+
3378
+ public editBufferGetTextRange(
3379
+ buffer: Pointer,
3380
+ startOffset: number,
3381
+ endOffset: number,
3382
+ maxLength: number,
3383
+ ): Uint8Array | null {
3384
+ const outBuffer = new Uint8Array(maxLength)
3385
+ const actualLen = this.opentui.symbols.editBufferGetTextRange(
3386
+ buffer,
3387
+ startOffset,
3388
+ endOffset,
3389
+ ptr(outBuffer),
3390
+ maxLength,
3391
+ )
3392
+ const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen
3393
+ if (len === 0) return null
3394
+ return outBuffer.slice(0, len)
3395
+ }
3396
+
3397
+ public editBufferGetTextRangeByCoords(
3398
+ buffer: Pointer,
3399
+ startRow: number,
3400
+ startCol: number,
3401
+ endRow: number,
3402
+ endCol: number,
3403
+ maxLength: number,
3404
+ ): Uint8Array | null {
3405
+ const outBuffer = new Uint8Array(maxLength)
3406
+ const actualLen = this.opentui.symbols.editBufferGetTextRangeByCoords(
3407
+ buffer,
3408
+ startRow,
3409
+ startCol,
3410
+ endRow,
3411
+ endCol,
3412
+ ptr(outBuffer),
3413
+ maxLength,
3414
+ )
3415
+ const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen
3416
+ if (len === 0) return null
3417
+ return outBuffer.slice(0, len)
3418
+ }
3419
+
3420
+ // EditorView selection and editing implementations
3421
+ public editorViewSetSelection(
3422
+ view: Pointer,
3423
+ start: number,
3424
+ end: number,
3425
+ bgColor: RGBA | null,
3426
+ fgColor: RGBA | null,
3427
+ ): void {
3428
+ const bg = bgColor ? bgColor.buffer : null
3429
+ const fg = fgColor ? fgColor.buffer : null
3430
+ this.opentui.symbols.editorViewSetSelection(view, start, end, bg, fg)
3431
+ }
3432
+
3433
+ public editorViewResetSelection(view: Pointer): void {
3434
+ this.opentui.symbols.editorViewResetSelection(view)
3435
+ }
3436
+
3437
+ public editorViewGetSelection(view: Pointer): { start: number; end: number } | null {
3438
+ const packedInfo = this.opentui.symbols.editorViewGetSelection(view)
3439
+ if (packedInfo === 0xffff_ffff_ffff_ffffn) {
3440
+ return null
3441
+ }
3442
+ const start = Number(packedInfo >> 32n)
3443
+ const end = Number(packedInfo & 0xffff_ffffn)
3444
+ return { start, end }
3445
+ }
3446
+
3447
+ public editorViewSetLocalSelection(
3448
+ view: Pointer,
3449
+ anchorX: number,
3450
+ anchorY: number,
3451
+ focusX: number,
3452
+ focusY: number,
3453
+ bgColor: RGBA | null,
3454
+ fgColor: RGBA | null,
3455
+ updateCursor: boolean,
3456
+ followCursor: boolean,
3457
+ ): boolean {
3458
+ const bg = bgColor ? bgColor.buffer : null
3459
+ const fg = fgColor ? fgColor.buffer : null
3460
+ return this.opentui.symbols.editorViewSetLocalSelection(
3461
+ view,
3462
+ anchorX,
3463
+ anchorY,
3464
+ focusX,
3465
+ focusY,
3466
+ bg,
3467
+ fg,
3468
+ updateCursor,
3469
+ followCursor,
3470
+ )
3471
+ }
3472
+
3473
+ public editorViewUpdateSelection(view: Pointer, end: number, bgColor: RGBA | null, fgColor: RGBA | null): void {
3474
+ const bg = bgColor ? bgColor.buffer : null
3475
+ const fg = fgColor ? fgColor.buffer : null
3476
+ this.opentui.symbols.editorViewUpdateSelection(view, end, bg, fg)
3477
+ }
3478
+
3479
+ public editorViewUpdateLocalSelection(
3480
+ view: Pointer,
3481
+ anchorX: number,
3482
+ anchorY: number,
3483
+ focusX: number,
3484
+ focusY: number,
3485
+ bgColor: RGBA | null,
3486
+ fgColor: RGBA | null,
3487
+ updateCursor: boolean,
3488
+ followCursor: boolean,
3489
+ ): boolean {
3490
+ const bg = bgColor ? bgColor.buffer : null
3491
+ const fg = fgColor ? fgColor.buffer : null
3492
+ return this.opentui.symbols.editorViewUpdateLocalSelection(
3493
+ view,
3494
+ anchorX,
3495
+ anchorY,
3496
+ focusX,
3497
+ focusY,
3498
+ bg,
3499
+ fg,
3500
+ updateCursor,
3501
+ followCursor,
3502
+ )
3503
+ }
3504
+
3505
+ public editorViewResetLocalSelection(view: Pointer): void {
3506
+ this.opentui.symbols.editorViewResetLocalSelection(view)
3507
+ }
3508
+
3509
+ public editorViewGetSelectedTextBytes(view: Pointer, maxLength: number): Uint8Array | null {
3510
+ const outBuffer = new Uint8Array(maxLength)
3511
+ const actualLen = this.opentui.symbols.editorViewGetSelectedTextBytes(view, ptr(outBuffer), maxLength)
3512
+ const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen
3513
+ if (len === 0) return null
3514
+ return outBuffer.slice(0, len)
3515
+ }
3516
+
3517
+ public editorViewGetCursor(view: Pointer): { row: number; col: number } {
3518
+ const row = new Uint32Array(1)
3519
+ const col = new Uint32Array(1)
3520
+ this.opentui.symbols.editorViewGetCursor(view, ptr(row), ptr(col))
3521
+ return { row: row[0], col: col[0] }
3522
+ }
3523
+
3524
+ public editorViewGetText(view: Pointer, maxLength: number): Uint8Array | null {
3525
+ const outBuffer = new Uint8Array(maxLength)
3526
+ const actualLen = this.opentui.symbols.editorViewGetText(view, ptr(outBuffer), maxLength)
3527
+ const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen
3528
+ if (len === 0) return null
3529
+ return outBuffer.slice(0, len)
3530
+ }
3531
+
3532
+ public editorViewGetVisualCursor(view: Pointer): VisualCursor {
3533
+ const cursorBuffer = new ArrayBuffer(VisualCursorStruct.size)
3534
+ this.opentui.symbols.editorViewGetVisualCursor(view, ptr(cursorBuffer))
3535
+ return VisualCursorStruct.unpack(cursorBuffer)
3536
+ }
3537
+
3538
+ public editorViewMoveUpVisual(view: Pointer): void {
3539
+ this.opentui.symbols.editorViewMoveUpVisual(view)
3540
+ }
3541
+
3542
+ public editorViewMoveDownVisual(view: Pointer): void {
3543
+ this.opentui.symbols.editorViewMoveDownVisual(view)
3544
+ }
3545
+
3546
+ public editorViewDeleteSelectedText(view: Pointer): void {
3547
+ this.opentui.symbols.editorViewDeleteSelectedText(view)
3548
+ }
3549
+
3550
+ public editorViewSetCursorByOffset(view: Pointer, offset: number): void {
3551
+ this.opentui.symbols.editorViewSetCursorByOffset(view, offset)
3552
+ }
3553
+
3554
+ public editorViewGetNextWordBoundary(view: Pointer): VisualCursor {
3555
+ const cursorBuffer = new ArrayBuffer(VisualCursorStruct.size)
3556
+ this.opentui.symbols.editorViewGetNextWordBoundary(view, ptr(cursorBuffer))
3557
+ return VisualCursorStruct.unpack(cursorBuffer)
3558
+ }
3559
+
3560
+ public editorViewGetPrevWordBoundary(view: Pointer): VisualCursor {
3561
+ const cursorBuffer = new ArrayBuffer(VisualCursorStruct.size)
3562
+ this.opentui.symbols.editorViewGetPrevWordBoundary(view, ptr(cursorBuffer))
3563
+ return VisualCursorStruct.unpack(cursorBuffer)
3564
+ }
3565
+
3566
+ public editorViewGetEOL(view: Pointer): VisualCursor {
3567
+ const cursorBuffer = new ArrayBuffer(VisualCursorStruct.size)
3568
+ this.opentui.symbols.editorViewGetEOL(view, ptr(cursorBuffer))
3569
+ return VisualCursorStruct.unpack(cursorBuffer)
3570
+ }
3571
+
3572
+ public editorViewGetVisualSOL(view: Pointer): VisualCursor {
3573
+ const cursorBuffer = new ArrayBuffer(VisualCursorStruct.size)
3574
+ this.opentui.symbols.editorViewGetVisualSOL(view, ptr(cursorBuffer))
3575
+ return VisualCursorStruct.unpack(cursorBuffer)
3576
+ }
3577
+
3578
+ public editorViewGetVisualEOL(view: Pointer): VisualCursor {
3579
+ const cursorBuffer = new ArrayBuffer(VisualCursorStruct.size)
3580
+ this.opentui.symbols.editorViewGetVisualEOL(view, ptr(cursorBuffer))
3581
+ return VisualCursorStruct.unpack(cursorBuffer)
3582
+ }
3583
+
3584
+ public bufferPushScissorRect(buffer: Pointer, x: number, y: number, width: number, height: number): void {
3585
+ this.opentui.symbols.bufferPushScissorRect(buffer, x, y, width, height)
3586
+ }
3587
+
3588
+ public bufferPopScissorRect(buffer: Pointer): void {
3589
+ this.opentui.symbols.bufferPopScissorRect(buffer)
3590
+ }
3591
+
3592
+ public bufferClearScissorRects(buffer: Pointer): void {
3593
+ this.opentui.symbols.bufferClearScissorRects(buffer)
3594
+ }
3595
+
3596
+ public bufferPushOpacity(buffer: Pointer, opacity: number): void {
3597
+ this.opentui.symbols.bufferPushOpacity(buffer, opacity)
3598
+ }
3599
+
3600
+ public bufferPopOpacity(buffer: Pointer): void {
3601
+ this.opentui.symbols.bufferPopOpacity(buffer)
3602
+ }
3603
+
3604
+ public bufferGetCurrentOpacity(buffer: Pointer): number {
3605
+ return this.opentui.symbols.bufferGetCurrentOpacity(buffer)
3606
+ }
3607
+
3608
+ public bufferClearOpacity(buffer: Pointer): void {
3609
+ this.opentui.symbols.bufferClearOpacity(buffer)
3610
+ }
3611
+
3612
+ public getTerminalCapabilities(renderer: Pointer) {
3613
+ const capsBuffer = new ArrayBuffer(TerminalCapabilitiesStruct.size)
3614
+ this.opentui.symbols.getTerminalCapabilities(renderer, ptr(capsBuffer))
3615
+
3616
+ const caps = TerminalCapabilitiesStruct.unpack(capsBuffer)
3617
+
3618
+ return {
3619
+ kitty_keyboard: caps.kitty_keyboard,
3620
+ kitty_graphics: caps.kitty_graphics,
3621
+ rgb: caps.rgb,
3622
+ unicode: caps.unicode,
3623
+ sgr_pixels: caps.sgr_pixels,
3624
+ color_scheme_updates: caps.color_scheme_updates,
3625
+ explicit_width: caps.explicit_width,
3626
+ scaled_text: caps.scaled_text,
3627
+ sixel: caps.sixel,
3628
+ focus_tracking: caps.focus_tracking,
3629
+ sync: caps.sync,
3630
+ bracketed_paste: caps.bracketed_paste,
3631
+ hyperlinks: caps.hyperlinks,
3632
+ osc52: caps.osc52,
3633
+ explicit_cursor_positioning: caps.explicit_cursor_positioning,
3634
+ terminal: {
3635
+ name: caps.term_name ?? "",
3636
+ version: caps.term_version ?? "",
3637
+ from_xtversion: caps.term_from_xtversion,
3638
+ },
3639
+ }
3640
+ }
3641
+
3642
+ public processCapabilityResponse(renderer: Pointer, response: string): void {
3643
+ const responseBytes = this.encoder.encode(response)
3644
+ this.opentui.symbols.processCapabilityResponse(renderer, responseBytes, responseBytes.length)
3645
+ }
3646
+
3647
+ public encodeUnicode(
3648
+ text: string,
3649
+ widthMethod: WidthMethod,
3650
+ ): { ptr: Pointer; data: Array<{ width: number; char: number }> } | null {
3651
+ const textBytes = this.encoder.encode(text)
3652
+ const widthMethodCode = widthMethod === "wcwidth" ? 0 : 1
3653
+
3654
+ const outPtrBuffer = new ArrayBuffer(8) // Pointer size
3655
+ const outLenBuffer = new ArrayBuffer(8) // usize
3656
+
3657
+ const success = this.opentui.symbols.encodeUnicode(
3658
+ textBytes,
3659
+ textBytes.length,
3660
+ ptr(outPtrBuffer),
3661
+ ptr(outLenBuffer),
3662
+ widthMethodCode,
3663
+ )
3664
+
3665
+ if (!success) {
3666
+ return null
3667
+ }
3668
+
3669
+ const outPtrView = new BigUint64Array(outPtrBuffer)
3670
+ const outLenView = new BigUint64Array(outLenBuffer)
3671
+
3672
+ const resultPtr = Number(outPtrView[0]) as Pointer
3673
+ const resultLen = Number(outLenView[0])
3674
+
3675
+ if (resultLen === 0) {
3676
+ return { ptr: resultPtr, data: [] }
3677
+ }
3678
+
3679
+ // Convert pointer to ArrayBuffer and use EncodedCharStruct to unpack the list
3680
+ const byteLen = resultLen * EncodedCharStruct.size
3681
+ const raw = toArrayBuffer(resultPtr, 0, byteLen)
3682
+ const data = EncodedCharStruct.unpackList(raw, resultLen)
3683
+
3684
+ return { ptr: resultPtr, data }
3685
+ }
3686
+
3687
+ public freeUnicode(encoded: { ptr: Pointer; data: Array<{ width: number; char: number }> }): void {
3688
+ this.opentui.symbols.freeUnicode(encoded.ptr, encoded.data.length)
3689
+ }
3690
+
3691
+ public bufferDrawChar(
3692
+ buffer: Pointer,
3693
+ char: number,
3694
+ x: number,
3695
+ y: number,
3696
+ fg: RGBA,
3697
+ bg: RGBA,
3698
+ attributes: number = 0,
3699
+ ): void {
3700
+ this.opentui.symbols.bufferDrawChar(buffer, char, x, y, fg.buffer, bg.buffer, attributes)
3701
+ }
3702
+
3703
+ public registerNativeSpanFeedStream(stream: Pointer, handler: NativeSpanFeedEventHandler): void {
3704
+ const callback = this.ensureNativeSpanFeedCallback()
3705
+ this.nativeSpanFeedHandlers.set(toPointer(stream), handler)
3706
+ this.opentui.symbols.streamSetCallback(stream, callback.ptr)
3707
+ }
3708
+
3709
+ public unregisterNativeSpanFeedStream(stream: Pointer): void {
3710
+ this.opentui.symbols.streamSetCallback(stream, null)
3711
+ this.nativeSpanFeedHandlers.delete(toPointer(stream))
3712
+ }
3713
+
3714
+ public createNativeSpanFeed(options?: NativeSpanFeedOptions | null): Pointer {
3715
+ const optionsBuffer = options == null ? null : NativeSpanFeedOptionsStruct.pack(options)
3716
+ const streamPtr = this.opentui.symbols.createNativeSpanFeed(optionsBuffer ? ptr(optionsBuffer) : null)
3717
+ if (!streamPtr) {
3718
+ throw new Error("Failed to create stream")
3719
+ }
3720
+ return toPointer(streamPtr)
3721
+ }
3722
+
3723
+ public attachNativeSpanFeed(stream: Pointer): number {
3724
+ return this.opentui.symbols.attachNativeSpanFeed(stream)
3725
+ }
3726
+
3727
+ public destroyNativeSpanFeed(stream: Pointer): void {
3728
+ this.opentui.symbols.destroyNativeSpanFeed(stream)
3729
+ this.nativeSpanFeedHandlers.delete(toPointer(stream))
3730
+ }
3731
+
3732
+ public streamWrite(stream: Pointer, data: Uint8Array | string): number {
3733
+ const bytes = typeof data === "string" ? this.encoder.encode(data) : data
3734
+ return this.opentui.symbols.streamWrite(stream, ptr(bytes), bytes.length)
3735
+ }
3736
+
3737
+ public streamCommit(stream: Pointer): number {
3738
+ return this.opentui.symbols.streamCommit(stream)
3739
+ }
3740
+
3741
+ public streamDrainSpans(stream: Pointer, outBuffer: Uint8Array, maxSpans: number): number {
3742
+ const count = this.opentui.symbols.streamDrainSpans(stream, ptr(outBuffer), maxSpans)
3743
+ return toNumber(count)
3744
+ }
3745
+
3746
+ public streamClose(stream: Pointer): number {
3747
+ return this.opentui.symbols.streamClose(stream)
3748
+ }
3749
+
3750
+ public streamSetOptions(stream: Pointer, options: NativeSpanFeedOptions): number {
3751
+ const optionsBuffer = NativeSpanFeedOptionsStruct.pack(options)
3752
+ return this.opentui.symbols.streamSetOptions(stream, ptr(optionsBuffer))
3753
+ }
3754
+
3755
+ public streamGetStats(stream: Pointer): NativeSpanFeedStats | null {
3756
+ const statsBuffer = new ArrayBuffer(NativeSpanFeedStatsStruct.size)
3757
+ const status = this.opentui.symbols.streamGetStats(stream, ptr(statsBuffer))
3758
+ if (status !== 0) {
3759
+ return null
3760
+ }
3761
+ const stats = NativeSpanFeedStatsStruct.unpack(statsBuffer)
3762
+ return {
3763
+ bytesWritten: typeof stats.bytesWritten === "bigint" ? stats.bytesWritten : BigInt(stats.bytesWritten),
3764
+ spansCommitted: typeof stats.spansCommitted === "bigint" ? stats.spansCommitted : BigInt(stats.spansCommitted),
3765
+ chunks: stats.chunks,
3766
+ pendingSpans: stats.pendingSpans,
3767
+ }
3768
+ }
3769
+
3770
+ public streamReserve(stream: Pointer, minLen: number): { status: number; info: ReserveInfo | null } {
3771
+ const reserveBuffer = new ArrayBuffer(ReserveInfoStruct.size)
3772
+ const status = this.opentui.symbols.streamReserve(stream, minLen, ptr(reserveBuffer))
3773
+ if (status !== 0) {
3774
+ return { status, info: null }
3775
+ }
3776
+ return { status, info: ReserveInfoStruct.unpack(reserveBuffer) }
3777
+ }
3778
+
3779
+ public streamCommitReserved(stream: Pointer, length: number): number {
3780
+ return this.opentui.symbols.streamCommitReserved(stream, length)
3781
+ }
3782
+
3783
+ public createSyntaxStyle(): Pointer {
3784
+ const stylePtr = this.opentui.symbols.createSyntaxStyle()
3785
+ if (!stylePtr) {
3786
+ throw new Error("Failed to create SyntaxStyle")
3787
+ }
3788
+ return stylePtr
3789
+ }
3790
+
3791
+ public destroySyntaxStyle(style: Pointer): void {
3792
+ this.opentui.symbols.destroySyntaxStyle(style)
3793
+ }
3794
+
3795
+ public syntaxStyleRegister(
3796
+ style: Pointer,
3797
+ name: string,
3798
+ fg: RGBA | null,
3799
+ bg: RGBA | null,
3800
+ attributes: number,
3801
+ ): number {
3802
+ const nameBytes = this.encoder.encode(name)
3803
+ const fgPtr = fg ? fg.buffer : null
3804
+ const bgPtr = bg ? bg.buffer : null
3805
+ return this.opentui.symbols.syntaxStyleRegister(style, nameBytes, nameBytes.length, fgPtr, bgPtr, attributes)
3806
+ }
3807
+
3808
+ public syntaxStyleResolveByName(style: Pointer, name: string): number | null {
3809
+ const nameBytes = this.encoder.encode(name)
3810
+ const id = this.opentui.symbols.syntaxStyleResolveByName(style, nameBytes, nameBytes.length)
3811
+ return id === 0 ? null : id
3812
+ }
3813
+
3814
+ public syntaxStyleGetStyleCount(style: Pointer): number {
3815
+ const result = this.opentui.symbols.syntaxStyleGetStyleCount(style)
3816
+ return typeof result === "bigint" ? Number(result) : result
3817
+ }
3818
+
3819
+ public editorViewSetPlaceholderStyledText(
3820
+ view: Pointer,
3821
+ chunks: Array<{ text: string; fg?: RGBA | null; bg?: RGBA | null; attributes?: number }>,
3822
+ ): void {
3823
+ const nonEmptyChunks = chunks.filter((c) => c.text.length > 0)
3824
+ if (nonEmptyChunks.length === 0) {
3825
+ this.opentui.symbols.editorViewSetPlaceholderStyledText(view, null, 0)
3826
+ return
3827
+ }
3828
+
3829
+ const chunksBuffer = StyledChunkStruct.packList(nonEmptyChunks)
3830
+ this.opentui.symbols.editorViewSetPlaceholderStyledText(view, ptr(chunksBuffer), nonEmptyChunks.length)
3831
+ }
3832
+
3833
+ public editorViewSetTabIndicator(view: Pointer, indicator: number): void {
3834
+ this.opentui.symbols.editorViewSetTabIndicator(view, indicator)
3835
+ }
3836
+
3837
+ public editorViewSetTabIndicatorColor(view: Pointer, color: RGBA): void {
3838
+ this.opentui.symbols.editorViewSetTabIndicatorColor(view, color.buffer)
3839
+ }
3840
+
3841
+ public onNativeEvent(name: string, handler: (data: ArrayBuffer) => void): void {
3842
+ this._nativeEvents.on(name, handler)
3843
+ }
3844
+
3845
+ public onceNativeEvent(name: string, handler: (data: ArrayBuffer) => void): void {
3846
+ this._nativeEvents.once(name, handler)
3847
+ }
3848
+
3849
+ public offNativeEvent(name: string, handler: (data: ArrayBuffer) => void): void {
3850
+ this._nativeEvents.off(name, handler)
3851
+ }
3852
+
3853
+ public onAnyNativeEvent(handler: (name: string, data: ArrayBuffer) => void): void {
3854
+ this._anyEventHandlers.push(handler)
3855
+ }
3856
+ }
3857
+
3858
+ let opentuiLibPath: string | undefined
3859
+ let opentuiLib: RenderLib | undefined
3860
+
3861
+ export function setRenderLibPath(libPath: string) {
3862
+ if (opentuiLibPath !== libPath) {
3863
+ opentuiLibPath = libPath
3864
+ opentuiLib = undefined
3865
+ }
3866
+ }
3867
+
3868
+ export function resolveRenderLib(): RenderLib {
3869
+ if (!opentuiLib) {
3870
+ try {
3871
+ opentuiLib = new FFIRenderLib(opentuiLibPath)
3872
+ } catch (error) {
3873
+ throw new Error(
3874
+ `Failed to initialize OpenTUI render library: ${error instanceof Error ? error.message : "Unknown error"}`,
3875
+ )
3876
+ }
3877
+ }
3878
+ return opentuiLib
3879
+ }
3880
+
3881
+ // Try eager loading
3882
+ try {
3883
+ opentuiLib = new FFIRenderLib(opentuiLibPath)
3884
+ } catch (error) {}