@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,222 @@
1
+ import { EventEmitter } from "events"
2
+ import { type KeyEventType, type ParsedKey } from "./parse.keypress.js"
3
+ import type { PasteMetadata } from "./paste.js"
4
+
5
+ export class KeyEvent implements ParsedKey {
6
+ name: string
7
+ ctrl: boolean
8
+ meta: boolean
9
+ shift: boolean
10
+ option: boolean
11
+ sequence: string
12
+ number: boolean
13
+ raw: string
14
+ eventType: KeyEventType
15
+ source: "raw" | "kitty"
16
+ code?: string
17
+ super?: boolean
18
+ hyper?: boolean
19
+ capsLock?: boolean
20
+ numLock?: boolean
21
+ baseCode?: number
22
+ repeated?: boolean
23
+
24
+ private _defaultPrevented: boolean = false
25
+ private _propagationStopped: boolean = false
26
+
27
+ constructor(key: ParsedKey) {
28
+ this.name = key.name
29
+ this.ctrl = key.ctrl
30
+ this.meta = key.meta
31
+ this.shift = key.shift
32
+ this.option = key.option
33
+ this.sequence = key.sequence
34
+ this.number = key.number
35
+ this.raw = key.raw
36
+ this.eventType = key.eventType
37
+ this.source = key.source
38
+ this.code = key.code
39
+ this.super = key.super
40
+ this.hyper = key.hyper
41
+ this.capsLock = key.capsLock
42
+ this.numLock = key.numLock
43
+ this.baseCode = key.baseCode
44
+ this.repeated = key.repeated
45
+ }
46
+
47
+ get defaultPrevented(): boolean {
48
+ return this._defaultPrevented
49
+ }
50
+
51
+ get propagationStopped(): boolean {
52
+ return this._propagationStopped
53
+ }
54
+
55
+ preventDefault(): void {
56
+ this._defaultPrevented = true
57
+ }
58
+
59
+ stopPropagation(): void {
60
+ this._propagationStopped = true
61
+ }
62
+ }
63
+
64
+ export class PasteEvent {
65
+ type = "paste" as const
66
+ bytes: Uint8Array
67
+ metadata?: PasteMetadata
68
+ private _defaultPrevented: boolean = false
69
+ private _propagationStopped: boolean = false
70
+
71
+ constructor(bytes: Uint8Array, metadata?: PasteMetadata) {
72
+ this.bytes = bytes
73
+ this.metadata = metadata
74
+ }
75
+
76
+ get defaultPrevented(): boolean {
77
+ return this._defaultPrevented
78
+ }
79
+
80
+ get propagationStopped(): boolean {
81
+ return this._propagationStopped
82
+ }
83
+
84
+ preventDefault(): void {
85
+ this._defaultPrevented = true
86
+ }
87
+
88
+ stopPropagation(): void {
89
+ this._propagationStopped = true
90
+ }
91
+ }
92
+
93
+ export type KeyHandlerEventMap = {
94
+ keypress: [KeyEvent]
95
+ keyrelease: [KeyEvent]
96
+ paste: [PasteEvent]
97
+ }
98
+
99
+ export class KeyHandler extends EventEmitter<KeyHandlerEventMap> {
100
+ public processParsedKey(parsedKey: ParsedKey): boolean {
101
+ try {
102
+ switch (parsedKey.eventType) {
103
+ case "press":
104
+ this.emit("keypress", new KeyEvent(parsedKey))
105
+ break
106
+ case "release":
107
+ this.emit("keyrelease", new KeyEvent(parsedKey))
108
+ break
109
+ default:
110
+ this.emit("keypress", new KeyEvent(parsedKey))
111
+ break
112
+ }
113
+ } catch (error) {
114
+ console.error(`[KeyHandler] Error processing parsed key:`, error)
115
+ return true
116
+ }
117
+
118
+ return true
119
+ }
120
+
121
+ public processPaste(bytes: Uint8Array, metadata?: PasteMetadata): void {
122
+ try {
123
+ this.emit("paste", new PasteEvent(bytes, metadata))
124
+ } catch (error) {
125
+ console.error(`[KeyHandler] Error processing paste:`, error)
126
+ }
127
+ }
128
+ }
129
+
130
+ /**
131
+ * This class is used internally by the renderer to ensure global handlers
132
+ * can preventDefault before renderable handlers process events.
133
+ */
134
+ export class InternalKeyHandler extends KeyHandler {
135
+ private renderableHandlers: Map<keyof KeyHandlerEventMap, Set<Function>> = new Map()
136
+
137
+ public emit<K extends keyof KeyHandlerEventMap>(event: K, ...args: KeyHandlerEventMap[K]): boolean {
138
+ return this.emitWithPriority(event, ...args)
139
+ }
140
+
141
+ private emitWithPriority<K extends keyof KeyHandlerEventMap>(event: K, ...args: KeyHandlerEventMap[K]): boolean {
142
+ let hasGlobalListeners = false
143
+
144
+ // Check if we should emit to global handlers
145
+ // Global handlers are emitted using the parent EventEmitter which calls all listeners
146
+ // We need to manually iterate to check for stopPropagation between handlers
147
+ const globalListeners = this.listeners(event as any)
148
+ if (globalListeners.length > 0) {
149
+ hasGlobalListeners = true
150
+
151
+ for (const listener of globalListeners) {
152
+ try {
153
+ listener(...args)
154
+ } catch (error) {
155
+ console.error(`[KeyHandler] Error in global ${event} handler:`, error)
156
+ }
157
+
158
+ // Check if propagation was stopped after this handler
159
+ if (event === "keypress" || event === "keyrelease" || event === "paste") {
160
+ const keyEvent = args[0]
161
+ if (keyEvent.propagationStopped) {
162
+ return hasGlobalListeners
163
+ }
164
+ }
165
+ }
166
+ }
167
+
168
+ const renderableSet = this.renderableHandlers.get(event)
169
+ // Snapshot the handler list so listeners added during dispatch (e.g., via focus changes)
170
+ // do not receive the in-flight key event.
171
+ const renderableHandlers = renderableSet && renderableSet.size > 0 ? [...renderableSet] : []
172
+ let hasRenderableListeners = false
173
+
174
+ if (renderableSet && renderableSet.size > 0) {
175
+ hasRenderableListeners = true
176
+
177
+ if (event === "keypress" || event === "keyrelease" || event === "paste") {
178
+ const keyEvent = args[0]
179
+ if (keyEvent.defaultPrevented) return hasGlobalListeners || hasRenderableListeners
180
+ if (keyEvent.propagationStopped) return hasGlobalListeners || hasRenderableListeners
181
+ }
182
+
183
+ for (const handler of renderableHandlers) {
184
+ try {
185
+ handler(...args)
186
+ } catch (error) {
187
+ console.error(`[KeyHandler] Error in renderable ${event} handler:`, error)
188
+ }
189
+
190
+ // Check if propagation was stopped after this handler
191
+ if (event === "keypress" || event === "keyrelease" || event === "paste") {
192
+ const keyEvent = args[0]
193
+ if (keyEvent.propagationStopped) {
194
+ return hasGlobalListeners || hasRenderableListeners
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ return hasGlobalListeners || hasRenderableListeners
201
+ }
202
+
203
+ public onInternal<K extends keyof KeyHandlerEventMap>(
204
+ event: K,
205
+ handler: (...args: KeyHandlerEventMap[K]) => void,
206
+ ): void {
207
+ if (!this.renderableHandlers.has(event)) {
208
+ this.renderableHandlers.set(event, new Set())
209
+ }
210
+ this.renderableHandlers.get(event)!.add(handler)
211
+ }
212
+
213
+ public offInternal<K extends keyof KeyHandlerEventMap>(
214
+ event: K,
215
+ handler: (...args: KeyHandlerEventMap[K]) => void,
216
+ ): void {
217
+ const handlers = this.renderableHandlers.get(event)
218
+ if (handlers) {
219
+ handlers.delete(handler)
220
+ }
221
+ }
222
+ }
@@ -0,0 +1,60 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import { RGBA, ansi256IndexToRgb, hexToRgb, normalizeColorValue, parseColor, rgbToHex } from "./RGBA.js"
3
+
4
+ describe("RGBA", () => {
5
+ test("uses packed Uint16 transport", () => {
6
+ const color = RGBA.fromValues(1, 0, 0, 0.5)
7
+ expect(color.buffer).toBeInstanceOf(Uint16Array)
8
+ expect(color.buffer).toHaveLength(4)
9
+ expect(color.toInts()).toEqual([255, 0, 0, 128])
10
+ expect(color.intent).toBe("rgb")
11
+ })
12
+
13
+ test("copies constructor input", () => {
14
+ const input = new Uint16Array([1, 2, 3, 4])
15
+ const color = new RGBA(input)
16
+ input[0] = 255
17
+ expect(color.buffer[0]).toBe(1)
18
+ })
19
+
20
+ test("preserves metadata when mutating channels", () => {
21
+ const color = RGBA.fromIndex(6)
22
+ color.r = 1
23
+ expect(color.intent).toBe("indexed")
24
+ expect(color.slot).toBe(6)
25
+ expect(color.toInts()[0]).toBe(255)
26
+ })
27
+
28
+ test("constructs indexed and default colors", () => {
29
+ const indexed = RGBA.fromIndex(12, "#112233")
30
+ const defaultFg = RGBA.defaultForeground("#abcdef")
31
+
32
+ expect(indexed.intent).toBe("indexed")
33
+ expect(indexed.slot).toBe(12)
34
+ expect(indexed.toInts()).toEqual([0x11, 0x22, 0x33, 255])
35
+ expect(defaultFg.intent).toBe("default")
36
+ expect(defaultFg.toInts()).toEqual([0xab, 0xcd, 0xef, 255])
37
+ })
38
+
39
+ test("converts ANSI 256 indexes", () => {
40
+ expect(ansi256IndexToRgb(9)).toEqual([255, 0, 0])
41
+ expect(ansi256IndexToRgb(21)).toEqual([0, 0, 255])
42
+ expect(ansi256IndexToRgb(232)).toEqual([8, 8, 8])
43
+ })
44
+
45
+ test("parses and formats colors", () => {
46
+ expect(hexToRgb("#F808").toInts()).toEqual([255, 136, 0, 136])
47
+ expect(parseColor("transparent").toInts()).toEqual([0, 0, 0, 0])
48
+ expect(rgbToHex(RGBA.fromInts(255, 128, 64, 128))).toBe("#ff804080")
49
+ })
50
+
51
+ test("normalizes ColorInput values", () => {
52
+ expect(normalizeColorValue(null)).toBeNull()
53
+ expect(normalizeColorValue("#123456")?.rgba.toInts()).toEqual([0x12, 0x34, 0x56, 255])
54
+ })
55
+
56
+ test("compares packed values exactly", () => {
57
+ expect(RGBA.fromIndex(4, "#0000ff").equals(RGBA.fromInts(0, 0, 255))).toBe(false)
58
+ expect(RGBA.clone(RGBA.fromIndex(4)).equals(RGBA.fromIndex(4))).toBe(true)
59
+ })
60
+ })
@@ -0,0 +1,343 @@
1
+ export type RGBTriplet = readonly [number, number, number]
2
+ export type ColorIntent = "rgb" | "indexed" | "default"
3
+ export type ColorInput = string | RGBA
4
+
5
+ export const DEFAULT_FOREGROUND_RGB: RGBTriplet = [255, 255, 255]
6
+ export const DEFAULT_BACKGROUND_RGB: RGBTriplet = [0, 0, 0]
7
+
8
+ const INTENT_RGB = 0
9
+ const INTENT_INDEXED = 1
10
+ const INTENT_DEFAULT = 2
11
+
12
+ const ANSI16_RGB: readonly RGBTriplet[] = [
13
+ [0x00, 0x00, 0x00],
14
+ [0x80, 0x00, 0x00],
15
+ [0x00, 0x80, 0x00],
16
+ [0x80, 0x80, 0x00],
17
+ [0x00, 0x00, 0x80],
18
+ [0x80, 0x00, 0x80],
19
+ [0x00, 0x80, 0x80],
20
+ [0xc0, 0xc0, 0xc0],
21
+ [0x80, 0x80, 0x80],
22
+ [0xff, 0x00, 0x00],
23
+ [0x00, 0xff, 0x00],
24
+ [0xff, 0xff, 0x00],
25
+ [0x00, 0x00, 0xff],
26
+ [0xff, 0x00, 0xff],
27
+ [0x00, 0xff, 0xff],
28
+ [0xff, 0xff, 0xff],
29
+ ]
30
+
31
+ const ANSI_256_CUBE_LEVELS = [0, 95, 135, 175, 215, 255] as const
32
+
33
+ export interface NormalizedColorValue {
34
+ rgba: RGBA
35
+ }
36
+
37
+ function packMeta(intent: number, slot = 0): number {
38
+ return ((slot & 0xff) | ((intent & 0xff) << 8)) >>> 0
39
+ }
40
+
41
+ function toU8(value: number): number {
42
+ return Math.round(Math.max(0, Math.min(1, Number.isFinite(value) ? value : 0)) * 255)
43
+ }
44
+
45
+ function toByte(value: number): number {
46
+ return Math.round(Math.max(0, Math.min(255, Number.isFinite(value) ? value : 0)))
47
+ }
48
+
49
+ function packRGBA8(r: number, g: number, b: number, a: number, meta: number): Uint16Array {
50
+ return new Uint16Array([
51
+ (toByte(r) & 0xff) | (((meta >>> 0) & 0xff) << 8),
52
+ (toByte(g) & 0xff) | (((meta >>> 8) & 0xff) << 8),
53
+ (toByte(b) & 0xff) | (((meta >>> 16) & 0xff) << 8),
54
+ (toByte(a) & 0xff) | (((meta >>> 24) & 0xff) << 8),
55
+ ])
56
+ }
57
+
58
+ function rgbaForAnsi256Index(index: number): RGBA {
59
+ const [r, g, b] = ansi256IndexToRgb(index)
60
+ return RGBA.fromInts(r, g, b)
61
+ }
62
+
63
+ export function normalizeIndexedColorIndex(index: number): number {
64
+ if (!Number.isInteger(index) || index < 0 || index > 255) {
65
+ throw new RangeError(`Indexed color must be an integer in the range 0..255, got ${index}`)
66
+ }
67
+
68
+ return index
69
+ }
70
+
71
+ export function ansi256IndexToRgb(index: number): RGBTriplet {
72
+ const normalizedIndex = normalizeIndexedColorIndex(index)
73
+
74
+ if (normalizedIndex < ANSI16_RGB.length) {
75
+ return ANSI16_RGB[normalizedIndex]
76
+ }
77
+
78
+ if (normalizedIndex < 232) {
79
+ const cubeIndex = normalizedIndex - 16
80
+ const r = Math.floor(cubeIndex / 36)
81
+ const g = Math.floor(cubeIndex / 6) % 6
82
+ const b = cubeIndex % 6
83
+ return [ANSI_256_CUBE_LEVELS[r], ANSI_256_CUBE_LEVELS[g], ANSI_256_CUBE_LEVELS[b]]
84
+ }
85
+
86
+ const value = 8 + (normalizedIndex - 232) * 10
87
+ return [value, value, value]
88
+ }
89
+
90
+ export class RGBA {
91
+ buffer: Uint16Array
92
+
93
+ constructor(buffer: Uint16Array) {
94
+ this.buffer = new Uint16Array(4)
95
+ this.buffer.set(buffer.subarray(0, 4))
96
+ }
97
+
98
+ static fromArray(array: Uint16Array): RGBA {
99
+ return new RGBA(array)
100
+ }
101
+
102
+ static fromValues(r: number, g: number, b: number, a: number = 1): RGBA {
103
+ return new RGBA(packRGBA8(toU8(r), toU8(g), toU8(b), toU8(a), packMeta(INTENT_RGB)))
104
+ }
105
+
106
+ static clone(rgba: RGBA): RGBA {
107
+ return new RGBA(rgba.buffer)
108
+ }
109
+
110
+ static fromInts(r: number, g: number, b: number, a: number = 255): RGBA {
111
+ return new RGBA(packRGBA8(r, g, b, a, packMeta(INTENT_RGB)))
112
+ }
113
+
114
+ static fromHex(hex: string): RGBA {
115
+ return hexToRgb(hex)
116
+ }
117
+
118
+ static fromIndex(index: number, snapshot?: ColorInput): RGBA {
119
+ const normalized = normalizeIndexedColorIndex(index)
120
+ const rgba = snapshot ? parseColor(snapshot) : rgbaForAnsi256Index(normalized)
121
+ const [r, g, b, a] = rgba.toInts()
122
+ return new RGBA(packRGBA8(r, g, b, a, packMeta(INTENT_INDEXED, normalized)))
123
+ }
124
+
125
+ static defaultForeground(snapshot?: ColorInput): RGBA {
126
+ const rgba = snapshot ? parseColor(snapshot) : RGBA.fromInts(...DEFAULT_FOREGROUND_RGB)
127
+ const [r, g, b, a] = rgba.toInts()
128
+ return new RGBA(packRGBA8(r, g, b, a, packMeta(INTENT_DEFAULT)))
129
+ }
130
+
131
+ static defaultBackground(snapshot?: ColorInput): RGBA {
132
+ const rgba = snapshot ? parseColor(snapshot) : RGBA.fromInts(...DEFAULT_BACKGROUND_RGB)
133
+ const [r, g, b, a] = rgba.toInts()
134
+ return new RGBA(packRGBA8(r, g, b, a, packMeta(INTENT_DEFAULT)))
135
+ }
136
+
137
+ toInts(): [number, number, number, number] {
138
+ return [this.buffer[0] & 0xff, this.buffer[1] & 0xff, this.buffer[2] & 0xff, this.buffer[3] & 0xff]
139
+ }
140
+
141
+ get r(): number {
142
+ return (this.buffer[0] & 0xff) / 255
143
+ }
144
+
145
+ set r(value: number) {
146
+ this.buffer[0] = (this.buffer[0] & 0xff00) | toU8(value)
147
+ }
148
+
149
+ get g(): number {
150
+ return (this.buffer[1] & 0xff) / 255
151
+ }
152
+
153
+ set g(value: number) {
154
+ this.buffer[1] = (this.buffer[1] & 0xff00) | toU8(value)
155
+ }
156
+
157
+ get b(): number {
158
+ return (this.buffer[2] & 0xff) / 255
159
+ }
160
+
161
+ set b(value: number) {
162
+ this.buffer[2] = (this.buffer[2] & 0xff00) | toU8(value)
163
+ }
164
+
165
+ get a(): number {
166
+ return (this.buffer[3] & 0xff) / 255
167
+ }
168
+
169
+ set a(value: number) {
170
+ this.buffer[3] = (this.buffer[3] & 0xff00) | toU8(value)
171
+ }
172
+
173
+ get meta(): number {
174
+ return (
175
+ ((this.buffer[0] >>> 8) |
176
+ ((this.buffer[1] >>> 8) << 8) |
177
+ ((this.buffer[2] >>> 8) << 16) |
178
+ ((this.buffer[3] >>> 8) << 24)) >>>
179
+ 0
180
+ )
181
+ }
182
+
183
+ get intent(): ColorIntent {
184
+ switch ((this.meta >>> 8) & 0xff) {
185
+ case INTENT_INDEXED:
186
+ return "indexed"
187
+ case INTENT_DEFAULT:
188
+ return "default"
189
+ default:
190
+ return "rgb"
191
+ }
192
+ }
193
+
194
+ get slot(): number {
195
+ return this.meta & 0xff
196
+ }
197
+
198
+ map<R>(fn: (value: number) => R): [R, R, R, R] {
199
+ return [fn(this.r), fn(this.g), fn(this.b), fn(this.a)]
200
+ }
201
+
202
+ toString(): string {
203
+ return `rgba(${this.r.toFixed(2)}, ${this.g.toFixed(2)}, ${this.b.toFixed(2)}, ${this.a.toFixed(2)})`
204
+ }
205
+
206
+ equals(other?: RGBA): boolean {
207
+ if (!other) return false
208
+ return (
209
+ this.buffer[0] === other.buffer[0] &&
210
+ this.buffer[1] === other.buffer[1] &&
211
+ this.buffer[2] === other.buffer[2] &&
212
+ this.buffer[3] === other.buffer[3]
213
+ )
214
+ }
215
+ }
216
+
217
+ export function normalizeColorValue(value: ColorInput | null | undefined): NormalizedColorValue | null {
218
+ if (value == null) return null
219
+ return { rgba: parseColor(value) }
220
+ }
221
+
222
+ export function hexToRgb(hex: string): RGBA {
223
+ hex = hex.replace(/^#/, "")
224
+
225
+ if (hex.length === 3) {
226
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]
227
+ } else if (hex.length === 4) {
228
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3]
229
+ }
230
+
231
+ if (!/^[0-9A-Fa-f]{6}$/.test(hex) && !/^[0-9A-Fa-f]{8}$/.test(hex)) {
232
+ console.warn(`Invalid hex color: ${hex}, defaulting to magenta`)
233
+ return RGBA.fromValues(1, 0, 1, 1)
234
+ }
235
+
236
+ const r = parseInt(hex.substring(0, 2), 16)
237
+ const g = parseInt(hex.substring(2, 4), 16)
238
+ const b = parseInt(hex.substring(4, 6), 16)
239
+ const a = hex.length === 8 ? parseInt(hex.substring(6, 8), 16) : 255
240
+
241
+ return RGBA.fromInts(r, g, b, a)
242
+ }
243
+
244
+ export function rgbToHex(rgb: RGBA): string {
245
+ const [r, g, b, a] = rgb.toInts()
246
+ const components = a === 255 ? [r, g, b] : [r, g, b, a]
247
+ return "#" + components.map((x) => x.toString(16).padStart(2, "0")).join("")
248
+ }
249
+
250
+ export function hsvToRgb(h: number, s: number, v: number): RGBA {
251
+ let r = 0,
252
+ g = 0,
253
+ b = 0
254
+
255
+ const i = Math.floor(h / 60) % 6
256
+ const f = h / 60 - Math.floor(h / 60)
257
+ const p = v * (1 - s)
258
+ const q = v * (1 - f * s)
259
+ const t = v * (1 - (1 - f) * s)
260
+
261
+ switch (i) {
262
+ case 0:
263
+ r = v
264
+ g = t
265
+ b = p
266
+ break
267
+ case 1:
268
+ r = q
269
+ g = v
270
+ b = p
271
+ break
272
+ case 2:
273
+ r = p
274
+ g = v
275
+ b = t
276
+ break
277
+ case 3:
278
+ r = p
279
+ g = q
280
+ b = v
281
+ break
282
+ case 4:
283
+ r = t
284
+ g = p
285
+ b = v
286
+ break
287
+ case 5:
288
+ r = v
289
+ g = p
290
+ b = q
291
+ break
292
+ }
293
+
294
+ return RGBA.fromValues(r, g, b, 1)
295
+ }
296
+
297
+ const CSS_COLOR_NAMES: Record<string, string> = {
298
+ black: "#000000",
299
+ white: "#FFFFFF",
300
+ red: "#FF0000",
301
+ green: "#008000",
302
+ blue: "#0000FF",
303
+ yellow: "#FFFF00",
304
+ cyan: "#00FFFF",
305
+ magenta: "#FF00FF",
306
+ silver: "#C0C0C0",
307
+ gray: "#808080",
308
+ grey: "#808080",
309
+ maroon: "#800000",
310
+ olive: "#808000",
311
+ lime: "#00FF00",
312
+ aqua: "#00FFFF",
313
+ teal: "#008080",
314
+ navy: "#000080",
315
+ fuchsia: "#FF00FF",
316
+ purple: "#800080",
317
+ orange: "#FFA500",
318
+ brightblack: "#666666",
319
+ brightred: "#FF6666",
320
+ brightgreen: "#66FF66",
321
+ brightblue: "#6666FF",
322
+ brightyellow: "#FFFF66",
323
+ brightcyan: "#66FFFF",
324
+ brightmagenta: "#FF66FF",
325
+ brightwhite: "#FFFFFF",
326
+ }
327
+
328
+ export function parseColor(color: ColorInput): RGBA {
329
+ if (typeof color === "string") {
330
+ const lowerColor = color.toLowerCase()
331
+
332
+ if (lowerColor === "transparent") {
333
+ return RGBA.fromValues(0, 0, 0, 0)
334
+ }
335
+
336
+ if (CSS_COLOR_NAMES[lowerColor]) {
337
+ return hexToRgb(CSS_COLOR_NAMES[lowerColor])
338
+ }
339
+
340
+ return hexToRgb(color)
341
+ }
342
+ return color
343
+ }