@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,441 @@
1
+ import { RGBA, DEFAULT_BACKGROUND_RGB, DEFAULT_FOREGROUND_RGB, ansi256IndexToRgb } from "./RGBA.js"
2
+ import { SystemClock, type Clock, type TimerHandle } from "./clock.js"
3
+ import { env, registerEnvVar } from "./env.js"
4
+
5
+ type Hex = string | null
6
+
7
+ const SYSTEM_CLOCK = new SystemClock()
8
+
9
+ registerEnvVar({
10
+ name: "OTUI_PALETTE_IDLE_TIMEOUT_MS",
11
+ description: "Milliseconds of silence after palette queries before using fallback colors.",
12
+ type: "number",
13
+ default: 300,
14
+ })
15
+
16
+ const OSC4_RESPONSE =
17
+ /\x1b]4;(\d+);(?:(?:rgb:)([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)|#([0-9a-fA-F]{6}))(?:\x07|\x1b\\)/g
18
+
19
+ const OSC_SPECIAL_RESPONSE =
20
+ /\x1b](\d+);(?:(?:rgb:)([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)|#([0-9a-fA-F]{6}))(?:\x07|\x1b\\)/g
21
+
22
+ export type WriteFunction = (data: string | Buffer) => boolean
23
+
24
+ export interface TerminalColors {
25
+ palette: Hex[]
26
+ defaultForeground: Hex
27
+ defaultBackground: Hex
28
+ cursorColor: Hex
29
+ mouseForeground: Hex
30
+ mouseBackground: Hex
31
+ tekForeground: Hex
32
+ tekBackground: Hex
33
+ highlightBackground: Hex
34
+ highlightForeground: Hex
35
+ }
36
+
37
+ export interface GetPaletteOptions {
38
+ timeout?: number
39
+ size?: number
40
+ }
41
+
42
+ export interface TerminalPaletteDetector {
43
+ detect(options?: GetPaletteOptions): Promise<TerminalColors>
44
+ detectOSCSupport(timeoutMs?: number): Promise<boolean>
45
+ cleanup(): void
46
+ }
47
+
48
+ export interface NormalizedTerminalPalette {
49
+ palette: RGBA[]
50
+ defaultForeground: RGBA
51
+ defaultBackground: RGBA
52
+ }
53
+
54
+ export type OscSubscriptionSource = {
55
+ subscribeOsc(handler: (sequence: string) => void): () => void
56
+ }
57
+
58
+ export interface TerminalPaletteOptions {
59
+ stdin: NodeJS.ReadStream
60
+ stdout: NodeJS.WriteStream
61
+ writeFn?: WriteFunction
62
+ isLegacyTmux?: boolean
63
+ isTmux?: boolean
64
+ oscSource?: OscSubscriptionSource
65
+ clock?: Clock
66
+ }
67
+
68
+ function scaleComponent(comp: string): string {
69
+ const val = parseInt(comp, 16)
70
+ const maxIn = (1 << (4 * comp.length)) - 1
71
+ return Math.round((val / maxIn) * 255)
72
+ .toString(16)
73
+ .padStart(2, "0")
74
+ }
75
+
76
+ function toHex(r?: string, g?: string, b?: string, hex6?: string): string {
77
+ if (hex6) return `#${hex6.toLowerCase()}`
78
+ if (r && g && b) return `#${scaleComponent(r)}${scaleComponent(g)}${scaleComponent(b)}`
79
+ return "#000000"
80
+ }
81
+
82
+ /**
83
+ * Wrap OSC sequence for tmux passthrough
84
+ * tmux requires DCS sequences to pass OSC to the underlying terminal
85
+ * Format: ESC P tmux; ESC <OSC_SEQUENCE> ESC \
86
+ */
87
+ function wrapForTmux(osc: string): string {
88
+ // Replace ESC with ESC ESC for tmux (escape the escape)
89
+ const escaped = osc.replace(/\x1b/g, "\x1b\x1b")
90
+ return `\x1bPtmux;${escaped}\x1b\\`
91
+ }
92
+
93
+ export class TerminalPalette implements TerminalPaletteDetector {
94
+ private stdin: NodeJS.ReadStream
95
+ private stdout: NodeJS.WriteStream
96
+ private writeFn: WriteFunction
97
+ private activeQuerySessions: Array<() => void> = []
98
+ private inLegacyTmux: boolean
99
+ private inTmux: boolean
100
+ private oscSource?: OscSubscriptionSource
101
+ private readonly clock: Clock
102
+
103
+ constructor(options: TerminalPaletteOptions) {
104
+ const { stdin, stdout, writeFn, isLegacyTmux, isTmux, oscSource, clock } = options
105
+
106
+ this.stdin = stdin
107
+ this.stdout = stdout
108
+ this.writeFn = writeFn || ((data: string | Buffer) => stdout.write(data))
109
+ this.inLegacyTmux = isLegacyTmux ?? false
110
+ this.inTmux = isTmux ?? this.inLegacyTmux
111
+ this.oscSource = oscSource
112
+ this.clock = clock ?? SYSTEM_CLOCK
113
+ }
114
+
115
+ private writeOsc(osc: string, wrapForLegacyTmux = false): boolean {
116
+ const data = wrapForLegacyTmux && this.inLegacyTmux ? wrapForTmux(osc) : osc
117
+ return this.writeFn(data)
118
+ }
119
+
120
+ cleanup(): void {
121
+ for (const cleanupSession of [...this.activeQuerySessions]) {
122
+ cleanupSession()
123
+ }
124
+ this.activeQuerySessions = []
125
+ }
126
+
127
+ private subscribeInput(handler: (chunk: string | Buffer) => void): () => void {
128
+ if (this.oscSource) {
129
+ return this.oscSource.subscribeOsc((sequence) => {
130
+ handler(sequence)
131
+ })
132
+ }
133
+
134
+ this.stdin.on("data", handler)
135
+ return () => {
136
+ this.stdin.removeListener("data", handler)
137
+ }
138
+ }
139
+
140
+ private createQuerySession() {
141
+ const timers = new Set<TimerHandle>()
142
+ const subscriptions = new Set<() => void>()
143
+ let closed = false
144
+
145
+ const cleanup = () => {
146
+ if (closed) return
147
+ closed = true
148
+
149
+ for (const timer of timers) {
150
+ this.clock.clearTimeout(timer)
151
+ }
152
+ timers.clear()
153
+
154
+ for (const unsubscribe of subscriptions) {
155
+ unsubscribe()
156
+ }
157
+ subscriptions.clear()
158
+
159
+ const idx = this.activeQuerySessions.indexOf(cleanup)
160
+ if (idx !== -1) this.activeQuerySessions.splice(idx, 1)
161
+ }
162
+
163
+ this.activeQuerySessions.push(cleanup)
164
+
165
+ return {
166
+ setTimer: (fn: () => void, ms: number): TimerHandle => {
167
+ const timer = this.clock.setTimeout(fn, ms)
168
+ timers.add(timer)
169
+ return timer
170
+ },
171
+ resetTimer: (existing: TimerHandle | null, fn: () => void, ms: number): TimerHandle => {
172
+ if (existing) {
173
+ this.clock.clearTimeout(existing)
174
+ timers.delete(existing)
175
+ }
176
+
177
+ const timer = this.clock.setTimeout(fn, ms)
178
+ timers.add(timer)
179
+ return timer
180
+ },
181
+ subscribeInput: (handler: (chunk: string | Buffer) => void): (() => void) => {
182
+ const unsubscribe = this.subscribeInput(handler)
183
+ subscriptions.add(unsubscribe)
184
+ return () => {
185
+ if (!subscriptions.has(unsubscribe)) return
186
+ subscriptions.delete(unsubscribe)
187
+ unsubscribe()
188
+ }
189
+ },
190
+ cleanup,
191
+ }
192
+ }
193
+
194
+ async detectOSCSupport(timeoutMs = 300): Promise<boolean> {
195
+ const out = this.stdout
196
+
197
+ if (!out.isTTY || !this.stdin.isTTY) return false
198
+
199
+ return new Promise<boolean>((resolve) => {
200
+ const session = this.createQuerySession()
201
+ let buffer = ""
202
+ let settled = false
203
+
204
+ const finish = (supported: boolean) => {
205
+ if (settled) return
206
+ settled = true
207
+ session.cleanup()
208
+ resolve(supported)
209
+ }
210
+
211
+ const onData = (chunk: string | Buffer) => {
212
+ buffer += chunk.toString()
213
+ // Reset regex lastIndex before testing due to global flag
214
+ OSC4_RESPONSE.lastIndex = 0
215
+ if (OSC4_RESPONSE.test(buffer)) {
216
+ finish(true)
217
+ }
218
+ }
219
+
220
+ session.setTimer(() => {
221
+ finish(false)
222
+ }, timeoutMs)
223
+ session.subscribeInput(onData)
224
+ // Only OSC 4 needs legacy tmux passthrough; tmux routes OSC 4 replies back to the pane.
225
+ this.writeOsc("\x1b]4;0;?\x07", true)
226
+ })
227
+ }
228
+
229
+ private async queryPalette(
230
+ indices: number[],
231
+ timeoutMs = 1200,
232
+ idleTimeoutMs = env.OTUI_PALETTE_IDLE_TIMEOUT_MS,
233
+ ): Promise<Map<number, Hex>> {
234
+ const out = this.stdout
235
+ const results = new Map<number, Hex>()
236
+ indices.forEach((i) => results.set(i, null))
237
+
238
+ if (!out.isTTY || !this.stdin.isTTY) {
239
+ return results
240
+ }
241
+
242
+ return new Promise<Map<number, Hex>>((resolve) => {
243
+ const session = this.createQuerySession()
244
+ let buffer = ""
245
+ let idleTimer: TimerHandle | null = null
246
+ let settled = false
247
+
248
+ const finish = () => {
249
+ if (settled) return
250
+ settled = true
251
+ session.cleanup()
252
+ resolve(results)
253
+ }
254
+
255
+ const onData = (chunk: string | Buffer) => {
256
+ buffer += chunk.toString()
257
+
258
+ let m: RegExpExecArray | null
259
+ OSC4_RESPONSE.lastIndex = 0
260
+ while ((m = OSC4_RESPONSE.exec(buffer))) {
261
+ const idx = parseInt(m[1], 10)
262
+ if (results.has(idx)) results.set(idx, toHex(m[2], m[3], m[4], m[5]))
263
+ }
264
+
265
+ if (buffer.length > 8192) buffer = buffer.slice(-4096)
266
+
267
+ const done = [...results.values()].filter((v) => v !== null).length
268
+ if (done === results.size) {
269
+ finish()
270
+ return
271
+ }
272
+
273
+ idleTimer = session.resetTimer(idleTimer, finish, idleTimeoutMs)
274
+ }
275
+
276
+ session.setTimer(finish, timeoutMs)
277
+ session.subscribeInput(onData)
278
+ // Only OSC 4 needs legacy tmux passthrough; tmux routes OSC 4 replies back to the pane.
279
+ this.writeOsc(indices.map((i) => `\x1b]4;${i};?\x07`).join(""), true)
280
+ idleTimer = session.resetTimer(idleTimer, finish, idleTimeoutMs)
281
+ })
282
+ }
283
+
284
+ private async querySpecialColors(
285
+ timeoutMs = 1200,
286
+ idleTimeoutMs = env.OTUI_PALETTE_IDLE_TIMEOUT_MS,
287
+ ): Promise<Record<number, Hex>> {
288
+ const out = this.stdout
289
+ const results: Record<number, Hex> = {
290
+ 10: null,
291
+ 11: null,
292
+ 12: null,
293
+ 13: null,
294
+ 14: null,
295
+ 15: null,
296
+ 16: null,
297
+ 17: null,
298
+ 19: null,
299
+ }
300
+ // tmux handles plain OSC 10/11/12 only; it has no OSC 13-17/19 handlers or reply routing.
301
+ const queries = this.inTmux ? [10, 11, 12] : [10, 11, 12, 13, 14, 15, 16, 17, 19]
302
+
303
+ if (!out.isTTY || !this.stdin.isTTY) {
304
+ return results
305
+ }
306
+
307
+ return new Promise<Record<number, Hex>>((resolve) => {
308
+ const session = this.createQuerySession()
309
+ let buffer = ""
310
+ let idleTimer: TimerHandle | null = null
311
+ let settled = false
312
+
313
+ const finish = () => {
314
+ if (settled) return
315
+ settled = true
316
+ session.cleanup()
317
+ resolve(results)
318
+ }
319
+
320
+ const onData = (chunk: string | Buffer) => {
321
+ buffer += chunk.toString()
322
+ let updated = false
323
+
324
+ let m: RegExpExecArray | null
325
+ OSC_SPECIAL_RESPONSE.lastIndex = 0
326
+ while ((m = OSC_SPECIAL_RESPONSE.exec(buffer))) {
327
+ const idx = parseInt(m[1], 10)
328
+ if (idx in results) {
329
+ results[idx] = toHex(m[2], m[3], m[4], m[5])
330
+ updated = true
331
+ }
332
+ }
333
+
334
+ if (buffer.length > 8192) buffer = buffer.slice(-4096)
335
+
336
+ if (queries.every((idx) => results[idx] !== null)) {
337
+ finish()
338
+ return
339
+ }
340
+
341
+ if (!updated) return
342
+
343
+ idleTimer = session.resetTimer(idleTimer, finish, idleTimeoutMs)
344
+ }
345
+
346
+ session.setTimer(finish, timeoutMs)
347
+ session.subscribeInput(onData)
348
+ // OSC 10/11/12 are plain tmux handlers. DCS passthrough does not help other special colors.
349
+ this.writeOsc(queries.map((idx) => `\x1b]${idx};?\x07`).join(""))
350
+ idleTimer = session.resetTimer(idleTimer, finish, idleTimeoutMs)
351
+ })
352
+ }
353
+
354
+ async detect(options?: GetPaletteOptions): Promise<TerminalColors> {
355
+ const { timeout = 5000, size = 16 } = options || {}
356
+ const supported = await this.detectOSCSupport()
357
+
358
+ if (!supported) {
359
+ return {
360
+ palette: Array(size).fill(null),
361
+ defaultForeground: null,
362
+ defaultBackground: null,
363
+ cursorColor: null,
364
+ mouseForeground: null,
365
+ mouseBackground: null,
366
+ tekForeground: null,
367
+ tekBackground: null,
368
+ highlightBackground: null,
369
+ highlightForeground: null,
370
+ }
371
+ }
372
+
373
+ const indicesToQuery = [...Array(size).keys()]
374
+ const idleTimeout = env.OTUI_PALETTE_IDLE_TIMEOUT_MS
375
+ const [paletteResults, specialColors] = await Promise.all([
376
+ this.queryPalette(indicesToQuery, timeout, idleTimeout),
377
+ this.querySpecialColors(timeout, idleTimeout),
378
+ ])
379
+
380
+ return {
381
+ palette: [...Array(size).keys()].map((i) => paletteResults.get(i) ?? null),
382
+ defaultForeground: specialColors[10],
383
+ defaultBackground: specialColors[11],
384
+ cursorColor: specialColors[12],
385
+ mouseForeground: specialColors[13],
386
+ mouseBackground: specialColors[14],
387
+ tekForeground: specialColors[15],
388
+ tekBackground: specialColors[16],
389
+ highlightBackground: specialColors[17],
390
+ highlightForeground: specialColors[19],
391
+ }
392
+ }
393
+ }
394
+
395
+ export function createTerminalPalette(options: TerminalPaletteOptions): TerminalPaletteDetector {
396
+ return new TerminalPalette(options)
397
+ }
398
+
399
+ const DEFAULT_FOREGROUND_FALLBACK = RGBA.fromInts(...DEFAULT_FOREGROUND_RGB)
400
+ const DEFAULT_BACKGROUND_FALLBACK = RGBA.fromInts(...DEFAULT_BACKGROUND_RGB)
401
+
402
+ let fallbackAnsi256Palette: RGBA[] | null = null
403
+
404
+ function getFallbackAnsi256Palette(): readonly RGBA[] {
405
+ if (!fallbackAnsi256Palette) {
406
+ fallbackAnsi256Palette = Array.from({ length: 256 }, (_, index) => {
407
+ const [r, g, b] = ansi256IndexToRgb(index)
408
+ return RGBA.fromInts(r, g, b)
409
+ })
410
+ }
411
+
412
+ return fallbackAnsi256Palette
413
+ }
414
+
415
+ export function normalizeTerminalPalette(colors?: TerminalColors | null): NormalizedTerminalPalette {
416
+ const fallbackPalette = getFallbackAnsi256Palette()
417
+
418
+ return {
419
+ palette: Array.from({ length: 256 }, (_, index) => {
420
+ const detected = colors?.palette[index]
421
+ return detected ? RGBA.fromHex(detected) : RGBA.clone(fallbackPalette[index])
422
+ }),
423
+ defaultForeground: colors?.defaultForeground
424
+ ? RGBA.fromHex(colors.defaultForeground)
425
+ : RGBA.clone(DEFAULT_FOREGROUND_FALLBACK),
426
+ defaultBackground: colors?.defaultBackground
427
+ ? RGBA.fromHex(colors.defaultBackground)
428
+ : RGBA.clone(DEFAULT_BACKGROUND_FALLBACK),
429
+ }
430
+ }
431
+
432
+ export function buildTerminalPaletteSignature(colors?: TerminalColors | null): string {
433
+ const normalized = normalizeTerminalPalette(colors)
434
+ const paletteSignature = normalized.palette.map((color) => color.toInts().join(",")).join(";")
435
+
436
+ return [
437
+ paletteSignature,
438
+ normalized.defaultForeground.toInts().join(","),
439
+ normalized.defaultBackground.toInts().join(","),
440
+ ].join("|")
441
+ }
@@ -0,0 +1,119 @@
1
+ # Tree-sitter Assets
2
+
3
+ This directory contains downloaded tree-sitter language parsers and highlight queries for the default parsers used by OpenTUI.
4
+ They are included in the repository to avoid downloading them every time the project is built or tests are run.
5
+
6
+ ## Asset Management
7
+
8
+ Parser definitions are configured in `../parsers-config.ts` for OpenTUI's built-in parser set.
9
+
10
+ ### Update Script
11
+
12
+ The `update.ts` script downloads parsers and queries from the configured URLs and generates the `../default-parsers.ts` file.
13
+
14
+ #### Usage
15
+
16
+ **For OpenTUI Core Development (using default paths):**
17
+
18
+ ```bash
19
+ # Run from this directory
20
+ bun update.ts
21
+
22
+ # Or from the project root
23
+ bun packages/core/src/lib/tree-sitter/assets/update.ts
24
+ ```
25
+
26
+ **For Application Developers (using custom paths):**
27
+
28
+ ```bash
29
+ # CLI usage with custom paths
30
+ bun update.ts \
31
+ --config ./my-parsers-config.json \
32
+ --assets ./src/tree-sitter/assets \
33
+ --output ./src/tree-sitter/parsers.ts
34
+
35
+ # Show help
36
+ bun update.ts --help
37
+ ```
38
+
39
+ **Programmatic Usage:**
40
+
41
+ ```typescript
42
+ import { updateAssets } from "@opentui/core/tree-sitter/update-assets"
43
+
44
+ await updateAssets({
45
+ configPath: "./my-parsers-config.json",
46
+ assetsDir: "./src/tree-sitter/assets",
47
+ outputPath: "./src/tree-sitter/parsers.ts",
48
+ })
49
+ ```
50
+
51
+ #### What it does
52
+
53
+ 1. **Downloads Language Parsers**: Downloads `.wasm` files from GitHub releases
54
+ 2. **Downloads Query Files**: Downloads `.scm` highlight query files from repositories
55
+ 3. **Combines Queries**: For languages like TypeScript, combines multiple query files (JS base + TS extensions)
56
+ 4. **Generates Imports**: Creates a TypeScript file with proper file imports using Bun's `with { type: "file" }` syntax
57
+
58
+ ## Adding New Parsers
59
+
60
+ ### For Application Developers
61
+
62
+ If you're using OpenTUI in your application and want to add support for additional languages:
63
+
64
+ #### 1. Create a parsers configuration file
65
+
66
+ Create a `parsers-config.json` file in your project with the structure:
67
+
68
+ ```json
69
+ {
70
+ "parsers": [
71
+ {
72
+ "filetype": "python",
73
+ "wasm": "https://github.com/tree-sitter/tree-sitter-python/releases/download/v0.20.4/tree-sitter-python.wasm",
74
+ "queries": {
75
+ "highlights": [
76
+ "https://raw.githubusercontent.com/tree-sitter/tree-sitter-python/refs/heads/master/queries/highlights.scm"
77
+ ]
78
+ }
79
+ }
80
+ ]
81
+ }
82
+ ```
83
+
84
+ #### 2. Add to your build pipeline
85
+
86
+ Add the update script to your `package.json`:
87
+
88
+ ```json
89
+ {
90
+ "scripts": {
91
+ "prebuild": "bun node_modules/@opentui/core/lib/tree-sitter/update-assets.js --config ./parsers-config.json --assets ./src/parsers --output ./src/parsers.ts",
92
+ "build": "bun build ./src/index.ts"
93
+ }
94
+ }
95
+ ```
96
+
97
+ #### 3. Use the generated parsers
98
+
99
+ ```typescript
100
+ import { getTreeSitterClient } from "@opentui/core"
101
+ import { getParsers } from "./parsers"
102
+
103
+ const client = getTreeSitterClient()
104
+
105
+ // Register your custom parsers
106
+ for (const parser of getParsers()) {
107
+ client.addFiletypeParser(parser)
108
+ }
109
+ ```
110
+
111
+ For more information about using Tree-Sitter in your application, see the [Tree-Sitter guide](../../../docs/tree-sitter.md).
112
+
113
+ ### For OpenTUI Core Developers
114
+
115
+ To add a new default parser to OpenTUI Core:
116
+
117
+ 1. **Update Configuration**: Add the new parser to `../parsers-config.ts`
118
+ 2. **Run Update Script**: Execute `bun update.ts` to download assets and regenerate imports
119
+ 3. **Commit Generated Assets**: Include the downloaded parser/query files and regenerated `../default-parsers.ts`