@fairyhunter13/opentui-core 0.1.112 → 0.1.114

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (591) hide show
  1. package/dev/keypress-debug-renderer.ts +148 -0
  2. package/dev/keypress-debug.ts +43 -0
  3. package/dev/print-env-vars.ts +32 -0
  4. package/dev/test-tmux-graphics-334.sh +68 -0
  5. package/dev/thai-debug-test.ts +68 -0
  6. package/docs/development.md +144 -0
  7. package/package.json +63 -51
  8. package/scripts/build.ts +400 -0
  9. package/scripts/publish.ts +60 -0
  10. package/src/3d/SpriteResourceManager.ts +286 -0
  11. package/src/3d/SpriteUtils.ts +70 -0
  12. package/src/3d/TextureUtils.ts +196 -0
  13. package/src/3d/ThreeRenderable.ts +197 -0
  14. package/src/3d/WGPURenderer.ts +294 -0
  15. package/src/3d/animation/ExplodingSpriteEffect.ts +513 -0
  16. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +429 -0
  17. package/src/3d/animation/SpriteAnimator.ts +633 -0
  18. package/src/3d/animation/SpriteParticleGenerator.ts +435 -0
  19. package/src/3d/canvas.ts +464 -0
  20. package/src/3d/index.ts +12 -0
  21. package/src/3d/physics/PlanckPhysicsAdapter.ts +72 -0
  22. package/src/3d/physics/RapierPhysicsAdapter.ts +66 -0
  23. package/src/3d/physics/physics-interface.ts +31 -0
  24. package/src/3d/shaders/supersampling.wgsl +201 -0
  25. package/src/3d.ts +3 -0
  26. package/src/NativeSpanFeed.ts +300 -0
  27. package/src/Renderable.ts +1704 -0
  28. package/src/__snapshots__/buffer.test.ts.snap +28 -0
  29. package/src/animation/Timeline.test.ts +2709 -0
  30. package/src/animation/Timeline.ts +598 -0
  31. package/src/ansi.ts +18 -0
  32. package/src/benchmark/attenuation-benchmark.ts +81 -0
  33. package/src/benchmark/colormatrix-benchmark.ts +128 -0
  34. package/src/benchmark/gain-benchmark.ts +80 -0
  35. package/src/benchmark/latest-all-bench-run.json +707 -0
  36. package/src/benchmark/latest-async-bench-run.json +336 -0
  37. package/src/benchmark/latest-default-bench-run.json +657 -0
  38. package/src/benchmark/latest-large-bench-run.json +707 -0
  39. package/src/benchmark/latest-quick-bench-run.json +207 -0
  40. package/src/benchmark/markdown-benchmark.ts +1796 -0
  41. package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
  42. package/src/benchmark/native-span-feed-benchmark.md +56 -0
  43. package/src/benchmark/native-span-feed-benchmark.ts +596 -0
  44. package/src/benchmark/native-span-feed-compare.ts +280 -0
  45. package/src/benchmark/renderer-benchmark.ts +754 -0
  46. package/src/benchmark/text-table-benchmark.ts +948 -0
  47. package/src/buffer.test.ts +291 -0
  48. package/src/buffer.ts +554 -0
  49. package/src/console.test.ts +612 -0
  50. package/src/console.ts +1254 -0
  51. package/src/edit-buffer.test.ts +1769 -0
  52. package/src/edit-buffer.ts +411 -0
  53. package/src/editor-view.test.ts +1032 -0
  54. package/src/editor-view.ts +284 -0
  55. package/src/examples/ascii-font-selection-demo.ts +245 -0
  56. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  57. package/src/examples/assets/concrete.png +0 -0
  58. package/src/examples/assets/crate.png +0 -0
  59. package/src/examples/assets/crate_emissive.png +0 -0
  60. package/src/examples/assets/forrest_background.png +0 -0
  61. package/src/examples/assets/hast-example.json +1018 -0
  62. package/src/examples/assets/heart.png +0 -0
  63. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  64. package/src/examples/assets/main_char_idle.png +0 -0
  65. package/src/examples/assets/main_char_jump_end.png +0 -0
  66. package/src/examples/assets/main_char_jump_landing.png +0 -0
  67. package/src/examples/assets/main_char_jump_start.png +0 -0
  68. package/src/examples/assets/main_char_run_loop.png +0 -0
  69. package/src/examples/assets/roughness_map.jpg +0 -0
  70. package/src/examples/build.ts +115 -0
  71. package/src/examples/code-demo.ts +924 -0
  72. package/src/examples/console-demo.ts +358 -0
  73. package/src/examples/core-plugin-slots-demo.ts +759 -0
  74. package/src/examples/diff-demo.ts +701 -0
  75. package/src/examples/draggable-three-demo.ts +259 -0
  76. package/src/examples/editor-demo.ts +322 -0
  77. package/src/examples/extmarks-demo.ts +196 -0
  78. package/src/examples/focus-restore-demo.ts +310 -0
  79. package/src/examples/fonts.ts +245 -0
  80. package/src/examples/fractal-shader-demo.ts +268 -0
  81. package/src/examples/framebuffer-demo.ts +674 -0
  82. package/src/examples/full-unicode-demo.ts +241 -0
  83. package/src/examples/golden-star-demo.ts +933 -0
  84. package/src/examples/grayscale-buffer-demo.ts +249 -0
  85. package/src/examples/hast-syntax-highlighting-demo.ts +129 -0
  86. package/src/examples/index.ts +926 -0
  87. package/src/examples/input-demo.ts +377 -0
  88. package/src/examples/input-select-layout-demo.ts +425 -0
  89. package/src/examples/install.sh +143 -0
  90. package/src/examples/keypress-debug-demo.ts +452 -0
  91. package/src/examples/lib/HexList.ts +122 -0
  92. package/src/examples/lib/PaletteGrid.ts +125 -0
  93. package/src/examples/lib/standalone-keys.ts +25 -0
  94. package/src/examples/lib/tab-controller.ts +243 -0
  95. package/src/examples/lights-phong-demo.ts +290 -0
  96. package/src/examples/link-demo.ts +220 -0
  97. package/src/examples/live-state-demo.ts +480 -0
  98. package/src/examples/markdown-demo.ts +725 -0
  99. package/src/examples/mouse-interaction-demo.ts +428 -0
  100. package/src/examples/nested-zindex-demo.ts +357 -0
  101. package/src/examples/opacity-example.ts +235 -0
  102. package/src/examples/opentui-demo.ts +1057 -0
  103. package/src/examples/physx-planck-2d-demo.ts +623 -0
  104. package/src/examples/physx-rapier-2d-demo.ts +655 -0
  105. package/src/examples/relative-positioning-demo.ts +323 -0
  106. package/src/examples/scroll-example.ts +214 -0
  107. package/src/examples/scrollbox-mouse-test.ts +112 -0
  108. package/src/examples/scrollbox-overlay-hit-test.ts +206 -0
  109. package/src/examples/select-demo.ts +237 -0
  110. package/src/examples/shader-cube-demo.ts +1015 -0
  111. package/src/examples/simple-layout-example.ts +591 -0
  112. package/src/examples/slider-demo.ts +617 -0
  113. package/src/examples/split-mode-demo.ts +453 -0
  114. package/src/examples/sprite-animation-demo.ts +443 -0
  115. package/src/examples/sprite-particle-generator-demo.ts +486 -0
  116. package/src/examples/static-sprite-demo.ts +193 -0
  117. package/src/examples/sticky-scroll-example.ts +308 -0
  118. package/src/examples/styled-text-demo.ts +282 -0
  119. package/src/examples/tab-select-demo.ts +219 -0
  120. package/src/examples/terminal-title.ts +29 -0
  121. package/src/examples/terminal.ts +305 -0
  122. package/src/examples/text-node-demo.ts +416 -0
  123. package/src/examples/text-selection-demo.ts +377 -0
  124. package/src/examples/text-table-demo.ts +503 -0
  125. package/src/examples/text-truncation-demo.ts +481 -0
  126. package/src/examples/text-wrap.ts +757 -0
  127. package/src/examples/texture-loading-demo.ts +259 -0
  128. package/src/examples/timeline-example.ts +670 -0
  129. package/src/examples/transparency-demo.ts +400 -0
  130. package/src/examples/vnode-composition-demo.ts +404 -0
  131. package/src/examples/wide-grapheme-overlay-demo.ts +280 -0
  132. package/src/index.ts +24 -0
  133. package/src/lib/KeyHandler.integration.test.ts +292 -0
  134. package/src/lib/KeyHandler.stopPropagation.test.ts +289 -0
  135. package/src/lib/KeyHandler.test.ts +662 -0
  136. package/src/lib/KeyHandler.ts +222 -0
  137. package/src/lib/RGBA.test.ts +984 -0
  138. package/src/lib/RGBA.ts +204 -0
  139. package/src/lib/ascii.font.ts +330 -0
  140. package/src/lib/border.test.ts +83 -0
  141. package/src/lib/border.ts +170 -0
  142. package/src/lib/bunfs.test.ts +27 -0
  143. package/src/lib/bunfs.ts +18 -0
  144. package/src/lib/clipboard.test.ts +41 -0
  145. package/src/lib/clipboard.ts +47 -0
  146. package/src/lib/clock.ts +35 -0
  147. package/src/lib/data-paths.test.ts +133 -0
  148. package/src/lib/data-paths.ts +109 -0
  149. package/src/lib/debounce.ts +106 -0
  150. package/src/lib/detect-links.test.ts +98 -0
  151. package/src/lib/detect-links.ts +56 -0
  152. package/src/lib/env.test.ts +228 -0
  153. package/src/lib/env.ts +209 -0
  154. package/src/lib/extmarks-history.ts +51 -0
  155. package/src/lib/extmarks-multiwidth.test.ts +322 -0
  156. package/src/lib/extmarks.test.ts +3457 -0
  157. package/src/lib/extmarks.ts +843 -0
  158. package/src/lib/fonts/block.json +405 -0
  159. package/src/lib/fonts/grid.json +265 -0
  160. package/src/lib/fonts/huge.json +741 -0
  161. package/src/lib/fonts/pallet.json +314 -0
  162. package/src/lib/fonts/shade.json +591 -0
  163. package/src/lib/fonts/slick.json +321 -0
  164. package/src/lib/fonts/tiny.json +69 -0
  165. package/src/lib/hast-styled-text.ts +59 -0
  166. package/src/lib/index.ts +21 -0
  167. package/src/lib/keymapping.test.ts +317 -0
  168. package/src/lib/keymapping.ts +115 -0
  169. package/src/lib/objects-in-viewport.test.ts +787 -0
  170. package/src/lib/objects-in-viewport.ts +153 -0
  171. package/src/lib/output.capture.ts +58 -0
  172. package/src/lib/parse.keypress-kitty.protocol.test.ts +340 -0
  173. package/src/lib/parse.keypress-kitty.test.ts +663 -0
  174. package/src/lib/parse.keypress-kitty.ts +439 -0
  175. package/src/lib/parse.keypress.test.ts +1849 -0
  176. package/src/lib/parse.keypress.ts +397 -0
  177. package/src/lib/parse.mouse.test.ts +552 -0
  178. package/src/lib/parse.mouse.ts +232 -0
  179. package/src/lib/paste.ts +16 -0
  180. package/src/lib/queue.ts +65 -0
  181. package/src/lib/renderable.validations.test.ts +87 -0
  182. package/src/lib/renderable.validations.ts +83 -0
  183. package/src/lib/scroll-acceleration.ts +98 -0
  184. package/src/lib/selection.ts +240 -0
  185. package/src/lib/singleton.ts +28 -0
  186. package/src/lib/stdin-parser.test.ts +2290 -0
  187. package/src/lib/stdin-parser.ts +1810 -0
  188. package/src/lib/styled-text.ts +178 -0
  189. package/src/lib/terminal-capability-detection.test.ts +202 -0
  190. package/src/lib/terminal-capability-detection.ts +79 -0
  191. package/src/lib/terminal-palette.test.ts +878 -0
  192. package/src/lib/terminal-palette.ts +383 -0
  193. package/src/lib/tree-sitter/assets/README.md +118 -0
  194. package/src/lib/tree-sitter/assets/update.ts +334 -0
  195. package/src/lib/tree-sitter/assets.d.ts +9 -0
  196. package/src/lib/tree-sitter/cache.test.ts +273 -0
  197. package/src/lib/tree-sitter/client.test.ts +1165 -0
  198. package/src/lib/tree-sitter/client.ts +607 -0
  199. package/src/lib/tree-sitter/default-parsers.ts +86 -0
  200. package/src/lib/tree-sitter/download-utils.ts +148 -0
  201. package/src/lib/tree-sitter/index.ts +28 -0
  202. package/src/lib/tree-sitter/parser.worker.ts +1042 -0
  203. package/src/lib/tree-sitter/parsers-config.ts +81 -0
  204. package/src/lib/tree-sitter/resolve-ft.test.ts +55 -0
  205. package/src/lib/tree-sitter/resolve-ft.ts +189 -0
  206. package/src/lib/tree-sitter/types.ts +82 -0
  207. package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
  208. package/src/lib/tree-sitter-styled-text.ts +306 -0
  209. package/src/lib/validate-dir-name.ts +55 -0
  210. package/src/lib/yoga.options.test.ts +628 -0
  211. package/src/lib/yoga.options.ts +346 -0
  212. package/src/plugins/core-slot.ts +579 -0
  213. package/src/plugins/registry.ts +402 -0
  214. package/src/plugins/types.ts +46 -0
  215. package/src/post/effects.ts +930 -0
  216. package/src/post/filters.ts +489 -0
  217. package/src/post/matrices.ts +288 -0
  218. package/src/renderables/ASCIIFont.ts +219 -0
  219. package/src/renderables/Box.test.ts +205 -0
  220. package/src/renderables/Box.ts +326 -0
  221. package/src/renderables/Code.test.ts +2062 -0
  222. package/src/renderables/Code.ts +357 -0
  223. package/src/renderables/Diff.regression.test.ts +226 -0
  224. package/src/renderables/Diff.test.ts +3101 -0
  225. package/src/renderables/Diff.ts +1211 -0
  226. package/src/renderables/EditBufferRenderable.test.ts +288 -0
  227. package/src/renderables/EditBufferRenderable.ts +1166 -0
  228. package/src/renderables/FrameBuffer.ts +47 -0
  229. package/src/renderables/Input.test.ts +1228 -0
  230. package/src/renderables/Input.ts +247 -0
  231. package/src/renderables/LineNumberRenderable.ts +724 -0
  232. package/src/renderables/Markdown.ts +1393 -0
  233. package/src/renderables/ScrollBar.ts +422 -0
  234. package/src/renderables/ScrollBox.ts +883 -0
  235. package/src/renderables/Select.test.ts +1033 -0
  236. package/src/renderables/Select.ts +524 -0
  237. package/src/renderables/Slider.test.ts +456 -0
  238. package/src/renderables/Slider.ts +342 -0
  239. package/src/renderables/TabSelect.test.ts +197 -0
  240. package/src/renderables/TabSelect.ts +455 -0
  241. package/src/renderables/Text.selection-buffer.test.ts +123 -0
  242. package/src/renderables/Text.test.ts +2660 -0
  243. package/src/renderables/Text.ts +147 -0
  244. package/src/renderables/TextBufferRenderable.ts +518 -0
  245. package/src/renderables/TextNode.test.ts +1058 -0
  246. package/src/renderables/TextNode.ts +325 -0
  247. package/src/renderables/TextTable.test.ts +1421 -0
  248. package/src/renderables/TextTable.ts +1344 -0
  249. package/src/renderables/Textarea.ts +430 -0
  250. package/src/renderables/TimeToFirstDraw.ts +89 -0
  251. package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
  252. package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
  253. package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
  254. package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
  255. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
  256. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +816 -0
  257. package/src/renderables/__tests__/LineNumberRenderable.test.ts +1865 -0
  258. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
  259. package/src/renderables/__tests__/Markdown.code-colors.test.ts +242 -0
  260. package/src/renderables/__tests__/Markdown.test.ts +2518 -0
  261. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
  262. package/src/renderables/__tests__/Textarea.buffer.test.ts +682 -0
  263. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
  264. package/src/renderables/__tests__/Textarea.editing.test.ts +2041 -0
  265. package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
  266. package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
  267. package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
  268. package/src/renderables/__tests__/Textarea.keybinding.test.ts +3149 -0
  269. package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
  270. package/src/renderables/__tests__/Textarea.rendering.test.ts +1866 -0
  271. package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
  272. package/src/renderables/__tests__/Textarea.selection.test.ts +1590 -0
  273. package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
  274. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
  275. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
  276. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
  277. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
  278. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
  279. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
  280. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
  281. package/src/renderables/__tests__/markdown-parser.test.ts +217 -0
  282. package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
  283. package/src/renderables/composition/README.md +8 -0
  284. package/src/renderables/composition/VRenderable.ts +32 -0
  285. package/src/renderables/composition/constructs.ts +127 -0
  286. package/src/renderables/composition/vnode.ts +289 -0
  287. package/src/renderables/index.ts +23 -0
  288. package/src/renderables/markdown-parser.ts +66 -0
  289. package/src/renderer.ts +2681 -0
  290. package/src/runtime-plugin-support.ts +39 -0
  291. package/src/runtime-plugin.ts +615 -0
  292. package/src/syntax-style.test.ts +841 -0
  293. package/src/syntax-style.ts +257 -0
  294. package/src/testing/README.md +210 -0
  295. package/src/testing/capture-spans.test.ts +194 -0
  296. package/src/testing/integration.test.ts +276 -0
  297. package/src/testing/manual-clock.ts +117 -0
  298. package/src/testing/mock-keys.test.ts +1378 -0
  299. package/src/testing/mock-keys.ts +457 -0
  300. package/src/testing/mock-mouse.test.ts +218 -0
  301. package/src/testing/mock-mouse.ts +247 -0
  302. package/src/testing/mock-tree-sitter-client.ts +73 -0
  303. package/src/testing/spy.ts +13 -0
  304. package/src/testing/test-recorder.test.ts +415 -0
  305. package/src/testing/test-recorder.ts +145 -0
  306. package/src/testing/test-renderer.ts +132 -0
  307. package/src/testing.ts +7 -0
  308. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
  309. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
  310. package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
  311. package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
  312. package/src/tests/allocator-stats.test.ts +38 -0
  313. package/src/tests/destroy-during-render.test.ts +200 -0
  314. package/src/tests/destroy-on-exit.fixture.ts +36 -0
  315. package/src/tests/destroy-on-exit.test.ts +41 -0
  316. package/src/tests/hover-cursor.test.ts +98 -0
  317. package/src/tests/native-span-feed-async.test.ts +173 -0
  318. package/src/tests/native-span-feed-close.test.ts +120 -0
  319. package/src/tests/native-span-feed-coverage.test.ts +227 -0
  320. package/src/tests/native-span-feed-edge-cases.test.ts +352 -0
  321. package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
  322. package/src/tests/opacity.test.ts +123 -0
  323. package/src/tests/renderable.snapshot.test.ts +524 -0
  324. package/src/tests/renderable.test.ts +1281 -0
  325. package/src/tests/renderer.clock.test.ts +158 -0
  326. package/src/tests/renderer.console-startup.test.ts +185 -0
  327. package/src/tests/renderer.control.test.ts +425 -0
  328. package/src/tests/renderer.core-slot-binding.test.ts +952 -0
  329. package/src/tests/renderer.cursor.test.ts +26 -0
  330. package/src/tests/renderer.destroy-during-render.test.ts +147 -0
  331. package/src/tests/renderer.focus-restore.test.ts +257 -0
  332. package/src/tests/renderer.focus.test.ts +294 -0
  333. package/src/tests/renderer.idle.test.ts +219 -0
  334. package/src/tests/renderer.input.test.ts +2237 -0
  335. package/src/tests/renderer.kitty-flags.test.ts +195 -0
  336. package/src/tests/renderer.mouse.test.ts +1274 -0
  337. package/src/tests/renderer.palette.test.ts +629 -0
  338. package/src/tests/renderer.selection.test.ts +49 -0
  339. package/src/tests/renderer.slot-registry.test.ts +684 -0
  340. package/src/tests/renderer.useMouse.test.ts +47 -0
  341. package/src/tests/runtime-plugin-node-modules-cycle.fixture.ts +76 -0
  342. package/src/tests/runtime-plugin-node-modules-mjs.fixture.ts +43 -0
  343. package/src/tests/runtime-plugin-node-modules-no-bare-rewrite.fixture.ts +67 -0
  344. package/src/tests/runtime-plugin-node-modules-package-type-cache.fixture.ts +72 -0
  345. package/src/tests/runtime-plugin-node-modules-runtime-specifier.fixture.ts +44 -0
  346. package/src/tests/runtime-plugin-node-modules-scoped-package-bare-rewrite.fixture.ts +85 -0
  347. package/src/tests/runtime-plugin-path-alias.fixture.ts +43 -0
  348. package/src/tests/runtime-plugin-resolve-roots.fixture.ts +65 -0
  349. package/src/tests/runtime-plugin-support.fixture.ts +11 -0
  350. package/src/tests/runtime-plugin-support.test.ts +19 -0
  351. package/src/tests/runtime-plugin-windows-file-url.fixture.ts +30 -0
  352. package/src/tests/runtime-plugin.fixture.ts +40 -0
  353. package/src/tests/runtime-plugin.test.ts +354 -0
  354. package/src/tests/scrollbox-culling-bug.test.ts +114 -0
  355. package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
  356. package/src/tests/scrollbox-hitgrid.test.ts +909 -0
  357. package/src/tests/scrollbox.test.ts +1530 -0
  358. package/src/tests/wrap-resize-perf.test.ts +276 -0
  359. package/src/tests/yoga-setters.test.ts +921 -0
  360. package/src/text-buffer-view.test.ts +705 -0
  361. package/src/text-buffer-view.ts +189 -0
  362. package/src/text-buffer.test.ts +347 -0
  363. package/src/text-buffer.ts +250 -0
  364. package/src/types.ts +161 -0
  365. package/src/utils.ts +88 -0
  366. package/src/zig/ansi.zig +268 -0
  367. package/src/zig/bench/README.md +50 -0
  368. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +887 -0
  369. package/src/zig/bench/edit-buffer_bench.zig +476 -0
  370. package/src/zig/bench/native-span-feed_bench.zig +100 -0
  371. package/src/zig/bench/rope-markers_bench.zig +713 -0
  372. package/src/zig/bench/rope_bench.zig +514 -0
  373. package/src/zig/bench/styled-text_bench.zig +470 -0
  374. package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
  375. package/src/zig/bench/text-buffer-view_bench.zig +459 -0
  376. package/src/zig/bench/text-chunk-graphemes_bench.zig +273 -0
  377. package/src/zig/bench/utf8_bench.zig +799 -0
  378. package/src/zig/bench-utils.zig +431 -0
  379. package/src/zig/bench.zig +217 -0
  380. package/src/zig/buffer-methods.zig +211 -0
  381. package/src/zig/buffer.zig +2281 -0
  382. package/src/zig/build.zig +289 -0
  383. package/src/zig/build.zig.zon +16 -0
  384. package/src/zig/edit-buffer.zig +825 -0
  385. package/src/zig/editor-view.zig +802 -0
  386. package/src/zig/event-bus.zig +13 -0
  387. package/src/zig/event-emitter.zig +65 -0
  388. package/src/zig/file-logger.zig +92 -0
  389. package/src/zig/grapheme.zig +599 -0
  390. package/src/zig/lib.zig +1854 -0
  391. package/src/zig/link.zig +333 -0
  392. package/src/zig/logger.zig +43 -0
  393. package/src/zig/mem-registry.zig +125 -0
  394. package/src/zig/native-span-feed-bench-lib.zig +7 -0
  395. package/src/zig/native-span-feed.zig +708 -0
  396. package/src/zig/renderer.zig +1393 -0
  397. package/src/zig/rope.zig +1220 -0
  398. package/src/zig/syntax-style.zig +161 -0
  399. package/src/zig/terminal.zig +987 -0
  400. package/src/zig/test.zig +72 -0
  401. package/src/zig/tests/README.md +18 -0
  402. package/src/zig/tests/buffer-methods_test.zig +1109 -0
  403. package/src/zig/tests/buffer_test.zig +2557 -0
  404. package/src/zig/tests/edit-buffer-history_test.zig +271 -0
  405. package/src/zig/tests/edit-buffer_test.zig +1689 -0
  406. package/src/zig/tests/editor-view_test.zig +3299 -0
  407. package/src/zig/tests/event-emitter_test.zig +249 -0
  408. package/src/zig/tests/grapheme_test.zig +1304 -0
  409. package/src/zig/tests/link_test.zig +190 -0
  410. package/src/zig/tests/mem-registry_test.zig +473 -0
  411. package/src/zig/tests/memory_leak_regression_test.zig +159 -0
  412. package/src/zig/tests/native-span-feed_test.zig +1264 -0
  413. package/src/zig/tests/renderer_test.zig +1017 -0
  414. package/src/zig/tests/rope-nested_test.zig +712 -0
  415. package/src/zig/tests/rope_fuzz_test.zig +238 -0
  416. package/src/zig/tests/rope_test.zig +2362 -0
  417. package/src/zig/tests/segment-merge.test.zig +148 -0
  418. package/src/zig/tests/syntax-style_test.zig +557 -0
  419. package/src/zig/tests/terminal_test.zig +754 -0
  420. package/src/zig/tests/text-buffer-drawing_test.zig +3237 -0
  421. package/src/zig/tests/text-buffer-highlights_test.zig +666 -0
  422. package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
  423. package/src/zig/tests/text-buffer-segment_test.zig +320 -0
  424. package/src/zig/tests/text-buffer-selection_test.zig +1035 -0
  425. package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
  426. package/src/zig/tests/text-buffer-view_test.zig +3649 -0
  427. package/src/zig/tests/text-buffer_test.zig +2191 -0
  428. package/src/zig/tests/unicode-width-map.zon +3909 -0
  429. package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
  430. package/src/zig/tests/utf8_test.zig +4057 -0
  431. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
  432. package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
  433. package/src/zig/tests/word-wrap-editing_test.zig +498 -0
  434. package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
  435. package/src/zig/text-buffer-iterators.zig +499 -0
  436. package/src/zig/text-buffer-segment.zig +404 -0
  437. package/src/zig/text-buffer-view.zig +1371 -0
  438. package/src/zig/text-buffer.zig +1180 -0
  439. package/src/zig/utf8.zig +1948 -0
  440. package/src/zig/utils.zig +9 -0
  441. package/src/zig-structs.ts +261 -0
  442. package/src/zig.ts +3884 -0
  443. package/tsconfig.build.json +24 -0
  444. package/tsconfig.json +27 -0
  445. package/3d/SpriteResourceManager.d.ts +0 -74
  446. package/3d/SpriteUtils.d.ts +0 -13
  447. package/3d/TextureUtils.d.ts +0 -24
  448. package/3d/ThreeRenderable.d.ts +0 -40
  449. package/3d/WGPURenderer.d.ts +0 -61
  450. package/3d/animation/ExplodingSpriteEffect.d.ts +0 -71
  451. package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +0 -76
  452. package/3d/animation/SpriteAnimator.d.ts +0 -124
  453. package/3d/animation/SpriteParticleGenerator.d.ts +0 -62
  454. package/3d/canvas.d.ts +0 -44
  455. package/3d/index.d.ts +0 -12
  456. package/3d/physics/PlanckPhysicsAdapter.d.ts +0 -19
  457. package/3d/physics/RapierPhysicsAdapter.d.ts +0 -19
  458. package/3d/physics/physics-interface.d.ts +0 -27
  459. package/3d.d.ts +0 -2
  460. package/3d.js +0 -34041
  461. package/3d.js.map +0 -155
  462. package/LICENSE +0 -21
  463. package/NativeSpanFeed.d.ts +0 -41
  464. package/Renderable.d.ts +0 -334
  465. package/animation/Timeline.d.ts +0 -126
  466. package/ansi.d.ts +0 -13
  467. package/buffer.d.ts +0 -111
  468. package/console.d.ts +0 -144
  469. package/edit-buffer.d.ts +0 -98
  470. package/editor-view.d.ts +0 -73
  471. package/index-8fks7yv1.js +0 -411
  472. package/index-8fks7yv1.js.map +0 -10
  473. package/index-egy5e2rs.js +0 -12267
  474. package/index-egy5e2rs.js.map +0 -42
  475. package/index-tse8gzh0.js +0 -20614
  476. package/index-tse8gzh0.js.map +0 -67
  477. package/index.d.ts +0 -23
  478. package/index.js +0 -478
  479. package/index.js.map +0 -9
  480. package/lib/KeyHandler.d.ts +0 -61
  481. package/lib/RGBA.d.ts +0 -25
  482. package/lib/ascii.font.d.ts +0 -508
  483. package/lib/border.d.ts +0 -51
  484. package/lib/bunfs.d.ts +0 -7
  485. package/lib/clipboard.d.ts +0 -17
  486. package/lib/clock.d.ts +0 -15
  487. package/lib/data-paths.d.ts +0 -26
  488. package/lib/debounce.d.ts +0 -42
  489. package/lib/detect-links.d.ts +0 -6
  490. package/lib/env.d.ts +0 -42
  491. package/lib/extmarks-history.d.ts +0 -17
  492. package/lib/extmarks.d.ts +0 -89
  493. package/lib/hast-styled-text.d.ts +0 -17
  494. package/lib/index.d.ts +0 -21
  495. package/lib/keymapping.d.ts +0 -25
  496. package/lib/objects-in-viewport.d.ts +0 -24
  497. package/lib/output.capture.d.ts +0 -24
  498. package/lib/parse.keypress-kitty.d.ts +0 -2
  499. package/lib/parse.keypress.d.ts +0 -26
  500. package/lib/parse.mouse.d.ts +0 -30
  501. package/lib/paste.d.ts +0 -7
  502. package/lib/queue.d.ts +0 -15
  503. package/lib/renderable.validations.d.ts +0 -12
  504. package/lib/scroll-acceleration.d.ts +0 -43
  505. package/lib/selection.d.ts +0 -63
  506. package/lib/singleton.d.ts +0 -7
  507. package/lib/stdin-parser.d.ts +0 -87
  508. package/lib/styled-text.d.ts +0 -63
  509. package/lib/terminal-capability-detection.d.ts +0 -30
  510. package/lib/terminal-palette.d.ts +0 -50
  511. package/lib/tree-sitter/assets/update.d.ts +0 -11
  512. package/lib/tree-sitter/client.d.ts +0 -47
  513. package/lib/tree-sitter/default-parsers.d.ts +0 -2
  514. package/lib/tree-sitter/download-utils.d.ts +0 -21
  515. package/lib/tree-sitter/index.d.ts +0 -8
  516. package/lib/tree-sitter/parser.worker.d.ts +0 -1
  517. package/lib/tree-sitter/parsers-config.d.ts +0 -53
  518. package/lib/tree-sitter/resolve-ft.d.ts +0 -5
  519. package/lib/tree-sitter/types.d.ts +0 -82
  520. package/lib/tree-sitter-styled-text.d.ts +0 -14
  521. package/lib/validate-dir-name.d.ts +0 -1
  522. package/lib/yoga.options.d.ts +0 -32
  523. package/parser.worker.js +0 -899
  524. package/parser.worker.js.map +0 -12
  525. package/plugins/core-slot.d.ts +0 -72
  526. package/plugins/registry.d.ts +0 -42
  527. package/plugins/types.d.ts +0 -34
  528. package/post/effects.d.ts +0 -147
  529. package/post/filters.d.ts +0 -65
  530. package/post/matrices.d.ts +0 -20
  531. package/renderables/ASCIIFont.d.ts +0 -52
  532. package/renderables/Box.d.ts +0 -81
  533. package/renderables/Code.d.ts +0 -78
  534. package/renderables/Diff.d.ts +0 -142
  535. package/renderables/EditBufferRenderable.d.ts +0 -237
  536. package/renderables/FrameBuffer.d.ts +0 -16
  537. package/renderables/Input.d.ts +0 -67
  538. package/renderables/LineNumberRenderable.d.ts +0 -78
  539. package/renderables/Markdown.d.ts +0 -185
  540. package/renderables/ScrollBar.d.ts +0 -77
  541. package/renderables/ScrollBox.d.ts +0 -124
  542. package/renderables/Select.d.ts +0 -115
  543. package/renderables/Slider.d.ts +0 -47
  544. package/renderables/TabSelect.d.ts +0 -96
  545. package/renderables/Text.d.ts +0 -36
  546. package/renderables/TextBufferRenderable.d.ts +0 -105
  547. package/renderables/TextNode.d.ts +0 -91
  548. package/renderables/TextTable.d.ts +0 -140
  549. package/renderables/Textarea.d.ts +0 -63
  550. package/renderables/TimeToFirstDraw.d.ts +0 -24
  551. package/renderables/__tests__/renderable-test-utils.d.ts +0 -12
  552. package/renderables/composition/VRenderable.d.ts +0 -16
  553. package/renderables/composition/constructs.d.ts +0 -35
  554. package/renderables/composition/vnode.d.ts +0 -46
  555. package/renderables/index.d.ts +0 -23
  556. package/renderables/markdown-parser.d.ts +0 -10
  557. package/renderer.d.ts +0 -419
  558. package/runtime-plugin-support.d.ts +0 -3
  559. package/runtime-plugin-support.js +0 -29
  560. package/runtime-plugin-support.js.map +0 -10
  561. package/runtime-plugin.d.ts +0 -16
  562. package/runtime-plugin.js +0 -16
  563. package/runtime-plugin.js.map +0 -9
  564. package/syntax-style.d.ts +0 -54
  565. package/testing/manual-clock.d.ts +0 -17
  566. package/testing/mock-keys.d.ts +0 -81
  567. package/testing/mock-mouse.d.ts +0 -38
  568. package/testing/mock-tree-sitter-client.d.ts +0 -23
  569. package/testing/spy.d.ts +0 -7
  570. package/testing/test-recorder.d.ts +0 -61
  571. package/testing/test-renderer.d.ts +0 -23
  572. package/testing.d.ts +0 -6
  573. package/testing.js +0 -697
  574. package/testing.js.map +0 -15
  575. package/text-buffer-view.d.ts +0 -42
  576. package/text-buffer.d.ts +0 -67
  577. package/types.d.ts +0 -139
  578. package/utils.d.ts +0 -14
  579. package/zig-structs.d.ts +0 -155
  580. package/zig.d.ts +0 -353
  581. /package/{assets → src/lib/tree-sitter/assets}/javascript/highlights.scm +0 -0
  582. /package/{assets → src/lib/tree-sitter/assets}/javascript/tree-sitter-javascript.wasm +0 -0
  583. /package/{assets → src/lib/tree-sitter/assets}/markdown/highlights.scm +0 -0
  584. /package/{assets → src/lib/tree-sitter/assets}/markdown/injections.scm +0 -0
  585. /package/{assets → src/lib/tree-sitter/assets}/markdown/tree-sitter-markdown.wasm +0 -0
  586. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/highlights.scm +0 -0
  587. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  588. /package/{assets → src/lib/tree-sitter/assets}/typescript/highlights.scm +0 -0
  589. /package/{assets → src/lib/tree-sitter/assets}/typescript/tree-sitter-typescript.wasm +0 -0
  590. /package/{assets → src/lib/tree-sitter/assets}/zig/highlights.scm +0 -0
  591. /package/{assets → src/lib/tree-sitter/assets}/zig/tree-sitter-zig.wasm +0 -0
@@ -0,0 +1,878 @@
1
+ import { test, expect } from "bun:test"
2
+ import { TerminalPalette } from "./terminal-palette.js"
3
+ import { EventEmitter } from "events"
4
+ import { Buffer } from "node:buffer"
5
+ import { ManualClock } from "../testing/manual-clock.js"
6
+
7
+ class MockStream extends EventEmitter {
8
+ isTTY = true
9
+ isRaw = false
10
+ isPaused() {
11
+ return false
12
+ }
13
+ write(_data: string) {
14
+ return true
15
+ }
16
+ }
17
+
18
+ function createPaletteHarness(
19
+ options: {
20
+ writeFn?: (data: string | Buffer) => boolean
21
+ oscSource?: {
22
+ subscribeOsc(handler: (sequence: string) => void): () => void
23
+ }
24
+ } = {},
25
+ ) {
26
+ const stdin = new MockStream() as any
27
+ const stdout = new MockStream() as any
28
+ const clock = new ManualClock()
29
+ const palette = new TerminalPalette(stdin, stdout, options.writeFn, false, options.oscSource, clock)
30
+
31
+ return { stdin, stdout, clock, palette }
32
+ }
33
+
34
+ async function flushAsync(): Promise<void> {
35
+ await Promise.resolve()
36
+ await Promise.resolve()
37
+ }
38
+
39
+ async function startPaletteDetection(
40
+ options: {
41
+ timeout?: number
42
+ size?: number
43
+ writeFn?: (data: string | Buffer) => boolean
44
+ } = {},
45
+ ) {
46
+ const timeout = options.timeout ?? 2000
47
+ const harness = createPaletteHarness({ writeFn: options.writeFn })
48
+ const detectPromise = harness.palette.detect({
49
+ timeout,
50
+ size: options.size ?? 256,
51
+ })
52
+
53
+ harness.stdin.emit("data", Buffer.from("\x1b]4;0;#000000\x07"))
54
+ await flushAsync()
55
+
56
+ return { ...harness, detectPromise, timeout }
57
+ }
58
+
59
+ async function advanceClock(clock: ManualClock, ms: number): Promise<void> {
60
+ await flushAsync()
61
+ // Flush queued 0ms mock terminal responses before advancing the real timeout window.
62
+ clock.advance(0)
63
+ await flushAsync()
64
+ clock.advance(ms)
65
+ await flushAsync()
66
+ }
67
+
68
+ test("TerminalPalette detectOSCSupport returns true on response", async () => {
69
+ const { stdin, clock, palette } = createPaletteHarness()
70
+
71
+ const detectPromise = palette.detectOSCSupport(500)
72
+
73
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff0000\x07"))
74
+
75
+ await advanceClock(clock, 500)
76
+
77
+ const result = await detectPromise
78
+
79
+ expect(result).toBe(true)
80
+ })
81
+
82
+ test("TerminalPalette detectOSCSupport returns false on timeout", async () => {
83
+ const { clock, palette } = createPaletteHarness()
84
+
85
+ const detectPromise = palette.detectOSCSupport(100)
86
+
87
+ await advanceClock(clock, 300)
88
+
89
+ const result = await detectPromise
90
+
91
+ expect(result).toBe(false)
92
+ })
93
+
94
+ test("TerminalPalette parses OSC 4 hex format correctly", async () => {
95
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
96
+
97
+ clock.setTimeout(() => {
98
+ for (let i = 0; i < 256; i++) {
99
+ const color = i === 0 ? "#ff00aa" : i === 1 ? "#00ff00" : i === 2 ? "#0000ff" : "#000000"
100
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};${color}\x07`))
101
+ }
102
+ stdin.emit("data", Buffer.from("\x1b]10;#aabbcc\x07"))
103
+ stdin.emit("data", Buffer.from("\x1b]11;#ddeeff\x07"))
104
+ }, 0)
105
+
106
+ await advanceClock(clock, timeout)
107
+
108
+ const result = await detectPromise
109
+
110
+ expect(result.palette[0]).toBe("#ff00aa")
111
+ expect(result.palette[1]).toBe("#00ff00")
112
+ expect(result.palette[2]).toBe("#0000ff")
113
+ expect(result.defaultForeground).toBe("#aabbcc")
114
+ expect(result.defaultBackground).toBe("#ddeeff")
115
+ })
116
+
117
+ test("TerminalPalette parses OSC 4 rgb format with 4 hex digits", async () => {
118
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
119
+
120
+ clock.setTimeout(() => {
121
+ stdin.emit("data", Buffer.from("\x1b]4;0;rgb:ffff/0000/aaaa\x07"))
122
+ for (let i = 1; i < 256; i++) {
123
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
124
+ }
125
+ }, 0)
126
+
127
+ await advanceClock(clock, timeout)
128
+
129
+ const result = await detectPromise
130
+
131
+ expect(result.palette[0]).toMatch(/^#[0-9a-f]{6}$/)
132
+ expect(result.palette[0]).toBe("#ff00aa")
133
+ })
134
+
135
+ test("TerminalPalette parses OSC 4 rgb format with 2 hex digits", async () => {
136
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
137
+
138
+ clock.setTimeout(() => {
139
+ stdin.emit("data", Buffer.from("\x1b]4;0;rgb:ff/00/aa\x07"))
140
+ for (let i = 1; i < 256; i++) {
141
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
142
+ }
143
+ }, 0)
144
+
145
+ await advanceClock(clock, timeout)
146
+
147
+ const result = await detectPromise
148
+
149
+ expect(result.palette[0]).toMatch(/^#[0-9a-f]{6}$/)
150
+ expect(result.palette[0]).toBe("#ff00aa")
151
+ })
152
+
153
+ test("TerminalPalette handles multiple color responses in single buffer", async () => {
154
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
155
+
156
+ clock.setTimeout(() => {
157
+ stdin.emit(
158
+ "data",
159
+ Buffer.from(
160
+ "\x1b]4;0;rgb:0000/0000/0000\x07" +
161
+ "\x1b]4;1;rgb:aa00/0000/0000\x07" +
162
+ "\x1b]4;2;rgb:0000/aa00/0000\x07" +
163
+ "\x1b]4;3;rgb:aa00/aa00/0000\x07",
164
+ ),
165
+ )
166
+
167
+ for (let i = 4; i < 256; i++) {
168
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
169
+ }
170
+ }, 0)
171
+
172
+ await advanceClock(clock, timeout)
173
+
174
+ const result = await detectPromise
175
+
176
+ expect(result.palette[0]).toBe("#000000")
177
+ expect(result.palette[1]).toBe("#a90000")
178
+ expect(result.palette[2]).toBe("#00a900")
179
+ expect(result.palette[3]).toBe("#a9a900")
180
+ })
181
+
182
+ test("TerminalPalette handles BEL terminator", async () => {
183
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
184
+
185
+ clock.setTimeout(() => {
186
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff0000\x07"))
187
+ for (let i = 1; i < 256; i++) {
188
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
189
+ }
190
+ }, 0)
191
+
192
+ await advanceClock(clock, timeout)
193
+
194
+ const result = await detectPromise
195
+
196
+ expect(result.palette[0]).toBe("#ff0000")
197
+ })
198
+
199
+ test("TerminalPalette handles ST terminator", async () => {
200
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
201
+
202
+ clock.setTimeout(() => {
203
+ stdin.emit("data", Buffer.from("\x1b]4;0;#00ff00\x1b\\"))
204
+ for (let i = 1; i < 256; i++) {
205
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
206
+ }
207
+ }, 0)
208
+
209
+ await advanceClock(clock, timeout)
210
+
211
+ const result = await detectPromise
212
+
213
+ expect(result.palette[0]).toBe("#00ff00")
214
+ })
215
+
216
+ test("TerminalPalette scales color components correctly", async () => {
217
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
218
+
219
+ clock.setTimeout(() => {
220
+ stdin.emit("data", Buffer.from("\x1b]4;0;rgb:ffff/0000/0000\x07"))
221
+ for (let i = 1; i < 256; i++) {
222
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
223
+ }
224
+ }, 0)
225
+
226
+ await advanceClock(clock, timeout)
227
+
228
+ const result = await detectPromise
229
+
230
+ expect(result.palette[0]).toBe("#ff0000")
231
+ })
232
+
233
+ test("TerminalPalette returns null for colors that don't respond", async () => {
234
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection({ timeout: 1000 })
235
+
236
+ clock.setTimeout(() => {
237
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff0000\x07"))
238
+ }, 0)
239
+
240
+ await advanceClock(clock, timeout)
241
+
242
+ const result = await detectPromise
243
+
244
+ expect(result.palette[0]).toBe("#ff0000")
245
+ expect(result.palette.some((color: string | null) => color === null)).toBe(true)
246
+ })
247
+
248
+ test("TerminalPalette handles response split across chunks", async () => {
249
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
250
+
251
+ clock.setTimeout(() => {
252
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff"))
253
+ stdin.emit("data", Buffer.from("00aa\x07"))
254
+
255
+ stdin.emit("data", Buffer.from("\x1b]4;1;rgb:0000/"))
256
+ stdin.emit("data", Buffer.from("ffff/"))
257
+ stdin.emit("data", Buffer.from("0000\x07"))
258
+
259
+ for (let i = 2; i < 256; i++) {
260
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
261
+ }
262
+ }, 0)
263
+
264
+ await advanceClock(clock, timeout)
265
+
266
+ const result = await detectPromise
267
+
268
+ expect(result.palette[0]).toBe("#ff00aa")
269
+ expect(result.palette[1]).toBe("#00ff00")
270
+ })
271
+
272
+ test("TerminalPalette handles OSC response mixed with mouse events", async () => {
273
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
274
+
275
+ clock.setTimeout(() => {
276
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff00aa\x07"))
277
+ stdin.emit("data", Buffer.from("\x1b[<0;10;5M"))
278
+ stdin.emit("data", Buffer.from("\x1b]4;1;#00ff00\x07"))
279
+ stdin.emit("data", Buffer.from("\x1b[<0;11;5M"))
280
+ stdin.emit("data", Buffer.from("\x1b]4;2;#0000ff\x07"))
281
+ stdin.emit("data", Buffer.from("\x1b[<0;12;5m"))
282
+
283
+ for (let i = 3; i < 256; i++) {
284
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
285
+ }
286
+ }, 0)
287
+
288
+ await advanceClock(clock, timeout)
289
+
290
+ const result = await detectPromise
291
+
292
+ expect(result.palette[0]).toBe("#ff00aa")
293
+ expect(result.palette[1]).toBe("#00ff00")
294
+ expect(result.palette[2]).toBe("#0000ff")
295
+ })
296
+
297
+ test("TerminalPalette handles OSC response mixed with key events", async () => {
298
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
299
+
300
+ clock.setTimeout(() => {
301
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff00aa\x07"))
302
+ stdin.emit("data", Buffer.from("hello"))
303
+ stdin.emit("data", Buffer.from("\x1b]4;1;#00ff00\x07"))
304
+ stdin.emit("data", Buffer.from("\x1b[A"))
305
+ stdin.emit("data", Buffer.from("\x1b]4;2;#0000ff\x07"))
306
+ stdin.emit("data", Buffer.from("\x1b[B"))
307
+ stdin.emit("data", Buffer.from("\x1b]4;3;#ffff00\x07"))
308
+
309
+ for (let i = 4; i < 256; i++) {
310
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
311
+ }
312
+ }, 0)
313
+
314
+ await advanceClock(clock, timeout)
315
+
316
+ const result = await detectPromise
317
+
318
+ expect(result.palette[0]).toBe("#ff00aa")
319
+ expect(result.palette[1]).toBe("#00ff00")
320
+ expect(result.palette[2]).toBe("#0000ff")
321
+ expect(result.palette[3]).toBe("#ffff00")
322
+ })
323
+
324
+ test("TerminalPalette handles response split mid-escape sequence", async () => {
325
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
326
+
327
+ clock.setTimeout(() => {
328
+ stdin.emit("data", Buffer.from("\x1b"))
329
+ stdin.emit("data", Buffer.from("]4;0;#ff00aa\x07"))
330
+
331
+ stdin.emit("data", Buffer.from("\x1b]"))
332
+ stdin.emit("data", Buffer.from("4;1;#00ff00\x07"))
333
+
334
+ stdin.emit("data", Buffer.from("\x1b]4"))
335
+ stdin.emit("data", Buffer.from(";2;#0000ff\x07"))
336
+
337
+ stdin.emit("data", Buffer.from("\x1b]4;"))
338
+ stdin.emit("data", Buffer.from("3;#ffff00\x07"))
339
+
340
+ for (let i = 4; i < 256; i++) {
341
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
342
+ }
343
+ }, 0)
344
+
345
+ await advanceClock(clock, timeout)
346
+
347
+ const result = await detectPromise
348
+
349
+ expect(result.palette[0]).toBe("#ff00aa")
350
+ expect(result.palette[1]).toBe("#00ff00")
351
+ expect(result.palette[2]).toBe("#0000ff")
352
+ expect(result.palette[3]).toBe("#ffff00")
353
+ })
354
+
355
+ test("TerminalPalette handles mixed ANSI sequences and OSC responses", async () => {
356
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
357
+
358
+ clock.setTimeout(() => {
359
+ stdin.emit("data", Buffer.from("\x1b[2J"))
360
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff00aa\x07"))
361
+ stdin.emit("data", Buffer.from("\x1b[H"))
362
+ stdin.emit("data", Buffer.from("\x1b]4;1;#00ff00\x07"))
363
+ stdin.emit("data", Buffer.from("\x1b[31m"))
364
+ stdin.emit("data", Buffer.from("\x1b]4;2;#0000ff\x07"))
365
+ stdin.emit("data", Buffer.from("\x1b[0m"))
366
+
367
+ for (let i = 3; i < 256; i++) {
368
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
369
+ }
370
+ }, 0)
371
+
372
+ await advanceClock(clock, timeout)
373
+
374
+ const result = await detectPromise
375
+
376
+ expect(result.palette[0]).toBe("#ff00aa")
377
+ expect(result.palette[1]).toBe("#00ff00")
378
+ expect(result.palette[2]).toBe("#0000ff")
379
+ })
380
+
381
+ test("TerminalPalette handles complex chunking with partial responses", async () => {
382
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
383
+
384
+ clock.setTimeout(() => {
385
+ const response0 = "\x1b]4;0;rgb:ffff/0000/aaaa\x07"
386
+ for (let i = 0; i < response0.length; i += 3) {
387
+ stdin.emit("data", Buffer.from(response0.slice(i, i + 3)))
388
+ }
389
+
390
+ stdin.emit("data", Buffer.from("\x1b]4;1"))
391
+ stdin.emit("data", Buffer.from(";#00"))
392
+ stdin.emit("data", Buffer.from("some junk data"))
393
+ stdin.emit("data", Buffer.from("ff00"))
394
+ stdin.emit("data", Buffer.from("\x1b[D"))
395
+ stdin.emit("data", Buffer.from("\x07"))
396
+
397
+ stdin.emit("data", Buffer.from("\x1b]4;1;#00ff00\x07"))
398
+
399
+ for (let i = 2; i < 256; i++) {
400
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
401
+ }
402
+ }, 0)
403
+
404
+ await advanceClock(clock, timeout)
405
+
406
+ const result = await detectPromise
407
+
408
+ expect(result.palette[0]).toBe("#ff00aa")
409
+ expect(result.palette[1]).toBe("#00ff00")
410
+ })
411
+
412
+ test("TerminalPalette ignores malformed responses and waits for valid ones", async () => {
413
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
414
+
415
+ clock.setTimeout(() => {
416
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff00\x07"))
417
+ stdin.emit("data", Buffer.from("\x1b]4;1;rgb:gg00/0000/0000\x07"))
418
+ stdin.emit("data", Buffer.from("\x1b]4;2;#zzzzzz\x07"))
419
+
420
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff00aa\x07"))
421
+ stdin.emit("data", Buffer.from("\x1b]4;1;#00ff00\x07"))
422
+ stdin.emit("data", Buffer.from("\x1b]4;2;#0000ff\x07"))
423
+
424
+ for (let i = 3; i < 256; i++) {
425
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
426
+ }
427
+ }, 0)
428
+
429
+ await advanceClock(clock, timeout)
430
+
431
+ const result = await detectPromise
432
+
433
+ expect(result.palette[0]).toBe("#ff00aa")
434
+ expect(result.palette[1]).toBe("#00ff00")
435
+ expect(result.palette[2]).toBe("#0000ff")
436
+ })
437
+
438
+ test("TerminalPalette handles buffer overflow gracefully", async () => {
439
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
440
+
441
+ clock.setTimeout(() => {
442
+ const junkData = "x".repeat(10000)
443
+ stdin.emit("data", Buffer.from(junkData))
444
+
445
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff00aa\x07"))
446
+ stdin.emit("data", Buffer.from("\x1b]4;1;#00ff00\x07"))
447
+
448
+ for (let i = 2; i < 256; i++) {
449
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
450
+ }
451
+ }, 0)
452
+
453
+ await advanceClock(clock, timeout)
454
+
455
+ const result = await detectPromise
456
+
457
+ expect(result.palette[0]).toBe("#ff00aa")
458
+ expect(result.palette[1]).toBe("#00ff00")
459
+ })
460
+
461
+ test("TerminalPalette handles all 256 colors in a single blob", async () => {
462
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
463
+
464
+ clock.setTimeout(() => {
465
+ let blob = ""
466
+ for (let i = 0; i < 256; i++) {
467
+ const color = i === 0 ? "#ff0011" : i === 1 ? "#00ff22" : i === 255 ? "#aabbcc" : "#000000"
468
+ blob += `\x1b]4;${i};${color}\x07`
469
+ }
470
+
471
+ stdin.emit("data", Buffer.from(blob))
472
+ }, 0)
473
+
474
+ await advanceClock(clock, timeout)
475
+
476
+ const result = await detectPromise
477
+
478
+ expect(result.palette[0]).toBe("#ff0011")
479
+ expect(result.palette[1]).toBe("#00ff22")
480
+ expect(result.palette[255]).toBe("#aabbcc")
481
+ expect(result.palette.length).toBe(256)
482
+ })
483
+
484
+ test("TerminalPalette handles blob split across multiple chunks", async () => {
485
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
486
+
487
+ clock.setTimeout(() => {
488
+ let blob = ""
489
+ for (let i = 0; i < 256; i++) {
490
+ const color = i === 5 ? "#112233" : i === 100 ? "#445566" : i === 200 ? "#778899" : "#000000"
491
+ blob += `\x1b]4;${i};${color}\x07`
492
+ }
493
+
494
+ const chunkSize = 500
495
+ for (let i = 0; i < blob.length; i += chunkSize) {
496
+ stdin.emit("data", Buffer.from(blob.slice(i, i + chunkSize)))
497
+ }
498
+ }, 0)
499
+
500
+ await advanceClock(clock, timeout)
501
+
502
+ const result = await detectPromise
503
+
504
+ expect(result.palette[5]).toBe("#112233")
505
+ expect(result.palette[100]).toBe("#445566")
506
+ expect(result.palette[200]).toBe("#778899")
507
+ expect(result.palette.length).toBe(256)
508
+ })
509
+
510
+ test("TerminalPalette handles blob with mixed junk data", async () => {
511
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
512
+
513
+ clock.setTimeout(() => {
514
+ let blob = ""
515
+ for (let i = 0; i < 256; i++) {
516
+ const color = i === 10 ? "#abcdef" : i === 50 ? "#fedcba" : "#000000"
517
+ blob += `\x1b]4;${i};${color}\x07`
518
+
519
+ if (i % 20 === 0) {
520
+ blob += "JUNK_DATA_HERE"
521
+ }
522
+ if (i % 30 === 0) {
523
+ blob += "\x1b[2J\x1b[H"
524
+ }
525
+ if (i % 40 === 0) {
526
+ blob += "\x1b[<0;10;5M"
527
+ }
528
+ }
529
+
530
+ stdin.emit("data", Buffer.from(blob))
531
+ }, 0)
532
+
533
+ await advanceClock(clock, timeout)
534
+
535
+ const result = await detectPromise
536
+
537
+ expect(result.palette[10]).toBe("#abcdef")
538
+ expect(result.palette[50]).toBe("#fedcba")
539
+ expect(result.palette.length).toBe(256)
540
+ })
541
+
542
+ test("TerminalPalette handles realistic terminal response pattern", async () => {
543
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
544
+
545
+ clock.setTimeout(() => {
546
+ let chunk1 = ""
547
+ for (let i = 0; i <= 5; i++) {
548
+ chunk1 += `\x1b]4;${i};#ff0000\x07`
549
+ }
550
+ stdin.emit("data", Buffer.from(chunk1))
551
+
552
+ let chunk2 = ""
553
+ for (let i = 6; i <= 50; i++) {
554
+ chunk2 += `\x1b]4;${i};#00ff00\x07`
555
+ }
556
+ stdin.emit("data", Buffer.from(chunk2.slice(0, 200)))
557
+ stdin.emit("data", Buffer.from(chunk2.slice(200)))
558
+
559
+ stdin.emit("data", Buffer.from("\x1b[<35;20;10M"))
560
+ let chunk3 = ""
561
+ for (let i = 51; i <= 150; i++) {
562
+ chunk3 += `\x1b]4;${i};#0000ff\x07`
563
+ }
564
+ stdin.emit("data", Buffer.from(chunk3))
565
+
566
+ let chunk4 = ""
567
+ for (let i = 151; i <= 255; i++) {
568
+ chunk4 += `\x1b]4;${i};#ffffff\x07`
569
+ }
570
+ stdin.emit("data", Buffer.from(chunk4))
571
+ }, 0)
572
+
573
+ await advanceClock(clock, timeout)
574
+
575
+ const result = await detectPromise
576
+
577
+ expect(result.palette[0]).toBe("#ff0000")
578
+ expect(result.palette[5]).toBe("#ff0000")
579
+ expect(result.palette[6]).toBe("#00ff00")
580
+ expect(result.palette[50]).toBe("#00ff00")
581
+ expect(result.palette[51]).toBe("#0000ff")
582
+ expect(result.palette[150]).toBe("#0000ff")
583
+ expect(result.palette[151]).toBe("#ffffff")
584
+ expect(result.palette[255]).toBe("#ffffff")
585
+ expect(result.palette.length).toBe(256)
586
+ })
587
+
588
+ test("TerminalPalette uses custom write function when provided", async () => {
589
+ const writtenData: string[] = []
590
+
591
+ const customWrite = (data: string | Buffer) => {
592
+ writtenData.push(data.toString())
593
+ return true
594
+ }
595
+
596
+ const { stdin, clock, palette } = createPaletteHarness({ writeFn: customWrite })
597
+
598
+ const detectPromise = palette.detectOSCSupport(500)
599
+
600
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff0000\x07"))
601
+
602
+ await advanceClock(clock, 500)
603
+
604
+ const result = await detectPromise
605
+
606
+ expect(result).toBe(true)
607
+ expect(writtenData.length).toBe(1)
608
+ expect(writtenData[0]).toBe("\x1b]4;0;?\x07")
609
+ })
610
+
611
+ test("TerminalPalette uses custom write function for palette detection", async () => {
612
+ const writtenData: string[] = []
613
+
614
+ const customWrite = (data: string | Buffer) => {
615
+ writtenData.push(data.toString())
616
+ return true
617
+ }
618
+
619
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection({ writeFn: customWrite })
620
+
621
+ clock.setTimeout(() => {
622
+ for (let i = 0; i < 256; i++) {
623
+ const color = "#aabbcc"
624
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};${color}\x07`))
625
+ }
626
+ }, 0)
627
+
628
+ await advanceClock(clock, timeout)
629
+
630
+ await detectPromise
631
+
632
+ expect(writtenData.length).toBe(3)
633
+ expect(writtenData[0]).toBe("\x1b]4;0;?\x07")
634
+
635
+ const paletteQuery = writtenData[1]
636
+ for (let i = 0; i < 256; i++) {
637
+ expect(paletteQuery).toContain(`\x1b]4;${i};?\x07`)
638
+ }
639
+
640
+ const specialQuery = writtenData[2]
641
+ expect(specialQuery).toContain("\x1b]10;?\x07")
642
+ expect(specialQuery).toContain("\x1b]11;?\x07")
643
+ })
644
+
645
+ test("TerminalPalette falls back to stdout.write when no custom write function provided", async () => {
646
+ const clock = new ManualClock()
647
+ const stdin = new MockStream() as any
648
+ const writtenData: string[] = []
649
+
650
+ const stdout = new MockStream() as any
651
+ stdout.write = (data: string) => {
652
+ writtenData.push(data)
653
+ return true
654
+ }
655
+
656
+ const palette = new TerminalPalette(stdin, stdout, undefined, false, undefined, clock)
657
+
658
+ const detectPromise = palette.detectOSCSupport(500)
659
+
660
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff0000\x07"))
661
+
662
+ await advanceClock(clock, 500)
663
+
664
+ const result = await detectPromise
665
+
666
+ expect(result).toBe(true)
667
+ expect(writtenData.length).toBe(1)
668
+ expect(writtenData[0]).toBe("\x1b]4;0;?\x07")
669
+ })
670
+
671
+ test("TerminalPalette custom write function can intercept and modify output", async () => {
672
+ const interceptedWrites: string[] = []
673
+ let actualWrites = 0
674
+
675
+ const customWrite = (data: string | Buffer) => {
676
+ interceptedWrites.push(data.toString())
677
+ actualWrites++
678
+ return true
679
+ }
680
+
681
+ const { stdin, clock, palette } = createPaletteHarness({ writeFn: customWrite })
682
+
683
+ const detectPromise = palette.detectOSCSupport(500)
684
+
685
+ stdin.emit("data", Buffer.from("\x1b]4;0;#ff0000\x07"))
686
+
687
+ await advanceClock(clock, 500)
688
+
689
+ await detectPromise
690
+
691
+ expect(actualWrites).toBe(1)
692
+ expect(interceptedWrites.length).toBe(1)
693
+ expect(interceptedWrites[0]).toBe("\x1b]4;0;?\x07")
694
+ })
695
+
696
+ test("TerminalPalette detects all special OSC colors (10-19)", async () => {
697
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
698
+
699
+ clock.setTimeout(() => {
700
+ for (let i = 0; i < 256; i++) {
701
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
702
+ }
703
+ stdin.emit("data", Buffer.from("\x1b]10;#ff0001\x07"))
704
+ stdin.emit("data", Buffer.from("\x1b]11;#ff0002\x07"))
705
+ stdin.emit("data", Buffer.from("\x1b]12;#ff0003\x07"))
706
+ stdin.emit("data", Buffer.from("\x1b]13;#ff0004\x07"))
707
+ stdin.emit("data", Buffer.from("\x1b]14;#ff0005\x07"))
708
+ stdin.emit("data", Buffer.from("\x1b]15;#ff0006\x07"))
709
+ stdin.emit("data", Buffer.from("\x1b]16;#ff0007\x07"))
710
+ stdin.emit("data", Buffer.from("\x1b]17;#ff0008\x07"))
711
+ stdin.emit("data", Buffer.from("\x1b]19;#ff0009\x07"))
712
+ }, 0)
713
+
714
+ await advanceClock(clock, timeout)
715
+
716
+ const result = await detectPromise
717
+
718
+ expect(result.defaultForeground).toBe("#ff0001")
719
+ expect(result.defaultBackground).toBe("#ff0002")
720
+ expect(result.cursorColor).toBe("#ff0003")
721
+ expect(result.mouseForeground).toBe("#ff0004")
722
+ expect(result.mouseBackground).toBe("#ff0005")
723
+ expect(result.tekForeground).toBe("#ff0006")
724
+ expect(result.tekBackground).toBe("#ff0007")
725
+ expect(result.highlightBackground).toBe("#ff0008")
726
+ expect(result.highlightForeground).toBe("#ff0009")
727
+ })
728
+
729
+ test("TerminalPalette handles special colors in rgb format", async () => {
730
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
731
+
732
+ clock.setTimeout(() => {
733
+ for (let i = 0; i < 256; i++) {
734
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
735
+ }
736
+ stdin.emit("data", Buffer.from("\x1b]10;rgb:ffff/0000/0000\x07"))
737
+ stdin.emit("data", Buffer.from("\x1b]11;rgb:0000/ffff/0000\x07"))
738
+ }, 0)
739
+
740
+ await advanceClock(clock, timeout)
741
+
742
+ const result = await detectPromise
743
+
744
+ expect(result.defaultForeground).toBe("#ff0000")
745
+ expect(result.defaultBackground).toBe("#00ff00")
746
+ })
747
+
748
+ test("TerminalPalette handles missing special colors gracefully", async () => {
749
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
750
+
751
+ clock.setTimeout(() => {
752
+ for (let i = 0; i < 256; i++) {
753
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
754
+ }
755
+ stdin.emit("data", Buffer.from("\x1b]10;#ff0001\x07"))
756
+ stdin.emit("data", Buffer.from("\x1b]11;#ff0002\x07"))
757
+ }, 0)
758
+
759
+ await advanceClock(clock, timeout)
760
+
761
+ const result = await detectPromise
762
+
763
+ expect(result.defaultForeground).toBe("#ff0001")
764
+ expect(result.defaultBackground).toBe("#ff0002")
765
+ expect(result.cursorColor).toBe(null)
766
+ expect(result.mouseForeground).toBe(null)
767
+ expect(result.mouseBackground).toBe(null)
768
+ })
769
+
770
+ test("TerminalPalette special colors with ST terminator", async () => {
771
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
772
+
773
+ clock.setTimeout(() => {
774
+ for (let i = 0; i < 256; i++) {
775
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
776
+ }
777
+ stdin.emit("data", Buffer.from("\x1b]10;#aabbcc\x1b\\"))
778
+ stdin.emit("data", Buffer.from("\x1b]11;#ddeeff\x1b\\"))
779
+ }, 0)
780
+
781
+ await advanceClock(clock, timeout)
782
+
783
+ const result = await detectPromise
784
+
785
+ expect(result.defaultForeground).toBe("#aabbcc")
786
+ expect(result.defaultBackground).toBe("#ddeeff")
787
+ })
788
+
789
+ test("TerminalPalette handles mixed palette and special color responses", async () => {
790
+ const { stdin, clock, detectPromise, timeout } = await startPaletteDetection()
791
+
792
+ clock.setTimeout(() => {
793
+ stdin.emit("data", Buffer.from("\x1b]4;0;#010203\x07"))
794
+ stdin.emit("data", Buffer.from("\x1b]10;#aabbcc\x07"))
795
+ stdin.emit("data", Buffer.from("\x1b]4;1;#040506\x07"))
796
+ stdin.emit("data", Buffer.from("\x1b]11;#ddeeff\x07"))
797
+ for (let i = 2; i < 256; i++) {
798
+ stdin.emit("data", Buffer.from(`\x1b]4;${i};#000000\x07`))
799
+ }
800
+ }, 0)
801
+
802
+ await advanceClock(clock, timeout)
803
+
804
+ const result = await detectPromise
805
+
806
+ expect(result.palette[0]).toBe("#010203")
807
+ expect(result.palette[1]).toBe("#040506")
808
+ expect(result.defaultForeground).toBe("#aabbcc")
809
+ expect(result.defaultBackground).toBe("#ddeeff")
810
+ })
811
+
812
+ test("TerminalPalette returns null special colors on non-TTY", async () => {
813
+ const { stdin, stdout, clock, palette } = createPaletteHarness()
814
+ stdin.isTTY = false
815
+ stdout.isTTY = false
816
+
817
+ const detectPromise = palette.detect({ timeout: 100 })
818
+
819
+ await advanceClock(clock, 100)
820
+
821
+ const result = await detectPromise
822
+
823
+ expect(result.defaultForeground).toBe(null)
824
+ expect(result.defaultBackground).toBe(null)
825
+ expect(result.cursorColor).toBe(null)
826
+ expect(result.palette.every((c: string | null) => c === null)).toBe(true)
827
+ })
828
+
829
+ test("TerminalPalette returns null special colors on OSC not supported", async () => {
830
+ const { clock, palette } = createPaletteHarness()
831
+
832
+ const detectPromise = palette.detect({ timeout: 100 })
833
+
834
+ await advanceClock(clock, 300)
835
+
836
+ const result = await detectPromise
837
+
838
+ expect(result.defaultForeground).toBe(null)
839
+ expect(result.defaultBackground).toBe(null)
840
+ expect(result.cursorColor).toBe(null)
841
+ expect(result.palette.every((c: string | null) => c === null)).toBe(true)
842
+ })
843
+
844
+ test("TerminalPalette can read OSC from router subscription source", async () => {
845
+ const stdin = new MockStream() as any
846
+
847
+ const handlers = new Set<(sequence: string) => void>()
848
+ let subscribeCount = 0
849
+ let unsubscribeCount = 0
850
+
851
+ const oscSource = {
852
+ subscribeOsc(handler: (sequence: string) => void) {
853
+ subscribeCount++
854
+ handlers.add(handler)
855
+ return () => {
856
+ unsubscribeCount++
857
+ handlers.delete(handler)
858
+ }
859
+ },
860
+ }
861
+
862
+ const clock = new ManualClock()
863
+ const stdout = new MockStream() as any
864
+ const palette = new TerminalPalette(stdin, stdout, undefined, false, oscSource, clock)
865
+
866
+ const detectPromise = palette.detectOSCSupport(500)
867
+ for (const handler of handlers) {
868
+ handler("\x1b]4;0;#ff0000\x07")
869
+ }
870
+
871
+ await advanceClock(clock, 500)
872
+
873
+ const supported = await detectPromise
874
+ expect(supported).toBe(true)
875
+ expect(subscribeCount).toBe(1)
876
+ expect(unsubscribeCount).toBe(1)
877
+ expect(stdin.listenerCount("data")).toBe(0)
878
+ })