@xincli/opentui-core 0.4.6

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 (476) hide show
  1. package/README.md +63 -0
  2. package/dev/keypress-debug-renderer.ts +148 -0
  3. package/dev/keypress-debug.ts +43 -0
  4. package/dev/print-env-vars.ts +32 -0
  5. package/dev/test-tmux-graphics-334.sh +68 -0
  6. package/dev/test-tmux-theme-queries.sh +151 -0
  7. package/dev/thai-debug-test.ts +68 -0
  8. package/dev/theme-mode.ts +290 -0
  9. package/docs/development.md +144 -0
  10. package/package.json +102 -0
  11. package/prebuilt/aarch64-android/libopentui.so +0 -0
  12. package/scripts/build-android.ts +226 -0
  13. package/scripts/build-native-termux.sh +525 -0
  14. package/scripts/build.ts +530 -0
  15. package/scripts/dist-test.ts +312 -0
  16. package/scripts/package-prebuilt.ts +110 -0
  17. package/scripts/publish.ts +60 -0
  18. package/scripts/test-node-hook.mjs +16 -0
  19. package/scripts/test-node.ts +241 -0
  20. package/scripts/vendor-deps.sh +73 -0
  21. package/src/NativeSpanFeed.ts +375 -0
  22. package/src/Renderable.ts +1878 -0
  23. package/src/__snapshots__/buffer.test.ts.snap +28 -0
  24. package/src/animation/Timeline.test.ts +2709 -0
  25. package/src/animation/Timeline.ts +598 -0
  26. package/src/ansi.ts +22 -0
  27. package/src/audio.ts +479 -0
  28. package/src/benchmark/attenuation-benchmark.ts +81 -0
  29. package/src/benchmark/audio-playback-benchmark.ts +344 -0
  30. package/src/benchmark/box-draw-benchmark.ts +1042 -0
  31. package/src/benchmark/colormatrix-benchmark.ts +123 -0
  32. package/src/benchmark/gain-benchmark.ts +80 -0
  33. package/src/benchmark/latest-all-bench-run.json +707 -0
  34. package/src/benchmark/latest-async-bench-run.json +336 -0
  35. package/src/benchmark/latest-default-bench-run.json +657 -0
  36. package/src/benchmark/latest-large-bench-run.json +707 -0
  37. package/src/benchmark/latest-quick-bench-run.json +207 -0
  38. package/src/benchmark/layout-benchmark.ts +2547 -0
  39. package/src/benchmark/markdown-benchmark.ts +1796 -0
  40. package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
  41. package/src/benchmark/native-span-feed-benchmark.md +56 -0
  42. package/src/benchmark/native-span-feed-benchmark.ts +596 -0
  43. package/src/benchmark/native-span-feed-compare.ts +280 -0
  44. package/src/benchmark/render-traversal-benchmark.ts +928 -0
  45. package/src/benchmark/text-buffer-render-benchmark.ts +874 -0
  46. package/src/benchmark/text-table-benchmark.ts +948 -0
  47. package/src/buffer.test.ts +292 -0
  48. package/src/buffer.ts +564 -0
  49. package/src/console.test.ts +629 -0
  50. package/src/console.ts +1253 -0
  51. package/src/edit-buffer.test.ts +1852 -0
  52. package/src/edit-buffer.ts +417 -0
  53. package/src/editor-view.test.ts +1056 -0
  54. package/src/editor-view.ts +290 -0
  55. package/src/index.ts +25 -0
  56. package/src/lib/KeyHandler.integration.test.ts +292 -0
  57. package/src/lib/KeyHandler.stopPropagation.test.ts +289 -0
  58. package/src/lib/KeyHandler.test.ts +662 -0
  59. package/src/lib/KeyHandler.ts +222 -0
  60. package/src/lib/RGBA.test.ts +60 -0
  61. package/src/lib/RGBA.ts +343 -0
  62. package/src/lib/ascii.font.ts +330 -0
  63. package/src/lib/border.test.ts +83 -0
  64. package/src/lib/border.ts +170 -0
  65. package/src/lib/bunfs.test.ts +27 -0
  66. package/src/lib/bunfs.ts +18 -0
  67. package/src/lib/clipboard.test.ts +63 -0
  68. package/src/lib/clipboard.ts +41 -0
  69. package/src/lib/clock.ts +35 -0
  70. package/src/lib/data-paths.test.ts +133 -0
  71. package/src/lib/data-paths.ts +109 -0
  72. package/src/lib/debounce.ts +106 -0
  73. package/src/lib/detect-links.test.ts +98 -0
  74. package/src/lib/detect-links.ts +56 -0
  75. package/src/lib/env.test.ts +228 -0
  76. package/src/lib/env.ts +209 -0
  77. package/src/lib/extmarks-history.ts +51 -0
  78. package/src/lib/extmarks-multiwidth.test.ts +324 -0
  79. package/src/lib/extmarks.test.ts +3547 -0
  80. package/src/lib/extmarks.ts +861 -0
  81. package/src/lib/fonts/block.json +405 -0
  82. package/src/lib/fonts/grid.json +265 -0
  83. package/src/lib/fonts/huge.json +741 -0
  84. package/src/lib/fonts/pallet.json +314 -0
  85. package/src/lib/fonts/shade.json +591 -0
  86. package/src/lib/fonts/slick.json +321 -0
  87. package/src/lib/fonts/tiny.json +69 -0
  88. package/src/lib/hast-styled-text.ts +59 -0
  89. package/src/lib/index.ts +22 -0
  90. package/src/lib/keybinding.internal.test.ts +342 -0
  91. package/src/lib/keybinding.internal.ts +182 -0
  92. package/src/lib/objects-in-viewport.test.ts +789 -0
  93. package/src/lib/objects-in-viewport.ts +153 -0
  94. package/src/lib/output.capture.ts +58 -0
  95. package/src/lib/parse.keypress-kitty.protocol.test.ts +347 -0
  96. package/src/lib/parse.keypress-kitty.test.ts +712 -0
  97. package/src/lib/parse.keypress-kitty.ts +470 -0
  98. package/src/lib/parse.keypress.test.ts +2020 -0
  99. package/src/lib/parse.keypress.ts +480 -0
  100. package/src/lib/parse.mouse.test.ts +552 -0
  101. package/src/lib/parse.mouse.ts +232 -0
  102. package/src/lib/paste.ts +18 -0
  103. package/src/lib/queue.ts +65 -0
  104. package/src/lib/render-geometry.ts +36 -0
  105. package/src/lib/renderable.validations.test.ts +87 -0
  106. package/src/lib/renderable.validations.ts +83 -0
  107. package/src/lib/scroll-acceleration.ts +98 -0
  108. package/src/lib/selection.ts +261 -0
  109. package/src/lib/singleton.ts +34 -0
  110. package/src/lib/stdin-parser.test.ts +2439 -0
  111. package/src/lib/stdin-parser.ts +2007 -0
  112. package/src/lib/styled-text.ts +178 -0
  113. package/src/lib/terminal-capability-detection.test.ts +226 -0
  114. package/src/lib/terminal-capability-detection.ts +98 -0
  115. package/src/lib/terminal-palette.test.ts +954 -0
  116. package/src/lib/terminal-palette.ts +441 -0
  117. package/src/lib/tree-sitter/assets/README.md +119 -0
  118. package/src/lib/tree-sitter/assets/javascript/highlights.scm +205 -0
  119. package/src/lib/tree-sitter/assets/javascript/tree-sitter-javascript.wasm +0 -0
  120. package/src/lib/tree-sitter/assets/markdown/highlights.scm +150 -0
  121. package/src/lib/tree-sitter/assets/markdown/injections.scm +27 -0
  122. package/src/lib/tree-sitter/assets/markdown/tree-sitter-markdown.wasm +0 -0
  123. package/src/lib/tree-sitter/assets/markdown_inline/highlights.scm +115 -0
  124. package/src/lib/tree-sitter/assets/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  125. package/src/lib/tree-sitter/assets/typescript/highlights.scm +604 -0
  126. package/src/lib/tree-sitter/assets/typescript/tree-sitter-typescript.wasm +0 -0
  127. package/src/lib/tree-sitter/assets/update.ts +360 -0
  128. package/src/lib/tree-sitter/assets/zig/highlights.scm +284 -0
  129. package/src/lib/tree-sitter/assets/zig/tree-sitter-zig.wasm +0 -0
  130. package/src/lib/tree-sitter/assets.d.ts +9 -0
  131. package/src/lib/tree-sitter/cache.test.ts +291 -0
  132. package/src/lib/tree-sitter/client.test.ts +1434 -0
  133. package/src/lib/tree-sitter/client.ts +847 -0
  134. package/src/lib/tree-sitter/default-parsers.ts +133 -0
  135. package/src/lib/tree-sitter/download-utils.ts +148 -0
  136. package/src/lib/tree-sitter/index.ts +75 -0
  137. package/src/lib/tree-sitter/parser.worker.ts +1098 -0
  138. package/src/lib/tree-sitter/parsers-config.ts +81 -0
  139. package/src/lib/tree-sitter/resolve-ft.test.ts +55 -0
  140. package/src/lib/tree-sitter/resolve-ft.ts +189 -0
  141. package/src/lib/tree-sitter/types.ts +132 -0
  142. package/src/lib/tree-sitter/update-assets.ts +10 -0
  143. package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
  144. package/src/lib/tree-sitter-styled-text.ts +314 -0
  145. package/src/lib/validate-dir-name.ts +55 -0
  146. package/src/lib/yoga.options.test.ts +628 -0
  147. package/src/lib/yoga.options.ts +346 -0
  148. package/src/native-event-worker-repro.test.ts +48 -0
  149. package/src/native-event-worker-repro.worker.ts +9 -0
  150. package/src/native-handle.test.ts +221 -0
  151. package/src/platform/ffi.test.ts +516 -0
  152. package/src/platform/ffi.ts +653 -0
  153. package/src/platform/runtime.test.ts +52 -0
  154. package/src/platform/runtime.ts +121 -0
  155. package/src/platform/test.ts +45 -0
  156. package/src/platform/worker-handler-cleanup.fixture.ts +12 -0
  157. package/src/platform/worker-onmessage-startup.fixture.ts +10 -0
  158. package/src/platform/worker-startup.fixture.ts +9 -0
  159. package/src/platform/worker.node-test.ts +153 -0
  160. package/src/platform/worker.ts +425 -0
  161. package/src/plugins/core-slot.ts +579 -0
  162. package/src/plugins/registry.ts +402 -0
  163. package/src/plugins/types.ts +46 -0
  164. package/src/post/effects.ts +948 -0
  165. package/src/post/filters.ts +512 -0
  166. package/src/post/matrices.ts +288 -0
  167. package/src/renderables/ASCIIFont.ts +219 -0
  168. package/src/renderables/Box.test.ts +474 -0
  169. package/src/renderables/Box.ts +353 -0
  170. package/src/renderables/Code.test.ts +2388 -0
  171. package/src/renderables/Code.ts +555 -0
  172. package/src/renderables/Diff.regression.test.ts +381 -0
  173. package/src/renderables/Diff.test.ts +3212 -0
  174. package/src/renderables/Diff.ts +1278 -0
  175. package/src/renderables/EditBufferRenderable.test.ts +288 -0
  176. package/src/renderables/EditBufferRenderable.ts +1152 -0
  177. package/src/renderables/FrameBuffer.ts +47 -0
  178. package/src/renderables/Input.test.ts +1310 -0
  179. package/src/renderables/Input.ts +273 -0
  180. package/src/renderables/LineNumberRenderable.ts +725 -0
  181. package/src/renderables/Markdown.ts +2144 -0
  182. package/src/renderables/ScrollBar.ts +423 -0
  183. package/src/renderables/ScrollBox.ts +903 -0
  184. package/src/renderables/Select.test.ts +1134 -0
  185. package/src/renderables/Select.ts +535 -0
  186. package/src/renderables/Slider.test.ts +456 -0
  187. package/src/renderables/Slider.ts +342 -0
  188. package/src/renderables/TabSelect.test.ts +238 -0
  189. package/src/renderables/TabSelect.ts +447 -0
  190. package/src/renderables/Text.selection-buffer.test.ts +118 -0
  191. package/src/renderables/Text.test.ts +2662 -0
  192. package/src/renderables/Text.ts +147 -0
  193. package/src/renderables/TextBufferRenderable.ts +504 -0
  194. package/src/renderables/TextNode.test.ts +1137 -0
  195. package/src/renderables/TextNode.ts +379 -0
  196. package/src/renderables/TextTable.test.ts +1411 -0
  197. package/src/renderables/TextTable.ts +1434 -0
  198. package/src/renderables/Textarea.ts +425 -0
  199. package/src/renderables/TimeToFirstDraw.ts +89 -0
  200. package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
  201. package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
  202. package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
  203. package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
  204. package/src/renderables/__tests__/Code.test.ts +55 -0
  205. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
  206. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +827 -0
  207. package/src/renderables/__tests__/LineNumberRenderable.test.ts +1906 -0
  208. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
  209. package/src/renderables/__tests__/Markdown.code-colors.test.ts +288 -0
  210. package/src/renderables/__tests__/Markdown.test.ts +4175 -0
  211. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
  212. package/src/renderables/__tests__/Textarea.buffer.test.ts +683 -0
  213. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
  214. package/src/renderables/__tests__/Textarea.editing.test.ts +2120 -0
  215. package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
  216. package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
  217. package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
  218. package/src/renderables/__tests__/Textarea.keybinding.test.ts +3275 -0
  219. package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
  220. package/src/renderables/__tests__/Textarea.rendering.test.ts +1927 -0
  221. package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
  222. package/src/renderables/__tests__/Textarea.selection.test.ts +1589 -0
  223. package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
  224. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
  225. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
  226. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
  227. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
  228. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
  229. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
  230. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
  231. package/src/renderables/__tests__/markdown-parser.test.ts +241 -0
  232. package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
  233. package/src/renderables/composition/README.md +8 -0
  234. package/src/renderables/composition/VRenderable.ts +32 -0
  235. package/src/renderables/composition/constructs.ts +127 -0
  236. package/src/renderables/composition/vnode.ts +277 -0
  237. package/src/renderables/index.ts +23 -0
  238. package/src/renderables/markdown-parser.ts +79 -0
  239. package/src/renderer-theme-mode.ts +199 -0
  240. package/src/renderer.ts +4975 -0
  241. package/src/runtime-plugin-support-configure.ts +63 -0
  242. package/src/runtime-plugin-support.ts +13 -0
  243. package/src/runtime-plugin.ts +626 -0
  244. package/src/specs/terminal-startup.md +64 -0
  245. package/src/syntax-style.test.ts +841 -0
  246. package/src/syntax-style.ts +274 -0
  247. package/src/testing/README.md +219 -0
  248. package/src/testing/bun-test-node.ts +880 -0
  249. package/src/testing/capture-spans.test.ts +216 -0
  250. package/src/testing/integration.test.ts +276 -0
  251. package/src/testing/manual-clock.ts +117 -0
  252. package/src/testing/mock-keys.test.ts +1378 -0
  253. package/src/testing/mock-keys.ts +457 -0
  254. package/src/testing/mock-mouse.test.ts +218 -0
  255. package/src/testing/mock-mouse.ts +247 -0
  256. package/src/testing/mock-tree-sitter-client.ts +81 -0
  257. package/src/testing/spy.ts +13 -0
  258. package/src/testing/terminal-capabilities.ts +47 -0
  259. package/src/testing/test-recorder.test.ts +410 -0
  260. package/src/testing/test-recorder.ts +133 -0
  261. package/src/testing/test-renderer.ts +375 -0
  262. package/src/testing/test-renderer.wait.test.ts +278 -0
  263. package/src/testing/test-streams.ts +31 -0
  264. package/src/testing.ts +9 -0
  265. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
  266. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
  267. package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
  268. package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
  269. package/src/tests/allocator-stats.test.ts +53 -0
  270. package/src/tests/audio.test.ts +303 -0
  271. package/src/tests/destroy-during-render.test.ts +200 -0
  272. package/src/tests/destroy-on-exit.fixture.ts +36 -0
  273. package/src/tests/destroy-on-exit.test.ts +62 -0
  274. package/src/tests/ffi-borrowed-pointer-callsites.test.ts +153 -0
  275. package/src/tests/hover-cursor.test.ts +98 -0
  276. package/src/tests/native-backed-measurement-lifecycle.test.ts +133 -0
  277. package/src/tests/native-backed-measurement-parity.test.ts +322 -0
  278. package/src/tests/native-span-feed-async.test.ts +173 -0
  279. package/src/tests/native-span-feed-close.test.ts +120 -0
  280. package/src/tests/native-span-feed-coverage.test.ts +227 -0
  281. package/src/tests/native-span-feed-edge-cases.test.ts +384 -0
  282. package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
  283. package/src/tests/opacity.test.ts +123 -0
  284. package/src/tests/renderable.snapshot.test.ts +524 -0
  285. package/src/tests/renderable.test.ts +1851 -0
  286. package/src/tests/renderer.clock.test.ts +270 -0
  287. package/src/tests/renderer.console-startup.test.ts +2151 -0
  288. package/src/tests/renderer.control.test.ts +458 -0
  289. package/src/tests/renderer.core-slot-binding.test.ts +962 -0
  290. package/src/tests/renderer.cursor.test.ts +26 -0
  291. package/src/tests/renderer.custom-stdout.test.ts +1112 -0
  292. package/src/tests/renderer.destroy-during-render.test.ts +147 -0
  293. package/src/tests/renderer.focus-restore.test.ts +257 -0
  294. package/src/tests/renderer.focus.test.ts +329 -0
  295. package/src/tests/renderer.idle.test.ts +219 -0
  296. package/src/tests/renderer.input.test.ts +2615 -0
  297. package/src/tests/renderer.kitty-flags.test.ts +195 -0
  298. package/src/tests/renderer.lifecycle.test.ts +34 -0
  299. package/src/tests/renderer.mouse.test.ts +1315 -0
  300. package/src/tests/renderer.notifications.test.ts +27 -0
  301. package/src/tests/renderer.palette.test.ts +1199 -0
  302. package/src/tests/renderer.remote.test.ts +247 -0
  303. package/src/tests/renderer.render-stats.test.ts +146 -0
  304. package/src/tests/renderer.scrollback-surface.test.ts +474 -0
  305. package/src/tests/renderer.selection.test.ts +138 -0
  306. package/src/tests/renderer.slot-registry.test.ts +684 -0
  307. package/src/tests/renderer.tracker.test.ts +202 -0
  308. package/src/tests/renderer.useMouse.test.ts +83 -0
  309. package/src/tests/runtime-plugin-node-modules-cycle.fixture.ts +76 -0
  310. package/src/tests/runtime-plugin-node-modules-import-like-string.fixture.ts +48 -0
  311. package/src/tests/runtime-plugin-node-modules-mjs.fixture.ts +43 -0
  312. package/src/tests/runtime-plugin-node-modules-no-bare-rewrite.fixture.ts +67 -0
  313. package/src/tests/runtime-plugin-node-modules-package-type-cache.fixture.ts +72 -0
  314. package/src/tests/runtime-plugin-node-modules-runtime-specifier.fixture.ts +44 -0
  315. package/src/tests/runtime-plugin-node-modules-scoped-package-bare-rewrite.fixture.ts +85 -0
  316. package/src/tests/runtime-plugin-path-alias.fixture.ts +43 -0
  317. package/src/tests/runtime-plugin-resolve-roots.fixture.ts +65 -0
  318. package/src/tests/runtime-plugin-support-configure.fixture.ts +31 -0
  319. package/src/tests/runtime-plugin-support-late-addition.fixture.ts +17 -0
  320. package/src/tests/runtime-plugin-support.fixture.ts +11 -0
  321. package/src/tests/runtime-plugin-support.test.ts +54 -0
  322. package/src/tests/runtime-plugin-windows-file-url.fixture.ts +30 -0
  323. package/src/tests/runtime-plugin.fixture.ts +40 -0
  324. package/src/tests/runtime-plugin.test.ts +369 -0
  325. package/src/tests/scrollbox-culling-bug.test.ts +114 -0
  326. package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
  327. package/src/tests/scrollbox-hitgrid.test.ts +909 -0
  328. package/src/tests/scrollbox.test.ts +1895 -0
  329. package/src/tests/wrap-resize-perf.test.ts +276 -0
  330. package/src/tests/yoga-api-coverage.test.ts +409 -0
  331. package/src/tests/yoga-callback-stress.test.ts +122 -0
  332. package/src/tests/yoga-ffi.test.ts +117 -0
  333. package/src/tests/yoga-setters.test.ts +921 -0
  334. package/src/tests/yoga-upstream/YGAlignBaselineTest.test.ts +124 -0
  335. package/src/tests/yoga-upstream/YGComputedBorderTest.test.ts +27 -0
  336. package/src/tests/yoga-upstream/YGComputedMarginTest.test.ts +27 -0
  337. package/src/tests/yoga-upstream/YGComputedPaddingTest.test.ts +27 -0
  338. package/src/tests/yoga-upstream/YGDirtiedTest.test.ts +157 -0
  339. package/src/tests/yoga-upstream/YGErrataTest.test.ts +40 -0
  340. package/src/tests/yoga-upstream/YGFlexBasisAuto.test.ts +23 -0
  341. package/src/tests/yoga-upstream/YGHasNewLayout.test.ts +81 -0
  342. package/src/tests/yoga-upstream/YGMeasureCacheTest.test.ts +31 -0
  343. package/src/tests/yoga-upstream/YGMeasureTest.test.ts +70 -0
  344. package/src/tests/yoga-upstream/generated/YGAbsolutePositionTest.test.ts +1864 -0
  345. package/src/tests/yoga-upstream/generated/YGAlignContentTest.test.ts +5829 -0
  346. package/src/tests/yoga-upstream/generated/YGAlignItemsTest.test.ts +2444 -0
  347. package/src/tests/yoga-upstream/generated/YGAlignSelfTest.test.ts +293 -0
  348. package/src/tests/yoga-upstream/generated/YGAndroidNewsFeed.test.ts +315 -0
  349. package/src/tests/yoga-upstream/generated/YGAspectRatioTest.test.ts +231 -0
  350. package/src/tests/yoga-upstream/generated/YGAutoTest.test.ts +347 -0
  351. package/src/tests/yoga-upstream/generated/YGBorderTest.test.ts +256 -0
  352. package/src/tests/yoga-upstream/generated/YGBoxSizingTest.test.ts +2747 -0
  353. package/src/tests/yoga-upstream/generated/YGDimensionTest.test.ts +129 -0
  354. package/src/tests/yoga-upstream/generated/YGDisplayContentsTest.test.ts +109 -0
  355. package/src/tests/yoga-upstream/generated/YGDisplayTest.test.ts +1097 -0
  356. package/src/tests/yoga-upstream/generated/YGFlexDirectionTest.test.ts +4562 -0
  357. package/src/tests/yoga-upstream/generated/YGFlexTest.test.ts +677 -0
  358. package/src/tests/yoga-upstream/generated/YGFlexWrapTest.test.ts +2071 -0
  359. package/src/tests/yoga-upstream/generated/YGGapTest.test.ts +3303 -0
  360. package/src/tests/yoga-upstream/generated/YGIntrinsicSizeTest.test.ts +582 -0
  361. package/src/tests/yoga-upstream/generated/YGJustifyContentTest.test.ts +2150 -0
  362. package/src/tests/yoga-upstream/generated/YGMarginTest.test.ts +1963 -0
  363. package/src/tests/yoga-upstream/generated/YGMinMaxDimensionTest.test.ts +1446 -0
  364. package/src/tests/yoga-upstream/generated/YGPaddingTest.test.ts +354 -0
  365. package/src/tests/yoga-upstream/generated/YGPercentageTest.test.ts +1760 -0
  366. package/src/tests/yoga-upstream/generated/YGRoundingTest.test.ts +1161 -0
  367. package/src/tests/yoga-upstream/generated/YGSizeOverflowTest.test.ts +207 -0
  368. package/src/tests/yoga-upstream/generated/YGStaticPositionTest.test.ts +6338 -0
  369. package/src/tests/yoga-upstream/tools/MeasureCounter.ts +54 -0
  370. package/src/tests/yoga-upstream/tools/utils.ts +81 -0
  371. package/src/text-buffer-view.test.ts +722 -0
  372. package/src/text-buffer-view.ts +193 -0
  373. package/src/text-buffer.test.ts +512 -0
  374. package/src/text-buffer.ts +250 -0
  375. package/src/types.ts +199 -0
  376. package/src/utils.ts +88 -0
  377. package/src/yoga.ts +1146 -0
  378. package/src/zig/ansi.zig +502 -0
  379. package/src/zig/audio.zig +1206 -0
  380. package/src/zig/bench/README.md +50 -0
  381. package/src/zig/bench/buffer-color-blending_bench.zig +350 -0
  382. package/src/zig/bench/buffer-draw-box_bench.zig +786 -0
  383. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +894 -0
  384. package/src/zig/bench/edit-buffer_bench.zig +476 -0
  385. package/src/zig/bench/editor-view_bench.zig +169 -0
  386. package/src/zig/bench/native-span-feed_bench.zig +107 -0
  387. package/src/zig/bench/rope-markers_bench.zig +713 -0
  388. package/src/zig/bench/rope_bench.zig +514 -0
  389. package/src/zig/bench/styled-text_bench.zig +476 -0
  390. package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
  391. package/src/zig/bench/text-buffer-view_bench.zig +459 -0
  392. package/src/zig/bench/text-chunk-graphemes_bench.zig +272 -0
  393. package/src/zig/bench/utf8_bench.zig +799 -0
  394. package/src/zig/bench-utils.zig +431 -0
  395. package/src/zig/bench.zig +223 -0
  396. package/src/zig/buffer-methods.zig +215 -0
  397. package/src/zig/buffer.zig +2515 -0
  398. package/src/zig/build.zig +700 -0
  399. package/src/zig/build.zig.zon +19 -0
  400. package/src/zig/edit-buffer.zig +900 -0
  401. package/src/zig/editor-view.zig +812 -0
  402. package/src/zig/event-bus.zig +28 -0
  403. package/src/zig/event-emitter.zig +65 -0
  404. package/src/zig/file-logger.zig +92 -0
  405. package/src/zig/grapheme.zig +838 -0
  406. package/src/zig/handles.zig +267 -0
  407. package/src/zig/lib.zig +2813 -0
  408. package/src/zig/link.zig +349 -0
  409. package/src/zig/logger.zig +43 -0
  410. package/src/zig/mem-registry.zig +126 -0
  411. package/src/zig/miniaudio_shim.c +21 -0
  412. package/src/zig/native-renderable.zig +112 -0
  413. package/src/zig/native-span-feed-bench-lib.zig +7 -0
  414. package/src/zig/native-span-feed.zig +747 -0
  415. package/src/zig/renderer-output.zig +677 -0
  416. package/src/zig/renderer.zig +2106 -0
  417. package/src/zig/rope.zig +1220 -0
  418. package/src/zig/split-scrollback.zig +88 -0
  419. package/src/zig/syntax-style.zig +174 -0
  420. package/src/zig/terminal.zig +1652 -0
  421. package/src/zig/test.zig +82 -0
  422. package/src/zig/tests/README.md +18 -0
  423. package/src/zig/tests/ansi_test.zig +18 -0
  424. package/src/zig/tests/audio_test.zig +439 -0
  425. package/src/zig/tests/buffer-methods_test.zig +1111 -0
  426. package/src/zig/tests/buffer_test.zig +2926 -0
  427. package/src/zig/tests/edit-buffer-history_test.zig +299 -0
  428. package/src/zig/tests/edit-buffer_test.zig +1688 -0
  429. package/src/zig/tests/editor-view_test.zig +3454 -0
  430. package/src/zig/tests/event-emitter_test.zig +249 -0
  431. package/src/zig/tests/grapheme_test.zig +1329 -0
  432. package/src/zig/tests/handles_test.zig +123 -0
  433. package/src/zig/tests/link_test.zig +220 -0
  434. package/src/zig/tests/mem-registry_test.zig +473 -0
  435. package/src/zig/tests/memory_leak_regression_test.zig +234 -0
  436. package/src/zig/tests/native-renderable_test.zig +16 -0
  437. package/src/zig/tests/native-span-feed_test.zig +1266 -0
  438. package/src/zig/tests/renderer_test.zig +2604 -0
  439. package/src/zig/tests/rope-nested_test.zig +712 -0
  440. package/src/zig/tests/rope_fuzz_test.zig +238 -0
  441. package/src/zig/tests/rope_test.zig +2362 -0
  442. package/src/zig/tests/segment-merge.test.zig +148 -0
  443. package/src/zig/tests/split-scrollback_test.zig +70 -0
  444. package/src/zig/tests/syntax-style_test.zig +558 -0
  445. package/src/zig/tests/terminal_test.zig +1489 -0
  446. package/src/zig/tests/test-renderer.zig +126 -0
  447. package/src/zig/tests/text-buffer-drawing_test.zig +3291 -0
  448. package/src/zig/tests/text-buffer-highlights_test.zig +706 -0
  449. package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
  450. package/src/zig/tests/text-buffer-segment_test.zig +320 -0
  451. package/src/zig/tests/text-buffer-selection_test.zig +1056 -0
  452. package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
  453. package/src/zig/tests/text-buffer-view_test.zig +3672 -0
  454. package/src/zig/tests/text-buffer_test.zig +2191 -0
  455. package/src/zig/tests/unicode-width-map.zon +3909 -0
  456. package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
  457. package/src/zig/tests/utf8_test.zig +4060 -0
  458. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
  459. package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
  460. package/src/zig/tests/word-wrap-editing_test.zig +498 -0
  461. package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
  462. package/src/zig/tests/yoga_test.zig +65 -0
  463. package/src/zig/text-buffer-iterators.zig +496 -0
  464. package/src/zig/text-buffer-segment.zig +403 -0
  465. package/src/zig/text-buffer-view.zig +1428 -0
  466. package/src/zig/text-buffer.zig +1272 -0
  467. package/src/zig/utf8.zig +1954 -0
  468. package/src/zig/utils.zig +12 -0
  469. package/src/zig/uucode-stub.zig +76 -0
  470. package/src/zig/vendor/miniaudio/miniaudio.h +93468 -0
  471. package/src/zig/yoga.zig +658 -0
  472. package/src/zig-structs.ts +381 -0
  473. package/src/zig.ts +5260 -0
  474. package/tsconfig.build.json +17 -0
  475. package/tsconfig.json +27 -0
  476. package/tsconfig.node-test.json +138 -0
@@ -0,0 +1,147 @@
1
+ import { BaseRenderable } from "../Renderable.js"
2
+ import { stringToStyledText, StyledText } from "../lib/styled-text.js"
3
+ import { type TextChunk } from "../text-buffer.js"
4
+ import { RGBA } from "../lib/RGBA.js"
5
+ import { type RenderContext } from "../types.js"
6
+ import { RootTextNodeRenderable, TextNodeRenderable } from "./TextNode.js"
7
+ import { TextBufferRenderable, type TextBufferOptions } from "./TextBufferRenderable.js"
8
+
9
+ export interface TextOptions extends TextBufferOptions {
10
+ content?: StyledText | string
11
+ }
12
+
13
+ export class TextRenderable extends TextBufferRenderable {
14
+ private _text: StyledText
15
+
16
+ // TODO: The TextRenderable is currently juggling both a StyledText and a RootTextNodeRenderable.
17
+ // We should refactor this to only use the RootTextNodeRenderable here and have a separate StyledTextRenderable with `content`.
18
+ private _hasManualStyledText: boolean = false
19
+
20
+ protected rootTextNode: RootTextNodeRenderable
21
+
22
+ protected _contentDefaultOptions = {
23
+ content: "",
24
+ } satisfies Partial<TextOptions>
25
+
26
+ constructor(ctx: RenderContext, options: TextOptions) {
27
+ super(ctx, options)
28
+
29
+ const content = options.content ?? this._contentDefaultOptions.content
30
+ const styledText = typeof content === "string" ? stringToStyledText(content) : content
31
+ this._text = styledText
32
+ this._hasManualStyledText = options.content !== undefined && content !== ""
33
+
34
+ this.rootTextNode = new RootTextNodeRenderable(
35
+ ctx,
36
+ {
37
+ id: `${this.id}-root`,
38
+ fg: this._defaultFg,
39
+ bg: this._defaultBg,
40
+ attributes: this._defaultAttributes,
41
+ },
42
+ this,
43
+ )
44
+
45
+ this.updateTextBuffer(styledText)
46
+ }
47
+
48
+ private updateTextBuffer(styledText: StyledText): void {
49
+ this.textBuffer.setStyledText(styledText)
50
+ this.clearChunks(styledText)
51
+ }
52
+
53
+ private clearChunks(styledText: StyledText): void {
54
+ // Clearing chunks that were already writtend to the text buffer,
55
+ // to not retain references to the text data in js
56
+ // TODO: This is causing issues in the solid renderer
57
+ // styledText.chunks.forEach((chunk) => {
58
+ // // @ts-ignore
59
+ // chunk.text = undefined
60
+ // })
61
+ }
62
+
63
+ get content(): StyledText {
64
+ return this._text
65
+ }
66
+
67
+ get chunks(): TextChunk[] {
68
+ return this._text.chunks
69
+ }
70
+
71
+ get textNode(): RootTextNodeRenderable {
72
+ return this.rootTextNode
73
+ }
74
+
75
+ set content(value: StyledText | string) {
76
+ this._hasManualStyledText = true
77
+ const styledText = typeof value === "string" ? stringToStyledText(value) : value
78
+ if (this._text !== styledText) {
79
+ this._text = styledText
80
+ this.updateTextBuffer(styledText)
81
+ this.updateTextInfo()
82
+ }
83
+ }
84
+
85
+ private updateTextFromNodes(): void {
86
+ if (this.rootTextNode.isDirty && !this._hasManualStyledText) {
87
+ const chunks = this.rootTextNode.gatherWithInheritedStyle({
88
+ fg: this._defaultFg,
89
+ bg: this._defaultBg,
90
+ attributes: this._defaultAttributes,
91
+ link: undefined,
92
+ })
93
+ this.textBuffer.setStyledText(new StyledText(chunks))
94
+ this.refreshLocalSelection()
95
+ this.yogaNode.markDirty()
96
+ }
97
+ }
98
+
99
+ public add(obj: TextNodeRenderable | StyledText | string, index?: number): number {
100
+ return this.rootTextNode.add(obj, index)
101
+ }
102
+
103
+ public remove(child: BaseRenderable): void {
104
+ this.rootTextNode.remove(child)
105
+ }
106
+
107
+ public insertBefore(obj: BaseRenderable | any, anchor?: TextNodeRenderable): number {
108
+ this.rootTextNode.insertBefore(obj, anchor)
109
+ return this.rootTextNode.children.indexOf(obj)
110
+ }
111
+
112
+ public getTextChildren(): BaseRenderable[] {
113
+ return this.rootTextNode.getChildren()
114
+ }
115
+
116
+ public clear(): void {
117
+ this.rootTextNode.clear()
118
+
119
+ const emptyStyledText = stringToStyledText("")
120
+ this._text = emptyStyledText
121
+ this.updateTextBuffer(emptyStyledText)
122
+ this.updateTextInfo()
123
+
124
+ this.requestRender()
125
+ }
126
+
127
+ public onLifecyclePass = () => {
128
+ this.updateTextFromNodes()
129
+ }
130
+
131
+ protected onFgChanged(newColor: RGBA): void {
132
+ this.rootTextNode.fg = newColor
133
+ }
134
+
135
+ protected onBgChanged(newColor: RGBA): void {
136
+ this.rootTextNode.bg = newColor
137
+ }
138
+
139
+ protected onAttributesChanged(newAttributes: number): void {
140
+ this.rootTextNode.attributes = newAttributes
141
+ }
142
+
143
+ destroy(): void {
144
+ this.rootTextNode.children.length = 0
145
+ super.destroy()
146
+ }
147
+ }
@@ -0,0 +1,504 @@
1
+ import { Renderable, type RenderableOptions } from "../Renderable.js"
2
+ import { convertGlobalToLocalSelection, Selection, type LocalSelectionBounds } from "../lib/selection.js"
3
+ import { TextBuffer, type TextChunk } from "../text-buffer.js"
4
+ import { TextBufferView } from "../text-buffer-view.js"
5
+ import { RGBA, parseColor } from "../lib/RGBA.js"
6
+ import { type RenderContext, type LineInfoProvider } from "../types.js"
7
+ import type { OptimizedBuffer } from "../buffer.js"
8
+ import { NativeMeasureTargetKind, resolveRenderLib, type LineInfo, type NativeRenderableHandle } from "../zig.js"
9
+ import { SyntaxStyle } from "../syntax-style.js"
10
+
11
+ export interface TextBufferOptions extends RenderableOptions<TextBufferRenderable> {
12
+ fg?: string | RGBA
13
+ bg?: string | RGBA
14
+ selectionBg?: string | RGBA
15
+ selectionFg?: string | RGBA
16
+ selectable?: boolean
17
+ attributes?: number
18
+ wrapMode?: "none" | "char" | "word"
19
+ tabIndicator?: string | number
20
+ tabIndicatorColor?: string | RGBA
21
+ truncate?: boolean
22
+ }
23
+
24
+ export abstract class TextBufferRenderable extends Renderable implements LineInfoProvider {
25
+ public selectable: boolean = true
26
+
27
+ protected _defaultFg: RGBA
28
+ protected _defaultBg: RGBA
29
+ protected _defaultAttributes: number
30
+ protected _selectionBg: RGBA | undefined
31
+ protected _selectionFg: RGBA | undefined
32
+ protected _wrapMode: "none" | "char" | "word" = "word"
33
+ protected lastLocalSelection: LocalSelectionBounds | null = null
34
+ protected _tabIndicator?: string | number
35
+ protected _tabIndicatorColor?: RGBA
36
+ protected _scrollX: number = 0
37
+ protected _scrollY: number = 0
38
+ protected _truncate: boolean = false
39
+ protected _firstLineOffset: number = 0
40
+
41
+ protected textBuffer: TextBuffer
42
+ protected textBufferView: TextBufferView
43
+ protected _textBufferSyntaxStyle: SyntaxStyle
44
+ private nativeRenderable: NativeRenderableHandle | null = null
45
+
46
+ protected _defaultOptions = {
47
+ fg: RGBA.fromValues(1, 1, 1, 1),
48
+ bg: RGBA.fromValues(0, 0, 0, 0),
49
+ selectionBg: undefined,
50
+ selectionFg: undefined,
51
+ selectable: true,
52
+ attributes: 0,
53
+ wrapMode: "word" as "none" | "char" | "word",
54
+ tabIndicator: undefined,
55
+ tabIndicatorColor: undefined,
56
+ truncate: false,
57
+ } satisfies Partial<TextBufferOptions>
58
+
59
+ constructor(ctx: RenderContext, options: TextBufferOptions) {
60
+ super(ctx, options)
61
+
62
+ this._defaultFg = parseColor(options.fg ?? this._defaultOptions.fg)
63
+ this._defaultBg = parseColor(options.bg ?? this._defaultOptions.bg)
64
+ this._defaultAttributes = options.attributes ?? this._defaultOptions.attributes
65
+ this._selectionBg = options.selectionBg ? parseColor(options.selectionBg) : this._defaultOptions.selectionBg
66
+ this._selectionFg = options.selectionFg ? parseColor(options.selectionFg) : this._defaultOptions.selectionFg
67
+ this.selectable = options.selectable ?? this._defaultOptions.selectable
68
+ this._wrapMode = options.wrapMode ?? this._defaultOptions.wrapMode
69
+ this._tabIndicator = options.tabIndicator ?? this._defaultOptions.tabIndicator
70
+ this._tabIndicatorColor = options.tabIndicatorColor
71
+ ? parseColor(options.tabIndicatorColor)
72
+ : this._defaultOptions.tabIndicatorColor
73
+ this._truncate = options.truncate ?? this._defaultOptions.truncate
74
+
75
+ this.textBuffer = TextBuffer.create(this._ctx.widthMethod)
76
+ this.textBufferView = TextBufferView.create(this.textBuffer)
77
+ this._firstLineOffset = ctx.claimFirstLineOffset?.(this) ?? 0
78
+
79
+ this._textBufferSyntaxStyle = SyntaxStyle.create()
80
+ this.textBuffer.setSyntaxStyle(this._textBufferSyntaxStyle)
81
+
82
+ this.textBufferView.setWrapMode(this._wrapMode)
83
+ this.textBufferView.setFirstLineOffset(this._firstLineOffset)
84
+ this.setupNativeRenderable()
85
+
86
+ this.textBuffer.setDefaultFg(this._defaultFg)
87
+ this.textBuffer.setDefaultBg(this._defaultBg)
88
+ this.textBuffer.setDefaultAttributes(this._defaultAttributes)
89
+
90
+ if (this._tabIndicator !== undefined) {
91
+ this.textBufferView.setTabIndicator(this._tabIndicator)
92
+ }
93
+ if (this._tabIndicatorColor !== undefined) {
94
+ this.textBufferView.setTabIndicatorColor(this._tabIndicatorColor)
95
+ }
96
+
97
+ if (this._wrapMode !== "none" && this.width > 0) {
98
+ this.textBufferView.setWrapWidth(this.width)
99
+ }
100
+
101
+ if (this.width > 0 && this.height > 0) {
102
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, this.width, this.height)
103
+ }
104
+
105
+ this.textBufferView.setTruncate(this._truncate)
106
+
107
+ this.updateTextInfo()
108
+ }
109
+
110
+ protected onMouseEvent(event: any): void {
111
+ if (event.type === "scroll") {
112
+ this.handleScroll(event)
113
+ }
114
+ }
115
+
116
+ protected handleScroll(event: any): void {
117
+ if (!event.scroll) return
118
+
119
+ const { direction, delta } = event.scroll
120
+
121
+ if (direction === "up") {
122
+ this.scrollY -= delta
123
+ } else if (direction === "down") {
124
+ this.scrollY += delta
125
+ }
126
+
127
+ if (this._wrapMode === "none") {
128
+ if (direction === "left") {
129
+ this.scrollX -= delta
130
+ } else if (direction === "right") {
131
+ this.scrollX += delta
132
+ }
133
+ }
134
+ }
135
+
136
+ public get lineInfo(): LineInfo {
137
+ return this.textBufferView.logicalLineInfo
138
+ }
139
+
140
+ public get lineCount(): number {
141
+ return this.textBuffer.getLineCount()
142
+ }
143
+
144
+ public get virtualLineCount(): number {
145
+ return this.textBufferView.getVirtualLineCount()
146
+ }
147
+
148
+ public get scrollY(): number {
149
+ return this._scrollY
150
+ }
151
+
152
+ public set scrollY(value: number) {
153
+ const maxScrollY = Math.max(0, this.scrollHeight - this.height)
154
+ const clamped = Math.max(0, Math.min(value, maxScrollY))
155
+ if (this._scrollY !== clamped) {
156
+ this._scrollY = clamped
157
+ this.updateViewportOffset()
158
+ this.requestRender()
159
+ }
160
+ }
161
+
162
+ public get scrollX(): number {
163
+ return this._scrollX
164
+ }
165
+
166
+ public set scrollX(value: number) {
167
+ const maxScrollX = Math.max(0, this.scrollWidth - this.width)
168
+ const clamped = Math.max(0, Math.min(value, maxScrollX))
169
+ if (this._scrollX !== clamped) {
170
+ this._scrollX = clamped
171
+ this.updateViewportOffset()
172
+ this.requestRender()
173
+ }
174
+ }
175
+
176
+ public get scrollWidth(): number {
177
+ return this.lineInfo.lineWidthColsMax
178
+ }
179
+
180
+ public get scrollHeight(): number {
181
+ return this.lineInfo.lineStartCols.length
182
+ }
183
+
184
+ public get maxScrollY(): number {
185
+ return Math.max(0, this.scrollHeight - this.height)
186
+ }
187
+
188
+ public get maxScrollX(): number {
189
+ return Math.max(0, this.scrollWidth - this.width)
190
+ }
191
+
192
+ protected updateViewportOffset(): void {
193
+ // Update the viewport with the new scroll position
194
+ if (this.width > 0 && this.height > 0) {
195
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, this.width, this.height)
196
+ }
197
+ }
198
+
199
+ get plainText(): string {
200
+ return this.textBuffer.getPlainText()
201
+ }
202
+
203
+ get textLength(): number {
204
+ return this.textBuffer.length
205
+ }
206
+
207
+ get fg(): RGBA {
208
+ return this._defaultFg
209
+ }
210
+
211
+ set fg(value: RGBA | string | undefined) {
212
+ const newColor = parseColor(value ?? this._defaultOptions.fg)
213
+ if (this._defaultFg !== newColor) {
214
+ this._defaultFg = newColor
215
+ this.textBuffer.setDefaultFg(this._defaultFg)
216
+ this.onFgChanged(newColor)
217
+ this.requestRender()
218
+ }
219
+ }
220
+
221
+ get selectionBg(): RGBA | undefined {
222
+ return this._selectionBg
223
+ }
224
+
225
+ set selectionBg(value: RGBA | string | undefined) {
226
+ const newColor = value ? parseColor(value) : this._defaultOptions.selectionBg
227
+ if (this._selectionBg !== newColor) {
228
+ this._selectionBg = newColor
229
+ if (this.lastLocalSelection) {
230
+ this.updateLocalSelection(this.lastLocalSelection)
231
+ }
232
+ this.requestRender()
233
+ }
234
+ }
235
+
236
+ get selectionFg(): RGBA | undefined {
237
+ return this._selectionFg
238
+ }
239
+
240
+ set selectionFg(value: RGBA | string | undefined) {
241
+ const newColor = value ? parseColor(value) : this._defaultOptions.selectionFg
242
+ if (this._selectionFg !== newColor) {
243
+ this._selectionFg = newColor
244
+ if (this.lastLocalSelection) {
245
+ this.updateLocalSelection(this.lastLocalSelection)
246
+ }
247
+ this.requestRender()
248
+ }
249
+ }
250
+
251
+ get bg(): RGBA {
252
+ return this._defaultBg
253
+ }
254
+
255
+ set bg(value: RGBA | string | undefined) {
256
+ const newColor = parseColor(value ?? this._defaultOptions.bg)
257
+ if (this._defaultBg !== newColor) {
258
+ this._defaultBg = newColor
259
+ this.textBuffer.setDefaultBg(this._defaultBg)
260
+ this.onBgChanged(newColor)
261
+ this.requestRender()
262
+ }
263
+ }
264
+
265
+ get attributes(): number {
266
+ return this._defaultAttributes
267
+ }
268
+
269
+ set attributes(value: number) {
270
+ if (this._defaultAttributes !== value) {
271
+ this._defaultAttributes = value
272
+ this.textBuffer.setDefaultAttributes(this._defaultAttributes)
273
+ this.onAttributesChanged(value)
274
+ this.requestRender()
275
+ }
276
+ }
277
+
278
+ get wrapMode(): "none" | "char" | "word" {
279
+ return this._wrapMode
280
+ }
281
+
282
+ set wrapMode(value: "none" | "char" | "word") {
283
+ if (this._wrapMode !== value) {
284
+ this._wrapMode = value
285
+ this.textBufferView.setWrapMode(this._wrapMode)
286
+ if (value !== "none" && this.width > 0) {
287
+ this.textBufferView.setWrapWidth(this.width)
288
+ }
289
+ // Changing wrap mode can change dimensions, so mark yoga node dirty to trigger re-measurement
290
+ this.yogaNode.markDirty()
291
+ this.requestRender()
292
+ }
293
+ }
294
+
295
+ get tabIndicator(): string | number | undefined {
296
+ return this._tabIndicator
297
+ }
298
+
299
+ set tabIndicator(value: string | number | undefined) {
300
+ if (this._tabIndicator !== value) {
301
+ this._tabIndicator = value
302
+ if (value !== undefined) {
303
+ this.textBufferView.setTabIndicator(value)
304
+ }
305
+ this.requestRender()
306
+ }
307
+ }
308
+
309
+ get tabIndicatorColor(): RGBA | undefined {
310
+ return this._tabIndicatorColor
311
+ }
312
+
313
+ set tabIndicatorColor(value: RGBA | string | undefined) {
314
+ const newColor = value ? parseColor(value) : undefined
315
+ if (this._tabIndicatorColor !== newColor) {
316
+ this._tabIndicatorColor = newColor
317
+ if (newColor !== undefined) {
318
+ this.textBufferView.setTabIndicatorColor(newColor)
319
+ }
320
+ this.requestRender()
321
+ }
322
+ }
323
+
324
+ get truncate(): boolean {
325
+ return this._truncate
326
+ }
327
+
328
+ set truncate(value: boolean) {
329
+ if (this._truncate !== value) {
330
+ this._truncate = value
331
+ this.textBufferView.setTruncate(value)
332
+ this.requestRender()
333
+ }
334
+ }
335
+
336
+ protected onResize(width: number, height: number): void {
337
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, width, height)
338
+ this.yogaNode.markDirty()
339
+ this.requestRender()
340
+ this.emit("line-info-change")
341
+ }
342
+
343
+ protected refreshLocalSelection(): boolean {
344
+ if (this.lastLocalSelection) {
345
+ return this.updateLocalSelection(this.lastLocalSelection)
346
+ }
347
+ return false
348
+ }
349
+
350
+ private updateLocalSelection(localSelection: LocalSelectionBounds | null): boolean {
351
+ if (!localSelection?.isActive) {
352
+ this.textBufferView.resetLocalSelection()
353
+ return true
354
+ }
355
+
356
+ return this.textBufferView.setLocalSelection(
357
+ localSelection.anchorX,
358
+ localSelection.anchorY,
359
+ localSelection.focusX,
360
+ localSelection.focusY,
361
+ this._selectionBg,
362
+ this._selectionFg,
363
+ )
364
+ }
365
+
366
+ protected updateTextInfo(): void {
367
+ if (this.lastLocalSelection) {
368
+ this.updateLocalSelection(this.lastLocalSelection)
369
+ }
370
+
371
+ this.yogaNode.markDirty()
372
+ this.requestRender()
373
+ this.emit("line-info-change")
374
+ }
375
+
376
+ private setupNativeRenderable(): void {
377
+ const lib = resolveRenderLib()
378
+ // Transitional native backing: JS still owns the render tree and Yoga nodes,
379
+ // while native owns only hot measurement state. Attach the existing JS-created
380
+ // Yoga node for now. The intended direction is for every Renderable to become
381
+ // native-backed and for Yoga node ownership to move native-side with it.
382
+ const nativeRenderable = lib.createNativeRenderable()
383
+ if (!lib.nativeRenderableAttachYogaNode(nativeRenderable, this.yogaNode.ptr)) {
384
+ lib.destroyNativeRenderable(nativeRenderable)
385
+ throw new Error("Failed to attach native renderable Yoga node")
386
+ }
387
+ if (
388
+ !lib.nativeRenderableSetMeasureTarget(
389
+ nativeRenderable,
390
+ NativeMeasureTargetKind.TextBufferView,
391
+ this.textBufferView.ptr,
392
+ )
393
+ ) {
394
+ lib.destroyNativeRenderable(nativeRenderable)
395
+ throw new Error("Failed to attach text buffer native measure target")
396
+ }
397
+ this.nativeRenderable = nativeRenderable
398
+ }
399
+
400
+ shouldStartSelection(x: number, y: number): boolean {
401
+ if (!this.selectable) return false
402
+
403
+ const localX = x - this.x
404
+ const localY = y - this.y
405
+
406
+ return localX >= 0 && localX < this.width && localY >= 0 && localY < this.height
407
+ }
408
+
409
+ onSelectionChanged(selection: Selection | null): boolean {
410
+ const localSelection = convertGlobalToLocalSelection(selection, this.x, this.y)
411
+ this.lastLocalSelection = localSelection
412
+
413
+ let changed: boolean
414
+ if (!localSelection?.isActive) {
415
+ this.textBufferView.resetLocalSelection()
416
+ changed = true
417
+ } else if (selection?.isStart) {
418
+ changed = this.textBufferView.setLocalSelection(
419
+ localSelection.anchorX,
420
+ localSelection.anchorY,
421
+ localSelection.focusX,
422
+ localSelection.focusY,
423
+ this._selectionBg,
424
+ this._selectionFg,
425
+ )
426
+ } else {
427
+ changed = this.textBufferView.updateLocalSelection(
428
+ localSelection.anchorX,
429
+ localSelection.anchorY,
430
+ localSelection.focusX,
431
+ localSelection.focusY,
432
+ this._selectionBg,
433
+ this._selectionFg,
434
+ )
435
+ }
436
+
437
+ if (changed) {
438
+ this.requestRender()
439
+ }
440
+
441
+ return this.hasSelection()
442
+ }
443
+
444
+ getSelectedText(): string {
445
+ return this.textBufferView.getSelectedText()
446
+ }
447
+
448
+ hasSelection(): boolean {
449
+ return this.textBufferView.hasSelection()
450
+ }
451
+
452
+ getSelection(): { start: number; end: number } | null {
453
+ return this.textBufferView.getSelection()
454
+ }
455
+
456
+ render(buffer: OptimizedBuffer, deltaTime: number): void {
457
+ if (!this.visible) return
458
+ // Text views do enough per-frame work that avoiding recursive x/y lookups is
459
+ // measurable; use the layout cache for hit-grid and draw entry points.
460
+ const screenX = this._screenX
461
+ const screenY = this._screenY
462
+
463
+ this.markClean()
464
+ this._ctx.addToHitGrid(screenX, screenY, this.width, this.height, this.num)
465
+
466
+ this.renderSelf(buffer)
467
+
468
+ if (this.buffered && this.frameBuffer) {
469
+ buffer.drawFrameBuffer(screenX, screenY, this.frameBuffer)
470
+ }
471
+ }
472
+
473
+ protected renderSelf(buffer: OptimizedBuffer): void {
474
+ if (this.textBuffer.ptr) {
475
+ buffer.drawTextBuffer(this.textBufferView, this._screenX, this._screenY)
476
+ }
477
+ }
478
+
479
+ destroy(): void {
480
+ if (this.isDestroyed) return
481
+
482
+ if (this.nativeRenderable) {
483
+ resolveRenderLib().destroyNativeRenderable(this.nativeRenderable)
484
+ this.nativeRenderable = null
485
+ }
486
+ this.textBuffer.setSyntaxStyle(null)
487
+ this._textBufferSyntaxStyle.destroy()
488
+ this.textBufferView.destroy()
489
+ this.textBuffer.destroy()
490
+ super.destroy()
491
+ }
492
+
493
+ protected onFgChanged(newColor: RGBA): void {
494
+ // Override in subclasses if needed
495
+ }
496
+
497
+ protected onBgChanged(newColor: RGBA): void {
498
+ // Override in subclasses if needed
499
+ }
500
+
501
+ protected onAttributesChanged(newAttributes: number): void {
502
+ // Override in subclasses if needed
503
+ }
504
+ }