@fairyhunter13/opentui-core 0.1.89 → 0.1.91

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 (571) hide show
  1. package/README.md +2 -2
  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/thai-debug-test.ts +68 -0
  7. package/docs/development.md +141 -0
  8. package/docs/env-vars.md +140 -0
  9. package/docs/getting-started.md +353 -0
  10. package/docs/renderables-vs-constructs.md +159 -0
  11. package/docs/tree-sitter.md +311 -0
  12. package/package.json +61 -52
  13. package/scripts/build.ts +400 -0
  14. package/scripts/publish.ts +60 -0
  15. package/src/3d/SpriteResourceManager.ts +286 -0
  16. package/src/3d/SpriteUtils.ts +71 -0
  17. package/src/3d/TextureUtils.ts +196 -0
  18. package/src/3d/ThreeRenderable.ts +197 -0
  19. package/src/3d/WGPURenderer.ts +294 -0
  20. package/src/3d/animation/ExplodingSpriteEffect.ts +513 -0
  21. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +429 -0
  22. package/src/3d/animation/SpriteAnimator.ts +633 -0
  23. package/src/3d/animation/SpriteParticleGenerator.ts +435 -0
  24. package/src/3d/canvas.ts +464 -0
  25. package/src/3d/index.ts +12 -0
  26. package/src/3d/physics/PlanckPhysicsAdapter.ts +72 -0
  27. package/src/3d/physics/RapierPhysicsAdapter.ts +66 -0
  28. package/src/3d/physics/physics-interface.ts +31 -0
  29. package/src/3d/shaders/supersampling.wgsl +201 -0
  30. package/src/3d.ts +3 -0
  31. package/src/NativeSpanFeed.ts +300 -0
  32. package/src/Renderable.ts +1698 -0
  33. package/src/__snapshots__/buffer.test.ts.snap +28 -0
  34. package/src/animation/Timeline.test.ts +2709 -0
  35. package/src/animation/Timeline.ts +598 -0
  36. package/src/ansi.ts +18 -0
  37. package/src/benchmark/latest-all-bench-run.json +707 -0
  38. package/src/benchmark/latest-async-bench-run.json +336 -0
  39. package/src/benchmark/latest-default-bench-run.json +657 -0
  40. package/src/benchmark/latest-large-bench-run.json +707 -0
  41. package/src/benchmark/latest-quick-bench-run.json +207 -0
  42. package/src/benchmark/markdown-benchmark.ts +1804 -0
  43. package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
  44. package/src/benchmark/native-span-feed-benchmark.md +56 -0
  45. package/src/benchmark/native-span-feed-benchmark.ts +596 -0
  46. package/src/benchmark/native-span-feed-compare.ts +280 -0
  47. package/src/benchmark/renderer-benchmark.ts +754 -0
  48. package/src/benchmark/text-table-benchmark.ts +947 -0
  49. package/src/buffer.test.ts +291 -0
  50. package/src/buffer.ts +519 -0
  51. package/src/console.test.ts +612 -0
  52. package/src/console.ts +1255 -0
  53. package/src/edit-buffer.test.ts +1769 -0
  54. package/src/edit-buffer.ts +411 -0
  55. package/src/editor-view.test.ts +1032 -0
  56. package/src/editor-view.ts +284 -0
  57. package/src/examples/ascii-font-selection-demo.ts +245 -0
  58. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  59. package/src/examples/assets/concrete.png +0 -0
  60. package/src/examples/assets/crate.png +0 -0
  61. package/src/examples/assets/crate_emissive.png +0 -0
  62. package/src/examples/assets/forrest_background.png +0 -0
  63. package/src/examples/assets/hast-example.json +1018 -0
  64. package/src/examples/assets/heart.png +0 -0
  65. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  66. package/src/examples/assets/main_char_idle.png +0 -0
  67. package/src/examples/assets/main_char_jump_end.png +0 -0
  68. package/src/examples/assets/main_char_jump_landing.png +0 -0
  69. package/src/examples/assets/main_char_jump_start.png +0 -0
  70. package/src/examples/assets/main_char_run_loop.png +0 -0
  71. package/src/examples/assets/roughness_map.jpg +0 -0
  72. package/src/examples/build.ts +115 -0
  73. package/src/examples/code-demo.ts +584 -0
  74. package/src/examples/console-demo.ts +358 -0
  75. package/src/examples/core-plugin-slots-demo.ts +759 -0
  76. package/src/examples/diff-demo.ts +699 -0
  77. package/src/examples/draggable-three-demo.ts +259 -0
  78. package/src/examples/editor-demo.ts +322 -0
  79. package/src/examples/extmarks-demo.ts +204 -0
  80. package/src/examples/focus-restore-demo.ts +310 -0
  81. package/src/examples/fonts.ts +245 -0
  82. package/src/examples/fractal-shader-demo.ts +268 -0
  83. package/src/examples/framebuffer-demo.ts +674 -0
  84. package/src/examples/full-unicode-demo.ts +181 -0
  85. package/src/examples/golden-star-demo.ts +933 -0
  86. package/src/examples/grayscale-buffer-demo.ts +249 -0
  87. package/src/examples/hast-syntax-highlighting-demo.ts +129 -0
  88. package/src/examples/index.ts +925 -0
  89. package/src/examples/input-demo.ts +377 -0
  90. package/src/examples/input-select-layout-demo.ts +425 -0
  91. package/src/examples/install.sh +143 -0
  92. package/src/examples/keypress-debug-demo.ts +452 -0
  93. package/src/examples/lib/HexList.ts +122 -0
  94. package/src/examples/lib/PaletteGrid.ts +125 -0
  95. package/src/examples/lib/standalone-keys.ts +25 -0
  96. package/src/examples/lib/tab-controller.ts +243 -0
  97. package/src/examples/lights-phong-demo.ts +290 -0
  98. package/src/examples/link-demo.ts +220 -0
  99. package/src/examples/live-state-demo.ts +480 -0
  100. package/src/examples/markdown-demo.ts +620 -0
  101. package/src/examples/mouse-interaction-demo.ts +428 -0
  102. package/src/examples/nested-zindex-demo.ts +357 -0
  103. package/src/examples/opacity-example.ts +235 -0
  104. package/src/examples/opentui-demo.ts +1057 -0
  105. package/src/examples/physx-planck-2d-demo.ts +507 -0
  106. package/src/examples/physx-rapier-2d-demo.ts +526 -0
  107. package/src/examples/relative-positioning-demo.ts +323 -0
  108. package/src/examples/scroll-example.ts +214 -0
  109. package/src/examples/scrollbox-mouse-test.ts +112 -0
  110. package/src/examples/scrollbox-overlay-hit-test.ts +206 -0
  111. package/src/examples/select-demo.ts +237 -0
  112. package/src/examples/shader-cube-demo.ts +772 -0
  113. package/src/examples/simple-layout-example.ts +591 -0
  114. package/src/examples/slider-demo.ts +617 -0
  115. package/src/examples/split-mode-demo.ts +445 -0
  116. package/src/examples/sprite-animation-demo.ts +443 -0
  117. package/src/examples/sprite-particle-generator-demo.ts +486 -0
  118. package/src/examples/static-sprite-demo.ts +193 -0
  119. package/src/examples/sticky-scroll-example.ts +308 -0
  120. package/src/examples/styled-text-demo.ts +282 -0
  121. package/src/examples/tab-select-demo.ts +219 -0
  122. package/src/examples/terminal-title.ts +29 -0
  123. package/src/examples/terminal.ts +305 -0
  124. package/src/examples/text-node-demo.ts +416 -0
  125. package/src/examples/text-selection-demo.ts +377 -0
  126. package/src/examples/text-table-demo.ts +503 -0
  127. package/src/examples/text-truncation-demo.ts +481 -0
  128. package/src/examples/text-wrap.ts +757 -0
  129. package/src/examples/texture-loading-demo.ts +259 -0
  130. package/src/examples/timeline-example.ts +670 -0
  131. package/src/examples/transparency-demo.ts +241 -0
  132. package/src/examples/vnode-composition-demo.ts +404 -0
  133. package/src/index.ts +22 -0
  134. package/src/lib/KeyHandler.integration.test.ts +292 -0
  135. package/src/lib/KeyHandler.stopPropagation.test.ts +289 -0
  136. package/src/lib/KeyHandler.test.ts +662 -0
  137. package/src/lib/KeyHandler.ts +222 -0
  138. package/src/lib/RGBA.test.ts +984 -0
  139. package/src/lib/RGBA.ts +204 -0
  140. package/src/lib/ascii.font.ts +330 -0
  141. package/src/lib/border.test.ts +83 -0
  142. package/src/lib/border.ts +168 -0
  143. package/src/lib/bunfs.test.ts +27 -0
  144. package/src/lib/bunfs.ts +18 -0
  145. package/src/lib/clipboard.test.ts +41 -0
  146. package/src/lib/clipboard.ts +47 -0
  147. package/src/lib/clock.ts +31 -0
  148. package/src/lib/data-paths.test.ts +133 -0
  149. package/src/lib/data-paths.ts +109 -0
  150. package/src/lib/debounce.ts +106 -0
  151. package/src/lib/detect-links.test.ts +98 -0
  152. package/src/lib/detect-links.ts +56 -0
  153. package/src/lib/env.test.ts +228 -0
  154. package/src/lib/env.ts +209 -0
  155. package/src/lib/extmarks-history.ts +51 -0
  156. package/src/lib/extmarks-multiwidth.test.ts +322 -0
  157. package/src/lib/extmarks.test.ts +3457 -0
  158. package/src/lib/extmarks.ts +843 -0
  159. package/src/lib/fonts/block.json +405 -0
  160. package/src/lib/fonts/grid.json +265 -0
  161. package/src/lib/fonts/huge.json +741 -0
  162. package/src/lib/fonts/pallet.json +314 -0
  163. package/src/lib/fonts/shade.json +591 -0
  164. package/src/lib/fonts/slick.json +321 -0
  165. package/src/lib/fonts/tiny.json +69 -0
  166. package/src/lib/hast-styled-text.ts +59 -0
  167. package/src/lib/index.ts +21 -0
  168. package/src/lib/keymapping.test.ts +280 -0
  169. package/src/lib/keymapping.ts +87 -0
  170. package/src/lib/objects-in-viewport.test.ts +787 -0
  171. package/src/lib/objects-in-viewport.ts +153 -0
  172. package/src/lib/output.capture.ts +58 -0
  173. package/src/lib/parse.keypress-kitty.protocol.test.ts +340 -0
  174. package/src/lib/parse.keypress-kitty.test.ts +663 -0
  175. package/src/lib/parse.keypress-kitty.ts +439 -0
  176. package/src/lib/parse.keypress.test.ts +1849 -0
  177. package/src/lib/parse.keypress.ts +397 -0
  178. package/src/lib/parse.mouse.test.ts +552 -0
  179. package/src/lib/parse.mouse.ts +232 -0
  180. package/src/lib/paste.ts +16 -0
  181. package/src/lib/queue.ts +65 -0
  182. package/src/lib/renderable.validations.test.ts +87 -0
  183. package/src/lib/renderable.validations.ts +83 -0
  184. package/src/lib/scroll-acceleration.ts +98 -0
  185. package/src/lib/selection.ts +240 -0
  186. package/src/lib/singleton.ts +28 -0
  187. package/src/lib/stdin-parser.test.ts +1676 -0
  188. package/src/lib/stdin-parser.ts +1248 -0
  189. package/src/lib/styled-text.ts +178 -0
  190. package/src/lib/terminal-capability-detection.test.ts +202 -0
  191. package/src/lib/terminal-capability-detection.ts +79 -0
  192. package/src/lib/terminal-palette.test.ts +878 -0
  193. package/src/lib/terminal-palette.ts +383 -0
  194. package/src/lib/tree-sitter/assets/README.md +118 -0
  195. package/src/lib/tree-sitter/assets/update.ts +331 -0
  196. package/src/lib/tree-sitter/assets.d.ts +9 -0
  197. package/src/lib/tree-sitter/cache.test.ts +270 -0
  198. package/src/lib/tree-sitter/client.test.ts +1061 -0
  199. package/src/lib/tree-sitter/client.ts +615 -0
  200. package/src/lib/tree-sitter/default-parsers.ts +80 -0
  201. package/src/lib/tree-sitter/download-utils.ts +148 -0
  202. package/src/lib/tree-sitter/index.ts +28 -0
  203. package/src/lib/tree-sitter/parser.worker.ts +1001 -0
  204. package/src/lib/tree-sitter/parsers-config.ts +75 -0
  205. package/src/lib/tree-sitter/resolve-ft.ts +62 -0
  206. package/src/lib/tree-sitter/types.ts +81 -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 +377 -0
  214. package/src/plugins/types.ts +46 -0
  215. package/src/post/filters.ts +888 -0
  216. package/src/renderables/ASCIIFont.ts +219 -0
  217. package/src/renderables/Box.test.ts +160 -0
  218. package/src/renderables/Box.ts +295 -0
  219. package/src/renderables/Code.test.ts +2062 -0
  220. package/src/renderables/Code.ts +357 -0
  221. package/src/renderables/Diff.regression.test.ts +226 -0
  222. package/src/renderables/Diff.test.ts +3027 -0
  223. package/src/renderables/Diff.ts +1209 -0
  224. package/src/renderables/EditBufferRenderable.ts +764 -0
  225. package/src/renderables/FrameBuffer.ts +47 -0
  226. package/src/renderables/Input.test.ts +1228 -0
  227. package/src/renderables/Input.ts +245 -0
  228. package/src/renderables/LineNumberRenderable.ts +675 -0
  229. package/src/renderables/Markdown.ts +1106 -0
  230. package/src/renderables/ScrollBar.ts +422 -0
  231. package/src/renderables/ScrollBox.ts +883 -0
  232. package/src/renderables/Select.test.ts +1010 -0
  233. package/src/renderables/Select.ts +523 -0
  234. package/src/renderables/Slider.test.ts +456 -0
  235. package/src/renderables/Slider.ts +347 -0
  236. package/src/renderables/TabSelect.test.ts +197 -0
  237. package/src/renderables/TabSelect.ts +455 -0
  238. package/src/renderables/Text.selection-buffer.test.ts +123 -0
  239. package/src/renderables/Text.test.ts +2660 -0
  240. package/src/renderables/Text.ts +147 -0
  241. package/src/renderables/TextBufferRenderable.ts +518 -0
  242. package/src/renderables/TextNode.test.ts +1058 -0
  243. package/src/renderables/TextNode.ts +325 -0
  244. package/src/renderables/TextTable.test.ts +1421 -0
  245. package/src/renderables/TextTable.ts +1344 -0
  246. package/src/renderables/Textarea.ts +732 -0
  247. package/src/renderables/TimeToFirstDraw.ts +89 -0
  248. package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
  249. package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
  250. package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
  251. package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
  252. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
  253. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +816 -0
  254. package/src/renderables/__tests__/LineNumberRenderable.test.ts +1787 -0
  255. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
  256. package/src/renderables/__tests__/Markdown.test.ts +2287 -0
  257. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
  258. package/src/renderables/__tests__/Textarea.buffer.test.ts +682 -0
  259. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
  260. package/src/renderables/__tests__/Textarea.editing.test.ts +2041 -0
  261. package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
  262. package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
  263. package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
  264. package/src/renderables/__tests__/Textarea.keybinding.test.ts +3149 -0
  265. package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
  266. package/src/renderables/__tests__/Textarea.rendering.test.ts +1864 -0
  267. package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
  268. package/src/renderables/__tests__/Textarea.selection.test.ts +1590 -0
  269. package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
  270. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
  271. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
  272. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
  273. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
  274. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
  275. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
  276. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
  277. package/src/renderables/__tests__/markdown-parser.test.ts +217 -0
  278. package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
  279. package/src/renderables/composition/README.md +8 -0
  280. package/src/renderables/composition/VRenderable.ts +32 -0
  281. package/src/renderables/composition/constructs.ts +127 -0
  282. package/src/renderables/composition/vnode.ts +289 -0
  283. package/src/renderables/index.ts +22 -0
  284. package/src/renderables/markdown-parser.ts +66 -0
  285. package/src/renderer.ts +2363 -0
  286. package/src/runtime-plugin-support.ts +39 -0
  287. package/src/runtime-plugin.ts +144 -0
  288. package/src/syntax-style.test.ts +841 -0
  289. package/src/syntax-style.ts +264 -0
  290. package/src/testing/README.md +210 -0
  291. package/src/testing/capture-spans.test.ts +194 -0
  292. package/src/testing/integration.test.ts +276 -0
  293. package/src/testing/manual-clock.ts +106 -0
  294. package/src/testing/mock-keys.test.ts +1356 -0
  295. package/src/testing/mock-keys.ts +449 -0
  296. package/src/testing/mock-mouse.test.ts +218 -0
  297. package/src/testing/mock-mouse.ts +247 -0
  298. package/src/testing/mock-tree-sitter-client.ts +73 -0
  299. package/src/testing/spy.ts +13 -0
  300. package/src/testing/test-recorder.test.ts +415 -0
  301. package/src/testing/test-recorder.ts +145 -0
  302. package/src/testing/test-renderer.ts +116 -0
  303. package/src/testing.ts +7 -0
  304. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
  305. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
  306. package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
  307. package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
  308. package/src/tests/allocator-stats.test.ts +38 -0
  309. package/src/tests/destroy-during-render.test.ts +200 -0
  310. package/src/tests/hover-cursor.test.ts +98 -0
  311. package/src/tests/native-span-feed-async.test.ts +173 -0
  312. package/src/tests/native-span-feed-close.test.ts +120 -0
  313. package/src/tests/native-span-feed-coverage.test.ts +227 -0
  314. package/src/tests/native-span-feed-edge-cases.test.ts +352 -0
  315. package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
  316. package/src/tests/opacity.test.ts +123 -0
  317. package/src/tests/renderable.snapshot.test.ts +524 -0
  318. package/src/tests/renderable.test.ts +1281 -0
  319. package/src/tests/renderer.console-startup.test.ts +65 -0
  320. package/src/tests/renderer.control.test.ts +364 -0
  321. package/src/tests/renderer.core-slot-binding.test.ts +952 -0
  322. package/src/tests/renderer.cursor.test.ts +26 -0
  323. package/src/tests/renderer.destroy-during-render.test.ts +110 -0
  324. package/src/tests/renderer.focus-restore.test.ts +228 -0
  325. package/src/tests/renderer.focus.test.ts +251 -0
  326. package/src/tests/renderer.idle.test.ts +219 -0
  327. package/src/tests/renderer.input.test.ts +2145 -0
  328. package/src/tests/renderer.kitty-flags.test.ts +195 -0
  329. package/src/tests/renderer.mouse.test.ts +1269 -0
  330. package/src/tests/renderer.palette.test.ts +629 -0
  331. package/src/tests/renderer.selection.test.ts +49 -0
  332. package/src/tests/renderer.slot-registry.test.ts +649 -0
  333. package/src/tests/renderer.useMouse.test.ts +50 -0
  334. package/src/tests/runtime-plugin-support.fixture.ts +11 -0
  335. package/src/tests/runtime-plugin-support.test.ts +28 -0
  336. package/src/tests/runtime-plugin.fixture.ts +40 -0
  337. package/src/tests/runtime-plugin.test.ts +190 -0
  338. package/src/tests/scrollbox-culling-bug.test.ts +114 -0
  339. package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
  340. package/src/tests/scrollbox-hitgrid.test.ts +909 -0
  341. package/src/tests/scrollbox.test.ts +1530 -0
  342. package/src/tests/wrap-resize-perf.test.ts +229 -0
  343. package/src/tests/yoga-setters.test.ts +921 -0
  344. package/src/text-buffer-view.test.ts +705 -0
  345. package/src/text-buffer-view.ts +189 -0
  346. package/src/text-buffer.test.ts +347 -0
  347. package/src/text-buffer.ts +250 -0
  348. package/src/types.ts +152 -0
  349. package/src/utils.ts +88 -0
  350. package/src/zig/ansi.zig +268 -0
  351. package/src/zig/bench/README.md +50 -0
  352. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +887 -0
  353. package/src/zig/bench/edit-buffer_bench.zig +476 -0
  354. package/src/zig/bench/native-span-feed_bench.zig +100 -0
  355. package/src/zig/bench/rope-markers_bench.zig +713 -0
  356. package/src/zig/bench/rope_bench.zig +514 -0
  357. package/src/zig/bench/styled-text_bench.zig +470 -0
  358. package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
  359. package/src/zig/bench/text-buffer-view_bench.zig +459 -0
  360. package/src/zig/bench/text-chunk-graphemes_bench.zig +273 -0
  361. package/src/zig/bench/utf8_bench.zig +799 -0
  362. package/src/zig/bench-utils.zig +431 -0
  363. package/src/zig/bench.zig +217 -0
  364. package/src/zig/buffer.zig +2223 -0
  365. package/src/zig/build.zig +289 -0
  366. package/src/zig/build.zig.zon +16 -0
  367. package/src/zig/edit-buffer.zig +825 -0
  368. package/src/zig/editor-view.zig +802 -0
  369. package/src/zig/event-bus.zig +13 -0
  370. package/src/zig/event-emitter.zig +65 -0
  371. package/src/zig/file-logger.zig +92 -0
  372. package/src/zig/grapheme.zig +599 -0
  373. package/src/zig/lib.zig +1834 -0
  374. package/src/zig/link.zig +333 -0
  375. package/src/zig/logger.zig +43 -0
  376. package/src/zig/mem-registry.zig +125 -0
  377. package/src/zig/native-span-feed-bench-lib.zig +7 -0
  378. package/src/zig/native-span-feed.zig +708 -0
  379. package/src/zig/renderer.zig +1386 -0
  380. package/src/zig/rope.zig +1220 -0
  381. package/src/zig/syntax-style.zig +161 -0
  382. package/src/zig/terminal.zig +975 -0
  383. package/src/zig/test.zig +70 -0
  384. package/src/zig/tests/README.md +18 -0
  385. package/src/zig/tests/buffer_test.zig +2526 -0
  386. package/src/zig/tests/edit-buffer-history_test.zig +271 -0
  387. package/src/zig/tests/edit-buffer_test.zig +1689 -0
  388. package/src/zig/tests/editor-view_test.zig +3299 -0
  389. package/src/zig/tests/event-emitter_test.zig +249 -0
  390. package/src/zig/tests/grapheme_test.zig +1304 -0
  391. package/src/zig/tests/link_test.zig +190 -0
  392. package/src/zig/tests/mem-registry_test.zig +473 -0
  393. package/src/zig/tests/memory_leak_regression_test.zig +159 -0
  394. package/src/zig/tests/native-span-feed_test.zig +1264 -0
  395. package/src/zig/tests/renderer_test.zig +1010 -0
  396. package/src/zig/tests/rope-nested_test.zig +712 -0
  397. package/src/zig/tests/rope_fuzz_test.zig +238 -0
  398. package/src/zig/tests/rope_test.zig +2362 -0
  399. package/src/zig/tests/segment-merge.test.zig +148 -0
  400. package/src/zig/tests/syntax-style_test.zig +557 -0
  401. package/src/zig/tests/terminal_test.zig +719 -0
  402. package/src/zig/tests/text-buffer-drawing_test.zig +3237 -0
  403. package/src/zig/tests/text-buffer-highlights_test.zig +666 -0
  404. package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
  405. package/src/zig/tests/text-buffer-segment_test.zig +320 -0
  406. package/src/zig/tests/text-buffer-selection_test.zig +1035 -0
  407. package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
  408. package/src/zig/tests/text-buffer-view_test.zig +3649 -0
  409. package/src/zig/tests/text-buffer_test.zig +2191 -0
  410. package/src/zig/tests/unicode-width-map.zon +3909 -0
  411. package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
  412. package/src/zig/tests/utf8_test.zig +4057 -0
  413. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
  414. package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
  415. package/src/zig/tests/word-wrap-editing_test.zig +498 -0
  416. package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
  417. package/src/zig/text-buffer-iterators.zig +499 -0
  418. package/src/zig/text-buffer-segment.zig +404 -0
  419. package/src/zig/text-buffer-view.zig +1371 -0
  420. package/src/zig/text-buffer.zig +1180 -0
  421. package/src/zig/utf8.zig +1948 -0
  422. package/src/zig/utils.zig +9 -0
  423. package/src/zig-structs.ts +261 -0
  424. package/src/zig.ts +3843 -0
  425. package/tsconfig.build.json +22 -0
  426. package/tsconfig.json +28 -0
  427. package/3d/SpriteResourceManager.d.ts +0 -74
  428. package/3d/SpriteUtils.d.ts +0 -13
  429. package/3d/TextureUtils.d.ts +0 -24
  430. package/3d/ThreeRenderable.d.ts +0 -40
  431. package/3d/WGPURenderer.d.ts +0 -61
  432. package/3d/animation/ExplodingSpriteEffect.d.ts +0 -71
  433. package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +0 -76
  434. package/3d/animation/SpriteAnimator.d.ts +0 -124
  435. package/3d/animation/SpriteParticleGenerator.d.ts +0 -62
  436. package/3d/canvas.d.ts +0 -44
  437. package/3d/index.d.ts +0 -12
  438. package/3d/physics/PlanckPhysicsAdapter.d.ts +0 -19
  439. package/3d/physics/RapierPhysicsAdapter.d.ts +0 -19
  440. package/3d/physics/physics-interface.d.ts +0 -27
  441. package/3d.d.ts +0 -2
  442. package/3d.js +0 -34042
  443. package/3d.js.map +0 -155
  444. package/LICENSE +0 -21
  445. package/NativeSpanFeed.d.ts +0 -41
  446. package/Renderable.d.ts +0 -334
  447. package/animation/Timeline.d.ts +0 -126
  448. package/ansi.d.ts +0 -13
  449. package/buffer.d.ts +0 -107
  450. package/console.d.ts +0 -143
  451. package/edit-buffer.d.ts +0 -98
  452. package/editor-view.d.ts +0 -73
  453. package/index-e4hzc2j2.js +0 -113
  454. package/index-e4hzc2j2.js.map +0 -10
  455. package/index-nkrr8a4c.js +0 -18415
  456. package/index-nkrr8a4c.js.map +0 -64
  457. package/index-nyw5p3ep.js +0 -12619
  458. package/index-nyw5p3ep.js.map +0 -43
  459. package/index.d.ts +0 -21
  460. package/index.js +0 -430
  461. package/index.js.map +0 -9
  462. package/lib/KeyHandler.d.ts +0 -61
  463. package/lib/RGBA.d.ts +0 -25
  464. package/lib/ascii.font.d.ts +0 -508
  465. package/lib/border.d.ts +0 -49
  466. package/lib/bunfs.d.ts +0 -7
  467. package/lib/clipboard.d.ts +0 -17
  468. package/lib/clock.d.ts +0 -15
  469. package/lib/data-paths.d.ts +0 -26
  470. package/lib/debounce.d.ts +0 -42
  471. package/lib/detect-links.d.ts +0 -6
  472. package/lib/env.d.ts +0 -42
  473. package/lib/extmarks-history.d.ts +0 -17
  474. package/lib/extmarks.d.ts +0 -89
  475. package/lib/hast-styled-text.d.ts +0 -17
  476. package/lib/index.d.ts +0 -21
  477. package/lib/keymapping.d.ts +0 -25
  478. package/lib/objects-in-viewport.d.ts +0 -24
  479. package/lib/output.capture.d.ts +0 -24
  480. package/lib/parse.keypress-kitty.d.ts +0 -2
  481. package/lib/parse.keypress.d.ts +0 -26
  482. package/lib/parse.mouse.d.ts +0 -30
  483. package/lib/paste.d.ts +0 -7
  484. package/lib/queue.d.ts +0 -15
  485. package/lib/renderable.validations.d.ts +0 -12
  486. package/lib/scroll-acceleration.d.ts +0 -43
  487. package/lib/selection.d.ts +0 -63
  488. package/lib/singleton.d.ts +0 -7
  489. package/lib/stdin-parser.d.ts +0 -76
  490. package/lib/styled-text.d.ts +0 -63
  491. package/lib/terminal-capability-detection.d.ts +0 -30
  492. package/lib/terminal-palette.d.ts +0 -50
  493. package/lib/tree-sitter/assets/update.d.ts +0 -11
  494. package/lib/tree-sitter/client.d.ts +0 -47
  495. package/lib/tree-sitter/default-parsers.d.ts +0 -2
  496. package/lib/tree-sitter/download-utils.d.ts +0 -21
  497. package/lib/tree-sitter/index.d.ts +0 -8
  498. package/lib/tree-sitter/parser.worker.d.ts +0 -1
  499. package/lib/tree-sitter/parsers-config.d.ts +0 -38
  500. package/lib/tree-sitter/resolve-ft.d.ts +0 -2
  501. package/lib/tree-sitter/types.d.ts +0 -81
  502. package/lib/tree-sitter-styled-text.d.ts +0 -14
  503. package/lib/validate-dir-name.d.ts +0 -1
  504. package/lib/yoga.options.d.ts +0 -32
  505. package/parser.worker.js +0 -869
  506. package/parser.worker.js.map +0 -12
  507. package/plugins/core-slot.d.ts +0 -72
  508. package/plugins/registry.d.ts +0 -38
  509. package/plugins/types.d.ts +0 -34
  510. package/post/filters.d.ts +0 -105
  511. package/renderables/ASCIIFont.d.ts +0 -52
  512. package/renderables/Box.d.ts +0 -72
  513. package/renderables/Code.d.ts +0 -78
  514. package/renderables/Diff.d.ts +0 -142
  515. package/renderables/EditBufferRenderable.d.ts +0 -162
  516. package/renderables/FrameBuffer.d.ts +0 -16
  517. package/renderables/Input.d.ts +0 -67
  518. package/renderables/LineNumberRenderable.d.ts +0 -74
  519. package/renderables/Markdown.d.ts +0 -173
  520. package/renderables/ScrollBar.d.ts +0 -77
  521. package/renderables/ScrollBox.d.ts +0 -124
  522. package/renderables/Select.d.ts +0 -115
  523. package/renderables/Slider.d.ts +0 -44
  524. package/renderables/TabSelect.d.ts +0 -96
  525. package/renderables/Text.d.ts +0 -36
  526. package/renderables/TextBufferRenderable.d.ts +0 -105
  527. package/renderables/TextNode.d.ts +0 -91
  528. package/renderables/TextTable.d.ts +0 -140
  529. package/renderables/Textarea.d.ts +0 -114
  530. package/renderables/TimeToFirstDraw.d.ts +0 -24
  531. package/renderables/__tests__/renderable-test-utils.d.ts +0 -12
  532. package/renderables/composition/VRenderable.d.ts +0 -16
  533. package/renderables/composition/constructs.d.ts +0 -35
  534. package/renderables/composition/vnode.d.ts +0 -46
  535. package/renderables/index.d.ts +0 -22
  536. package/renderables/markdown-parser.d.ts +0 -10
  537. package/renderer.d.ts +0 -388
  538. package/runtime-plugin-support.d.ts +0 -3
  539. package/runtime-plugin-support.js +0 -29
  540. package/runtime-plugin-support.js.map +0 -10
  541. package/runtime-plugin.d.ts +0 -11
  542. package/runtime-plugin.js +0 -16
  543. package/runtime-plugin.js.map +0 -9
  544. package/syntax-style.d.ts +0 -54
  545. package/testing/manual-clock.d.ts +0 -16
  546. package/testing/mock-keys.d.ts +0 -81
  547. package/testing/mock-mouse.d.ts +0 -38
  548. package/testing/mock-tree-sitter-client.d.ts +0 -23
  549. package/testing/spy.d.ts +0 -7
  550. package/testing/test-recorder.d.ts +0 -61
  551. package/testing/test-renderer.d.ts +0 -23
  552. package/testing.d.ts +0 -6
  553. package/testing.js +0 -675
  554. package/testing.js.map +0 -15
  555. package/text-buffer-view.d.ts +0 -42
  556. package/text-buffer.d.ts +0 -67
  557. package/types.d.ts +0 -131
  558. package/utils.d.ts +0 -14
  559. package/zig-structs.d.ts +0 -155
  560. package/zig.d.ts +0 -351
  561. /package/{assets → src/lib/tree-sitter/assets}/javascript/highlights.scm +0 -0
  562. /package/{assets → src/lib/tree-sitter/assets}/javascript/tree-sitter-javascript.wasm +0 -0
  563. /package/{assets → src/lib/tree-sitter/assets}/markdown/highlights.scm +0 -0
  564. /package/{assets → src/lib/tree-sitter/assets}/markdown/injections.scm +0 -0
  565. /package/{assets → src/lib/tree-sitter/assets}/markdown/tree-sitter-markdown.wasm +0 -0
  566. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/highlights.scm +0 -0
  567. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  568. /package/{assets → src/lib/tree-sitter/assets}/typescript/highlights.scm +0 -0
  569. /package/{assets → src/lib/tree-sitter/assets}/typescript/tree-sitter-typescript.wasm +0 -0
  570. /package/{assets → src/lib/tree-sitter/assets}/zig/highlights.scm +0 -0
  571. /package/{assets → src/lib/tree-sitter/assets}/zig/tree-sitter-zig.wasm +0 -0
@@ -0,0 +1,455 @@
1
+ import { Renderable, type RenderableOptions } from "../Renderable.js"
2
+ import { OptimizedBuffer } from "../buffer.js"
3
+ import { RGBA, parseColor, type ColorInput } from "../lib/RGBA.js"
4
+ import type { KeyEvent } from "../lib/KeyHandler.js"
5
+ import type { RenderContext } from "../types.js"
6
+ import {
7
+ type KeyBinding as BaseKeyBinding,
8
+ mergeKeyBindings,
9
+ getKeyBindingKey,
10
+ buildKeyBindingsMap,
11
+ type KeyAliasMap,
12
+ defaultKeyAliases,
13
+ mergeKeyAliases,
14
+ } from "../lib/keymapping.js"
15
+
16
+ export interface TabSelectOption {
17
+ name: string
18
+ description: string
19
+ value?: any
20
+ }
21
+
22
+ export type TabSelectAction = "move-left" | "move-right" | "select-current"
23
+
24
+ export type TabSelectKeyBinding = BaseKeyBinding<TabSelectAction>
25
+
26
+ const defaultTabSelectKeybindings: TabSelectKeyBinding[] = [
27
+ { name: "left", action: "move-left" },
28
+ { name: "[", action: "move-left" },
29
+ { name: "right", action: "move-right" },
30
+ { name: "]", action: "move-right" },
31
+ { name: "return", action: "select-current" },
32
+ { name: "linefeed", action: "select-current" },
33
+ ]
34
+
35
+ export interface TabSelectRenderableOptions extends Omit<RenderableOptions<TabSelectRenderable>, "height"> {
36
+ height?: number
37
+ options?: TabSelectOption[]
38
+ tabWidth?: number
39
+ backgroundColor?: ColorInput
40
+ textColor?: ColorInput
41
+ focusedBackgroundColor?: ColorInput
42
+ focusedTextColor?: ColorInput
43
+ selectedBackgroundColor?: ColorInput
44
+ selectedTextColor?: ColorInput
45
+ selectedDescriptionColor?: ColorInput
46
+ showScrollArrows?: boolean
47
+ showDescription?: boolean
48
+ showUnderline?: boolean
49
+ wrapSelection?: boolean
50
+ keyBindings?: TabSelectKeyBinding[]
51
+ keyAliasMap?: KeyAliasMap
52
+ }
53
+
54
+ export enum TabSelectRenderableEvents {
55
+ SELECTION_CHANGED = "selectionChanged",
56
+ ITEM_SELECTED = "itemSelected",
57
+ }
58
+
59
+ function calculateDynamicHeight(showUnderline: boolean, showDescription: boolean): number {
60
+ let height = 1
61
+
62
+ if (showUnderline) {
63
+ height += 1
64
+ }
65
+
66
+ if (showDescription) {
67
+ height += 1
68
+ }
69
+
70
+ return height
71
+ }
72
+
73
+ export class TabSelectRenderable extends Renderable {
74
+ protected override _focusable: boolean = true
75
+
76
+ private _options: TabSelectOption[] = []
77
+ private selectedIndex: number = 0
78
+ private scrollOffset: number = 0
79
+ private _tabWidth: number
80
+ private maxVisibleTabs: number
81
+
82
+ private _backgroundColor: RGBA
83
+ private _textColor: RGBA
84
+ private _focusedBackgroundColor: RGBA
85
+ private _focusedTextColor: RGBA
86
+ private _selectedBackgroundColor: RGBA
87
+ private _selectedTextColor: RGBA
88
+ private _selectedDescriptionColor: RGBA
89
+ private _showScrollArrows: boolean
90
+ private _showDescription: boolean
91
+ private _showUnderline: boolean
92
+ private _wrapSelection: boolean
93
+ private _keyBindingsMap: Map<string, TabSelectAction>
94
+ private _keyAliasMap: KeyAliasMap
95
+ private _keyBindings: TabSelectKeyBinding[]
96
+
97
+ constructor(ctx: RenderContext, options: TabSelectRenderableOptions) {
98
+ const calculatedHeight = calculateDynamicHeight(options.showUnderline ?? true, options.showDescription ?? true)
99
+
100
+ super(ctx, { ...options, height: calculatedHeight, buffered: true })
101
+
102
+ this._backgroundColor = parseColor(options.backgroundColor || "transparent")
103
+ this._textColor = parseColor(options.textColor || "#FFFFFF")
104
+ this._focusedBackgroundColor = parseColor(options.focusedBackgroundColor || options.backgroundColor || "#1a1a1a")
105
+ this._focusedTextColor = parseColor(options.focusedTextColor || options.textColor || "#FFFFFF")
106
+ this._options = options.options || []
107
+ this._tabWidth = options.tabWidth || 20
108
+ this._showDescription = options.showDescription ?? true
109
+ this._showUnderline = options.showUnderline ?? true
110
+ this._showScrollArrows = options.showScrollArrows ?? true
111
+ this._wrapSelection = options.wrapSelection ?? false
112
+
113
+ this.maxVisibleTabs = Math.max(1, Math.floor(this.width / this._tabWidth))
114
+
115
+ this._selectedBackgroundColor = parseColor(options.selectedBackgroundColor || "#334455")
116
+ this._selectedTextColor = parseColor(options.selectedTextColor || "#FFFF00")
117
+ this._selectedDescriptionColor = parseColor(options.selectedDescriptionColor || "#CCCCCC")
118
+
119
+ this._keyAliasMap = mergeKeyAliases(defaultKeyAliases, options.keyAliasMap || {})
120
+ this._keyBindings = options.keyBindings || []
121
+ const mergedBindings = mergeKeyBindings(defaultTabSelectKeybindings, this._keyBindings)
122
+ this._keyBindingsMap = buildKeyBindingsMap(mergedBindings, this._keyAliasMap)
123
+ }
124
+
125
+ private calculateDynamicHeight(): number {
126
+ return calculateDynamicHeight(this._showUnderline, this._showDescription)
127
+ }
128
+
129
+ protected override renderSelf(buffer: OptimizedBuffer, deltaTime: number): void {
130
+ if (!this.visible || !this.frameBuffer) return
131
+
132
+ if (this.isDirty) {
133
+ this.refreshFrameBuffer()
134
+ }
135
+ }
136
+
137
+ private refreshFrameBuffer(): void {
138
+ if (!this.frameBuffer) return
139
+ // Use focused colors if focused
140
+ const bgColor = this._focused ? this._focusedBackgroundColor : this._backgroundColor
141
+ this.frameBuffer.clear(bgColor)
142
+ if (this._options.length === 0) return
143
+
144
+ const contentX = 0
145
+ const contentY = 0
146
+ const contentWidth = this.width
147
+ const contentHeight = this.height
148
+
149
+ const visibleOptions = this._options.slice(this.scrollOffset, this.scrollOffset + this.maxVisibleTabs)
150
+
151
+ // Render tab names
152
+ for (let i = 0; i < visibleOptions.length; i++) {
153
+ const actualIndex = this.scrollOffset + i
154
+ const option = visibleOptions[i]
155
+ const isSelected = actualIndex === this.selectedIndex
156
+ const tabX = contentX + i * this._tabWidth
157
+
158
+ if (tabX >= contentX + contentWidth) break
159
+
160
+ const actualTabWidth = Math.min(this._tabWidth, contentWidth - i * this._tabWidth)
161
+
162
+ if (isSelected) {
163
+ this.frameBuffer.fillRect(tabX, contentY, actualTabWidth, 1, this._selectedBackgroundColor)
164
+ }
165
+
166
+ const baseTextColor = this._focused ? this._focusedTextColor : this._textColor
167
+ const nameColor = isSelected ? this._selectedTextColor : baseTextColor
168
+ const nameContent = this.truncateText(option.name, actualTabWidth - 2)
169
+ this.frameBuffer.drawText(nameContent, tabX + 1, contentY, nameColor)
170
+
171
+ if (isSelected && this._showUnderline && contentHeight >= 2) {
172
+ const underlineY = contentY + 1
173
+ const underlineBg = isSelected ? this._selectedBackgroundColor : bgColor
174
+ this.frameBuffer.drawText("▬".repeat(actualTabWidth), tabX, underlineY, nameColor, underlineBg)
175
+ }
176
+ }
177
+
178
+ if (this._showDescription && contentHeight >= (this._showUnderline ? 3 : 2)) {
179
+ const selectedOption = this.getSelectedOption()
180
+ if (selectedOption) {
181
+ const descriptionY = contentY + (this._showUnderline ? 2 : 1)
182
+ const descColor = this._selectedDescriptionColor
183
+ const descContent = this.truncateText(selectedOption.description, contentWidth - 2)
184
+ this.frameBuffer.drawText(descContent, contentX + 1, descriptionY, descColor)
185
+ }
186
+ }
187
+
188
+ if (this._showScrollArrows && this._options.length > this.maxVisibleTabs) {
189
+ this.renderScrollArrowsToFrameBuffer(contentX, contentY, contentWidth, contentHeight)
190
+ }
191
+ }
192
+
193
+ private truncateText(text: string, maxWidth: number): string {
194
+ if (text.length <= maxWidth) return text
195
+ return text.substring(0, Math.max(0, maxWidth - 1)) + "…"
196
+ }
197
+
198
+ private renderScrollArrowsToFrameBuffer(
199
+ contentX: number,
200
+ contentY: number,
201
+ contentWidth: number,
202
+ contentHeight: number,
203
+ ): void {
204
+ if (!this.frameBuffer) return
205
+
206
+ const hasMoreLeft = this.scrollOffset > 0
207
+ const hasMoreRight = this.scrollOffset + this.maxVisibleTabs < this._options.length
208
+
209
+ if (hasMoreLeft) {
210
+ this.frameBuffer.drawText("‹", contentX, contentY, parseColor("#AAAAAA"))
211
+ }
212
+
213
+ if (hasMoreRight) {
214
+ this.frameBuffer.drawText("›", contentX + contentWidth - 1, contentY, parseColor("#AAAAAA"))
215
+ }
216
+ }
217
+
218
+ public setOptions(options: TabSelectOption[]): void {
219
+ this._options = options
220
+ this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, options.length - 1))
221
+ this.updateScrollOffset()
222
+ this.requestRender()
223
+ }
224
+
225
+ public getSelectedOption(): TabSelectOption | null {
226
+ return this._options[this.selectedIndex] || null
227
+ }
228
+
229
+ public getSelectedIndex(): number {
230
+ return this.selectedIndex
231
+ }
232
+
233
+ public moveLeft(): void {
234
+ if (this.selectedIndex > 0) {
235
+ this.selectedIndex--
236
+ } else if (this._wrapSelection && this._options.length > 0) {
237
+ this.selectedIndex = this._options.length - 1
238
+ } else {
239
+ return
240
+ }
241
+
242
+ this.updateScrollOffset()
243
+ this.requestRender()
244
+ this.emit(TabSelectRenderableEvents.SELECTION_CHANGED, this.selectedIndex, this.getSelectedOption())
245
+ }
246
+
247
+ public moveRight(): void {
248
+ if (this.selectedIndex < this._options.length - 1) {
249
+ this.selectedIndex++
250
+ } else if (this._wrapSelection && this._options.length > 0) {
251
+ this.selectedIndex = 0
252
+ } else {
253
+ return
254
+ }
255
+
256
+ this.updateScrollOffset()
257
+ this.requestRender()
258
+ this.emit(TabSelectRenderableEvents.SELECTION_CHANGED, this.selectedIndex, this.getSelectedOption())
259
+ }
260
+
261
+ public selectCurrent(): void {
262
+ const selected = this.getSelectedOption()
263
+ if (selected) {
264
+ this.emit(TabSelectRenderableEvents.ITEM_SELECTED, this.selectedIndex, selected)
265
+ }
266
+ }
267
+
268
+ public setSelectedIndex(index: number): void {
269
+ if (index >= 0 && index < this._options.length) {
270
+ this.selectedIndex = index
271
+ this.updateScrollOffset()
272
+ this.requestRender()
273
+ this.emit(TabSelectRenderableEvents.SELECTION_CHANGED, this.selectedIndex, this.getSelectedOption())
274
+ }
275
+ }
276
+
277
+ private updateScrollOffset(): void {
278
+ const halfVisible = Math.floor(this.maxVisibleTabs / 2)
279
+ const newScrollOffset = Math.max(
280
+ 0,
281
+ Math.min(this.selectedIndex - halfVisible, this._options.length - this.maxVisibleTabs),
282
+ )
283
+
284
+ if (newScrollOffset !== this.scrollOffset) {
285
+ this.scrollOffset = newScrollOffset
286
+ this.requestRender()
287
+ }
288
+ }
289
+
290
+ protected override onResize(width: number, height: number): void {
291
+ this.maxVisibleTabs = Math.max(1, Math.floor(width / this._tabWidth))
292
+ this.updateScrollOffset()
293
+ this.requestRender()
294
+ }
295
+
296
+ public setTabWidth(tabWidth: number): void {
297
+ if (this._tabWidth === tabWidth) return
298
+
299
+ this._tabWidth = tabWidth
300
+ this.maxVisibleTabs = Math.max(1, Math.floor(this.width / this._tabWidth))
301
+
302
+ this.updateScrollOffset()
303
+ this.requestRender()
304
+ }
305
+
306
+ public getTabWidth(): number {
307
+ return this._tabWidth
308
+ }
309
+
310
+ public handleKeyPress(key: KeyEvent): boolean {
311
+ const bindingKey = getKeyBindingKey({
312
+ name: key.name,
313
+ ctrl: key.ctrl,
314
+ shift: key.shift,
315
+ meta: key.meta,
316
+ super: key.super,
317
+ action: "move-left" as TabSelectAction,
318
+ })
319
+
320
+ const action = this._keyBindingsMap.get(bindingKey)
321
+
322
+ if (action) {
323
+ switch (action) {
324
+ case "move-left":
325
+ this.moveLeft()
326
+ return true
327
+ case "move-right":
328
+ this.moveRight()
329
+ return true
330
+ case "select-current":
331
+ this.selectCurrent()
332
+ return true
333
+ }
334
+ }
335
+
336
+ return false
337
+ }
338
+
339
+ public get options(): TabSelectOption[] {
340
+ return this._options
341
+ }
342
+
343
+ public set options(options: TabSelectOption[]) {
344
+ this._options = options
345
+ this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, options.length - 1))
346
+ this.updateScrollOffset()
347
+ this.requestRender()
348
+ }
349
+
350
+ public set backgroundColor(color: ColorInput) {
351
+ this._backgroundColor = parseColor(color)
352
+ this.requestRender()
353
+ }
354
+
355
+ public set textColor(color: ColorInput) {
356
+ this._textColor = parseColor(color)
357
+ this.requestRender()
358
+ }
359
+
360
+ public set focusedBackgroundColor(color: ColorInput) {
361
+ this._focusedBackgroundColor = parseColor(color)
362
+ this.requestRender()
363
+ }
364
+
365
+ public set focusedTextColor(color: ColorInput) {
366
+ this._focusedTextColor = parseColor(color)
367
+ this.requestRender()
368
+ }
369
+
370
+ public set selectedBackgroundColor(color: ColorInput) {
371
+ this._selectedBackgroundColor = parseColor(color)
372
+ this.requestRender()
373
+ }
374
+
375
+ public set selectedTextColor(color: ColorInput) {
376
+ this._selectedTextColor = parseColor(color)
377
+ this.requestRender()
378
+ }
379
+
380
+ public set selectedDescriptionColor(color: ColorInput) {
381
+ this._selectedDescriptionColor = parseColor(color)
382
+ this.requestRender()
383
+ }
384
+
385
+ public get showDescription(): boolean {
386
+ return this._showDescription
387
+ }
388
+
389
+ public set showDescription(show: boolean) {
390
+ if (this._showDescription !== show) {
391
+ this._showDescription = show
392
+ const newHeight = this.calculateDynamicHeight()
393
+ this.height = newHeight
394
+ this.requestRender()
395
+ }
396
+ }
397
+
398
+ public get showUnderline(): boolean {
399
+ return this._showUnderline
400
+ }
401
+
402
+ public set showUnderline(show: boolean) {
403
+ if (this._showUnderline !== show) {
404
+ this._showUnderline = show
405
+ const newHeight = this.calculateDynamicHeight()
406
+ this.height = newHeight
407
+ this.requestRender()
408
+ }
409
+ }
410
+
411
+ public get showScrollArrows(): boolean {
412
+ return this._showScrollArrows
413
+ }
414
+
415
+ public set showScrollArrows(show: boolean) {
416
+ if (this._showScrollArrows !== show) {
417
+ this._showScrollArrows = show
418
+ this.requestRender()
419
+ }
420
+ }
421
+
422
+ public get wrapSelection(): boolean {
423
+ return this._wrapSelection
424
+ }
425
+
426
+ public set wrapSelection(wrap: boolean) {
427
+ this._wrapSelection = wrap
428
+ }
429
+
430
+ public get tabWidth(): number {
431
+ return this._tabWidth
432
+ }
433
+
434
+ public set tabWidth(tabWidth: number) {
435
+ if (this._tabWidth === tabWidth) return
436
+
437
+ this._tabWidth = tabWidth
438
+ this.maxVisibleTabs = Math.max(1, Math.floor(this.width / this._tabWidth))
439
+
440
+ this.updateScrollOffset()
441
+ this.requestRender()
442
+ }
443
+
444
+ public set keyBindings(bindings: TabSelectKeyBinding[]) {
445
+ this._keyBindings = bindings
446
+ const mergedBindings = mergeKeyBindings(defaultTabSelectKeybindings, bindings)
447
+ this._keyBindingsMap = buildKeyBindingsMap(mergedBindings, this._keyAliasMap)
448
+ }
449
+
450
+ public set keyAliasMap(aliases: KeyAliasMap) {
451
+ this._keyAliasMap = mergeKeyAliases(defaultKeyAliases, aliases)
452
+ const mergedBindings = mergeKeyBindings(defaultTabSelectKeybindings, this._keyBindings)
453
+ this._keyBindingsMap = buildKeyBindingsMap(mergedBindings, this._keyAliasMap)
454
+ }
455
+ }
@@ -0,0 +1,123 @@
1
+ import { describe, expect, it, beforeEach, afterEach } from "bun:test"
2
+ import { TextRenderable } from "./Text.js"
3
+ import { RGBA } from "../lib/RGBA.js"
4
+ import { createTestRenderer, type MockMouse, type TestRenderer } from "../testing/test-renderer.js"
5
+ import { BoxRenderable } from "./Box.js"
6
+
7
+ let currentRenderer: TestRenderer
8
+ let renderOnce: () => Promise<void>
9
+ let currentMouse: MockMouse
10
+
11
+ describe("TextRenderable Selection - Buffer Validation", () => {
12
+ beforeEach(async () => {
13
+ ;({
14
+ renderer: currentRenderer,
15
+ renderOnce,
16
+ mockMouse: currentMouse,
17
+ } = await createTestRenderer({
18
+ width: 50,
19
+ height: 10,
20
+ }))
21
+ })
22
+
23
+ afterEach(() => {
24
+ currentRenderer.destroy()
25
+ })
26
+
27
+ it("applies selection background colors to selected text renderables", async () => {
28
+ const box1 = new BoxRenderable(currentRenderer, {
29
+ id: "box1",
30
+ left: 2,
31
+ top: 2,
32
+ width: 45,
33
+ height: 7,
34
+ backgroundColor: "#1e2936",
35
+ borderColor: "#58a6ff",
36
+ title: "Document Section 1",
37
+ flexDirection: "column",
38
+ padding: 1,
39
+ border: true,
40
+ })
41
+ currentRenderer.root.add(box1)
42
+
43
+ const text1 = new TextRenderable(currentRenderer, {
44
+ id: "text1",
45
+ content: "This is a paragraph in the first box.",
46
+ fg: "#f0f6fc",
47
+ selectionBg: "#4a5568",
48
+ selectionFg: "#ffffff",
49
+ })
50
+ box1.add(text1)
51
+
52
+ const text2 = new TextRenderable(currentRenderer, {
53
+ id: "text2",
54
+ content: "It contains multiple lines of text",
55
+ fg: "#f0f6fc",
56
+ selectionBg: "#4a5568",
57
+ selectionFg: "#ffffff",
58
+ })
59
+ box1.add(text2)
60
+
61
+ const text3 = new TextRenderable(currentRenderer, {
62
+ id: "text3",
63
+ content: "that can be selected independently.",
64
+ fg: "#f0f6fc",
65
+ selectionBg: "#4a5568",
66
+ selectionFg: "#ffffff",
67
+ })
68
+ box1.add(text3)
69
+
70
+ await renderOnce()
71
+
72
+ await currentMouse.drag(text1.x, text1.y, text2.x + 10, text2.y)
73
+ await renderOnce()
74
+
75
+ expect(text1.hasSelection()).toBe(true)
76
+ expect(text2.hasSelection()).toBe(true)
77
+ expect(text3.hasSelection()).toBe(false)
78
+
79
+ expect(text1.getSelectedText()).toBe("This is a paragraph in the first box.")
80
+ expect(text2.getSelectedText()).toBe("It contain")
81
+
82
+ const buffers = currentRenderer.currentRenderBuffer.buffers
83
+ const width = currentRenderer.currentRenderBuffer.width
84
+ const expectedBg = RGBA.fromHex("#4a5568")
85
+
86
+ const getBgAt = (x: number, y: number) => {
87
+ const index = y * width + x
88
+ return RGBA.fromValues(
89
+ buffers.bg[index * 4],
90
+ buffers.bg[index * 4 + 1],
91
+ buffers.bg[index * 4 + 2],
92
+ buffers.bg[index * 4 + 3],
93
+ )
94
+ }
95
+
96
+ for (let col = text1.x; col < text1.x + text1.plainText.length; col++) {
97
+ const bg = getBgAt(col, text1.y)
98
+ const bgMatches =
99
+ Math.abs(bg.r - expectedBg.r) < 0.01 &&
100
+ Math.abs(bg.g - expectedBg.g) < 0.01 &&
101
+ Math.abs(bg.b - expectedBg.b) < 0.01
102
+ expect(bgMatches).toBe(true)
103
+ }
104
+
105
+ for (let col = text2.x; col < text2.x + 10; col++) {
106
+ const bg = getBgAt(col, text2.y)
107
+ const bgMatches =
108
+ Math.abs(bg.r - expectedBg.r) < 0.01 &&
109
+ Math.abs(bg.g - expectedBg.g) < 0.01 &&
110
+ Math.abs(bg.b - expectedBg.b) < 0.01
111
+ expect(bgMatches).toBe(true)
112
+ }
113
+
114
+ for (let col = text2.x + 10; col < text2.x + text2.plainText.length; col++) {
115
+ const bg = getBgAt(col, text2.y)
116
+ const bgMatches =
117
+ Math.abs(bg.r - expectedBg.r) < 0.01 &&
118
+ Math.abs(bg.g - expectedBg.g) < 0.01 &&
119
+ Math.abs(bg.b - expectedBg.b) < 0.01
120
+ expect(bgMatches).toBe(false)
121
+ }
122
+ })
123
+ })