@fairyhunter13/opentui-core 0.1.89 → 0.1.90

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 (570) 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 +141 -0
  7. package/docs/env-vars.md +140 -0
  8. package/docs/getting-started.md +353 -0
  9. package/docs/renderables-vs-constructs.md +159 -0
  10. package/docs/tree-sitter.md +311 -0
  11. package/package.json +61 -52
  12. package/scripts/build.ts +400 -0
  13. package/scripts/publish.ts +60 -0
  14. package/src/3d/SpriteResourceManager.ts +286 -0
  15. package/src/3d/SpriteUtils.ts +71 -0
  16. package/src/3d/TextureUtils.ts +196 -0
  17. package/src/3d/ThreeRenderable.ts +197 -0
  18. package/src/3d/WGPURenderer.ts +294 -0
  19. package/src/3d/animation/ExplodingSpriteEffect.ts +513 -0
  20. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +429 -0
  21. package/src/3d/animation/SpriteAnimator.ts +633 -0
  22. package/src/3d/animation/SpriteParticleGenerator.ts +435 -0
  23. package/src/3d/canvas.ts +464 -0
  24. package/src/3d/index.ts +12 -0
  25. package/src/3d/physics/PlanckPhysicsAdapter.ts +72 -0
  26. package/src/3d/physics/RapierPhysicsAdapter.ts +66 -0
  27. package/src/3d/physics/physics-interface.ts +31 -0
  28. package/src/3d/shaders/supersampling.wgsl +201 -0
  29. package/src/3d.ts +3 -0
  30. package/src/NativeSpanFeed.ts +300 -0
  31. package/src/Renderable.ts +1698 -0
  32. package/src/__snapshots__/buffer.test.ts.snap +28 -0
  33. package/src/animation/Timeline.test.ts +2709 -0
  34. package/src/animation/Timeline.ts +598 -0
  35. package/src/ansi.ts +18 -0
  36. package/src/benchmark/latest-all-bench-run.json +707 -0
  37. package/src/benchmark/latest-async-bench-run.json +336 -0
  38. package/src/benchmark/latest-default-bench-run.json +657 -0
  39. package/src/benchmark/latest-large-bench-run.json +707 -0
  40. package/src/benchmark/latest-quick-bench-run.json +207 -0
  41. package/src/benchmark/markdown-benchmark.ts +1804 -0
  42. package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
  43. package/src/benchmark/native-span-feed-benchmark.md +56 -0
  44. package/src/benchmark/native-span-feed-benchmark.ts +596 -0
  45. package/src/benchmark/native-span-feed-compare.ts +280 -0
  46. package/src/benchmark/renderer-benchmark.ts +754 -0
  47. package/src/benchmark/text-table-benchmark.ts +947 -0
  48. package/src/buffer.test.ts +291 -0
  49. package/src/buffer.ts +519 -0
  50. package/src/console.test.ts +612 -0
  51. package/src/console.ts +1255 -0
  52. package/src/edit-buffer.test.ts +1769 -0
  53. package/src/edit-buffer.ts +411 -0
  54. package/src/editor-view.test.ts +1032 -0
  55. package/src/editor-view.ts +284 -0
  56. package/src/examples/ascii-font-selection-demo.ts +245 -0
  57. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  58. package/src/examples/assets/concrete.png +0 -0
  59. package/src/examples/assets/crate.png +0 -0
  60. package/src/examples/assets/crate_emissive.png +0 -0
  61. package/src/examples/assets/forrest_background.png +0 -0
  62. package/src/examples/assets/hast-example.json +1018 -0
  63. package/src/examples/assets/heart.png +0 -0
  64. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  65. package/src/examples/assets/main_char_idle.png +0 -0
  66. package/src/examples/assets/main_char_jump_end.png +0 -0
  67. package/src/examples/assets/main_char_jump_landing.png +0 -0
  68. package/src/examples/assets/main_char_jump_start.png +0 -0
  69. package/src/examples/assets/main_char_run_loop.png +0 -0
  70. package/src/examples/assets/roughness_map.jpg +0 -0
  71. package/src/examples/build.ts +115 -0
  72. package/src/examples/code-demo.ts +584 -0
  73. package/src/examples/console-demo.ts +358 -0
  74. package/src/examples/core-plugin-slots-demo.ts +759 -0
  75. package/src/examples/diff-demo.ts +699 -0
  76. package/src/examples/draggable-three-demo.ts +259 -0
  77. package/src/examples/editor-demo.ts +322 -0
  78. package/src/examples/extmarks-demo.ts +204 -0
  79. package/src/examples/focus-restore-demo.ts +310 -0
  80. package/src/examples/fonts.ts +245 -0
  81. package/src/examples/fractal-shader-demo.ts +268 -0
  82. package/src/examples/framebuffer-demo.ts +674 -0
  83. package/src/examples/full-unicode-demo.ts +181 -0
  84. package/src/examples/golden-star-demo.ts +933 -0
  85. package/src/examples/grayscale-buffer-demo.ts +249 -0
  86. package/src/examples/hast-syntax-highlighting-demo.ts +129 -0
  87. package/src/examples/index.ts +925 -0
  88. package/src/examples/input-demo.ts +377 -0
  89. package/src/examples/input-select-layout-demo.ts +425 -0
  90. package/src/examples/install.sh +143 -0
  91. package/src/examples/keypress-debug-demo.ts +452 -0
  92. package/src/examples/lib/HexList.ts +122 -0
  93. package/src/examples/lib/PaletteGrid.ts +125 -0
  94. package/src/examples/lib/standalone-keys.ts +25 -0
  95. package/src/examples/lib/tab-controller.ts +243 -0
  96. package/src/examples/lights-phong-demo.ts +290 -0
  97. package/src/examples/link-demo.ts +220 -0
  98. package/src/examples/live-state-demo.ts +480 -0
  99. package/src/examples/markdown-demo.ts +620 -0
  100. package/src/examples/mouse-interaction-demo.ts +428 -0
  101. package/src/examples/nested-zindex-demo.ts +357 -0
  102. package/src/examples/opacity-example.ts +235 -0
  103. package/src/examples/opentui-demo.ts +1057 -0
  104. package/src/examples/physx-planck-2d-demo.ts +507 -0
  105. package/src/examples/physx-rapier-2d-demo.ts +526 -0
  106. package/src/examples/relative-positioning-demo.ts +323 -0
  107. package/src/examples/scroll-example.ts +214 -0
  108. package/src/examples/scrollbox-mouse-test.ts +112 -0
  109. package/src/examples/scrollbox-overlay-hit-test.ts +206 -0
  110. package/src/examples/select-demo.ts +237 -0
  111. package/src/examples/shader-cube-demo.ts +772 -0
  112. package/src/examples/simple-layout-example.ts +591 -0
  113. package/src/examples/slider-demo.ts +617 -0
  114. package/src/examples/split-mode-demo.ts +445 -0
  115. package/src/examples/sprite-animation-demo.ts +443 -0
  116. package/src/examples/sprite-particle-generator-demo.ts +486 -0
  117. package/src/examples/static-sprite-demo.ts +193 -0
  118. package/src/examples/sticky-scroll-example.ts +308 -0
  119. package/src/examples/styled-text-demo.ts +282 -0
  120. package/src/examples/tab-select-demo.ts +219 -0
  121. package/src/examples/terminal-title.ts +29 -0
  122. package/src/examples/terminal.ts +305 -0
  123. package/src/examples/text-node-demo.ts +416 -0
  124. package/src/examples/text-selection-demo.ts +377 -0
  125. package/src/examples/text-table-demo.ts +503 -0
  126. package/src/examples/text-truncation-demo.ts +481 -0
  127. package/src/examples/text-wrap.ts +757 -0
  128. package/src/examples/texture-loading-demo.ts +259 -0
  129. package/src/examples/timeline-example.ts +670 -0
  130. package/src/examples/transparency-demo.ts +241 -0
  131. package/src/examples/vnode-composition-demo.ts +404 -0
  132. package/src/index.ts +22 -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 +168 -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 +31 -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 +280 -0
  168. package/src/lib/keymapping.ts +87 -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 +1676 -0
  187. package/src/lib/stdin-parser.ts +1248 -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 +331 -0
  195. package/src/lib/tree-sitter/assets.d.ts +9 -0
  196. package/src/lib/tree-sitter/cache.test.ts +270 -0
  197. package/src/lib/tree-sitter/client.test.ts +1061 -0
  198. package/src/lib/tree-sitter/client.ts +615 -0
  199. package/src/lib/tree-sitter/default-parsers.ts +80 -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 +1001 -0
  203. package/src/lib/tree-sitter/parsers-config.ts +75 -0
  204. package/src/lib/tree-sitter/resolve-ft.ts +62 -0
  205. package/src/lib/tree-sitter/types.ts +81 -0
  206. package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
  207. package/src/lib/tree-sitter-styled-text.ts +306 -0
  208. package/src/lib/validate-dir-name.ts +55 -0
  209. package/src/lib/yoga.options.test.ts +628 -0
  210. package/src/lib/yoga.options.ts +346 -0
  211. package/src/plugins/core-slot.ts +579 -0
  212. package/src/plugins/registry.ts +377 -0
  213. package/src/plugins/types.ts +46 -0
  214. package/src/post/filters.ts +888 -0
  215. package/src/renderables/ASCIIFont.ts +219 -0
  216. package/src/renderables/Box.test.ts +160 -0
  217. package/src/renderables/Box.ts +295 -0
  218. package/src/renderables/Code.test.ts +2062 -0
  219. package/src/renderables/Code.ts +357 -0
  220. package/src/renderables/Diff.regression.test.ts +226 -0
  221. package/src/renderables/Diff.test.ts +3027 -0
  222. package/src/renderables/Diff.ts +1209 -0
  223. package/src/renderables/EditBufferRenderable.ts +764 -0
  224. package/src/renderables/FrameBuffer.ts +47 -0
  225. package/src/renderables/Input.test.ts +1228 -0
  226. package/src/renderables/Input.ts +245 -0
  227. package/src/renderables/LineNumberRenderable.ts +675 -0
  228. package/src/renderables/Markdown.ts +1106 -0
  229. package/src/renderables/ScrollBar.ts +422 -0
  230. package/src/renderables/ScrollBox.ts +883 -0
  231. package/src/renderables/Select.test.ts +1010 -0
  232. package/src/renderables/Select.ts +523 -0
  233. package/src/renderables/Slider.test.ts +456 -0
  234. package/src/renderables/Slider.ts +347 -0
  235. package/src/renderables/TabSelect.test.ts +197 -0
  236. package/src/renderables/TabSelect.ts +455 -0
  237. package/src/renderables/Text.selection-buffer.test.ts +123 -0
  238. package/src/renderables/Text.test.ts +2660 -0
  239. package/src/renderables/Text.ts +147 -0
  240. package/src/renderables/TextBufferRenderable.ts +518 -0
  241. package/src/renderables/TextNode.test.ts +1058 -0
  242. package/src/renderables/TextNode.ts +325 -0
  243. package/src/renderables/TextTable.test.ts +1421 -0
  244. package/src/renderables/TextTable.ts +1344 -0
  245. package/src/renderables/Textarea.ts +732 -0
  246. package/src/renderables/TimeToFirstDraw.ts +89 -0
  247. package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
  248. package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
  249. package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
  250. package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
  251. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
  252. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +816 -0
  253. package/src/renderables/__tests__/LineNumberRenderable.test.ts +1787 -0
  254. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
  255. package/src/renderables/__tests__/Markdown.test.ts +2287 -0
  256. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
  257. package/src/renderables/__tests__/Textarea.buffer.test.ts +682 -0
  258. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
  259. package/src/renderables/__tests__/Textarea.editing.test.ts +2041 -0
  260. package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
  261. package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
  262. package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
  263. package/src/renderables/__tests__/Textarea.keybinding.test.ts +3149 -0
  264. package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
  265. package/src/renderables/__tests__/Textarea.rendering.test.ts +1864 -0
  266. package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
  267. package/src/renderables/__tests__/Textarea.selection.test.ts +1590 -0
  268. package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
  269. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
  270. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
  271. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
  272. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
  273. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
  274. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
  275. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
  276. package/src/renderables/__tests__/markdown-parser.test.ts +217 -0
  277. package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
  278. package/src/renderables/composition/README.md +8 -0
  279. package/src/renderables/composition/VRenderable.ts +32 -0
  280. package/src/renderables/composition/constructs.ts +127 -0
  281. package/src/renderables/composition/vnode.ts +289 -0
  282. package/src/renderables/index.ts +22 -0
  283. package/src/renderables/markdown-parser.ts +66 -0
  284. package/src/renderer.ts +2363 -0
  285. package/src/runtime-plugin-support.ts +39 -0
  286. package/src/runtime-plugin.ts +144 -0
  287. package/src/syntax-style.test.ts +841 -0
  288. package/src/syntax-style.ts +264 -0
  289. package/src/testing/README.md +210 -0
  290. package/src/testing/capture-spans.test.ts +194 -0
  291. package/src/testing/integration.test.ts +276 -0
  292. package/src/testing/manual-clock.ts +106 -0
  293. package/src/testing/mock-keys.test.ts +1356 -0
  294. package/src/testing/mock-keys.ts +449 -0
  295. package/src/testing/mock-mouse.test.ts +218 -0
  296. package/src/testing/mock-mouse.ts +247 -0
  297. package/src/testing/mock-tree-sitter-client.ts +73 -0
  298. package/src/testing/spy.ts +13 -0
  299. package/src/testing/test-recorder.test.ts +415 -0
  300. package/src/testing/test-recorder.ts +145 -0
  301. package/src/testing/test-renderer.ts +116 -0
  302. package/src/testing.ts +7 -0
  303. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
  304. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
  305. package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
  306. package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
  307. package/src/tests/allocator-stats.test.ts +38 -0
  308. package/src/tests/destroy-during-render.test.ts +200 -0
  309. package/src/tests/hover-cursor.test.ts +98 -0
  310. package/src/tests/native-span-feed-async.test.ts +173 -0
  311. package/src/tests/native-span-feed-close.test.ts +120 -0
  312. package/src/tests/native-span-feed-coverage.test.ts +227 -0
  313. package/src/tests/native-span-feed-edge-cases.test.ts +352 -0
  314. package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
  315. package/src/tests/opacity.test.ts +123 -0
  316. package/src/tests/renderable.snapshot.test.ts +524 -0
  317. package/src/tests/renderable.test.ts +1281 -0
  318. package/src/tests/renderer.console-startup.test.ts +65 -0
  319. package/src/tests/renderer.control.test.ts +364 -0
  320. package/src/tests/renderer.core-slot-binding.test.ts +952 -0
  321. package/src/tests/renderer.cursor.test.ts +26 -0
  322. package/src/tests/renderer.destroy-during-render.test.ts +110 -0
  323. package/src/tests/renderer.focus-restore.test.ts +228 -0
  324. package/src/tests/renderer.focus.test.ts +251 -0
  325. package/src/tests/renderer.idle.test.ts +219 -0
  326. package/src/tests/renderer.input.test.ts +2145 -0
  327. package/src/tests/renderer.kitty-flags.test.ts +195 -0
  328. package/src/tests/renderer.mouse.test.ts +1269 -0
  329. package/src/tests/renderer.palette.test.ts +629 -0
  330. package/src/tests/renderer.selection.test.ts +49 -0
  331. package/src/tests/renderer.slot-registry.test.ts +649 -0
  332. package/src/tests/renderer.useMouse.test.ts +50 -0
  333. package/src/tests/runtime-plugin-support.fixture.ts +11 -0
  334. package/src/tests/runtime-plugin-support.test.ts +28 -0
  335. package/src/tests/runtime-plugin.fixture.ts +40 -0
  336. package/src/tests/runtime-plugin.test.ts +190 -0
  337. package/src/tests/scrollbox-culling-bug.test.ts +114 -0
  338. package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
  339. package/src/tests/scrollbox-hitgrid.test.ts +909 -0
  340. package/src/tests/scrollbox.test.ts +1530 -0
  341. package/src/tests/wrap-resize-perf.test.ts +229 -0
  342. package/src/tests/yoga-setters.test.ts +921 -0
  343. package/src/text-buffer-view.test.ts +705 -0
  344. package/src/text-buffer-view.ts +189 -0
  345. package/src/text-buffer.test.ts +347 -0
  346. package/src/text-buffer.ts +250 -0
  347. package/src/types.ts +152 -0
  348. package/src/utils.ts +88 -0
  349. package/src/zig/ansi.zig +268 -0
  350. package/src/zig/bench/README.md +50 -0
  351. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +887 -0
  352. package/src/zig/bench/edit-buffer_bench.zig +476 -0
  353. package/src/zig/bench/native-span-feed_bench.zig +100 -0
  354. package/src/zig/bench/rope-markers_bench.zig +713 -0
  355. package/src/zig/bench/rope_bench.zig +514 -0
  356. package/src/zig/bench/styled-text_bench.zig +470 -0
  357. package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
  358. package/src/zig/bench/text-buffer-view_bench.zig +459 -0
  359. package/src/zig/bench/text-chunk-graphemes_bench.zig +273 -0
  360. package/src/zig/bench/utf8_bench.zig +799 -0
  361. package/src/zig/bench-utils.zig +431 -0
  362. package/src/zig/bench.zig +217 -0
  363. package/src/zig/buffer.zig +2223 -0
  364. package/src/zig/build.zig +289 -0
  365. package/src/zig/build.zig.zon +16 -0
  366. package/src/zig/edit-buffer.zig +825 -0
  367. package/src/zig/editor-view.zig +802 -0
  368. package/src/zig/event-bus.zig +13 -0
  369. package/src/zig/event-emitter.zig +65 -0
  370. package/src/zig/file-logger.zig +92 -0
  371. package/src/zig/grapheme.zig +599 -0
  372. package/src/zig/lib.zig +1834 -0
  373. package/src/zig/link.zig +333 -0
  374. package/src/zig/logger.zig +43 -0
  375. package/src/zig/mem-registry.zig +125 -0
  376. package/src/zig/native-span-feed-bench-lib.zig +7 -0
  377. package/src/zig/native-span-feed.zig +708 -0
  378. package/src/zig/renderer.zig +1386 -0
  379. package/src/zig/rope.zig +1220 -0
  380. package/src/zig/syntax-style.zig +161 -0
  381. package/src/zig/terminal.zig +975 -0
  382. package/src/zig/test.zig +70 -0
  383. package/src/zig/tests/README.md +18 -0
  384. package/src/zig/tests/buffer_test.zig +2526 -0
  385. package/src/zig/tests/edit-buffer-history_test.zig +271 -0
  386. package/src/zig/tests/edit-buffer_test.zig +1689 -0
  387. package/src/zig/tests/editor-view_test.zig +3299 -0
  388. package/src/zig/tests/event-emitter_test.zig +249 -0
  389. package/src/zig/tests/grapheme_test.zig +1304 -0
  390. package/src/zig/tests/link_test.zig +190 -0
  391. package/src/zig/tests/mem-registry_test.zig +473 -0
  392. package/src/zig/tests/memory_leak_regression_test.zig +159 -0
  393. package/src/zig/tests/native-span-feed_test.zig +1264 -0
  394. package/src/zig/tests/renderer_test.zig +1010 -0
  395. package/src/zig/tests/rope-nested_test.zig +712 -0
  396. package/src/zig/tests/rope_fuzz_test.zig +238 -0
  397. package/src/zig/tests/rope_test.zig +2362 -0
  398. package/src/zig/tests/segment-merge.test.zig +148 -0
  399. package/src/zig/tests/syntax-style_test.zig +557 -0
  400. package/src/zig/tests/terminal_test.zig +719 -0
  401. package/src/zig/tests/text-buffer-drawing_test.zig +3237 -0
  402. package/src/zig/tests/text-buffer-highlights_test.zig +666 -0
  403. package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
  404. package/src/zig/tests/text-buffer-segment_test.zig +320 -0
  405. package/src/zig/tests/text-buffer-selection_test.zig +1035 -0
  406. package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
  407. package/src/zig/tests/text-buffer-view_test.zig +3649 -0
  408. package/src/zig/tests/text-buffer_test.zig +2191 -0
  409. package/src/zig/tests/unicode-width-map.zon +3909 -0
  410. package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
  411. package/src/zig/tests/utf8_test.zig +4057 -0
  412. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
  413. package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
  414. package/src/zig/tests/word-wrap-editing_test.zig +498 -0
  415. package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
  416. package/src/zig/text-buffer-iterators.zig +499 -0
  417. package/src/zig/text-buffer-segment.zig +404 -0
  418. package/src/zig/text-buffer-view.zig +1371 -0
  419. package/src/zig/text-buffer.zig +1180 -0
  420. package/src/zig/utf8.zig +1948 -0
  421. package/src/zig/utils.zig +9 -0
  422. package/src/zig-structs.ts +261 -0
  423. package/src/zig.ts +3843 -0
  424. package/tsconfig.build.json +22 -0
  425. package/tsconfig.json +28 -0
  426. package/3d/SpriteResourceManager.d.ts +0 -74
  427. package/3d/SpriteUtils.d.ts +0 -13
  428. package/3d/TextureUtils.d.ts +0 -24
  429. package/3d/ThreeRenderable.d.ts +0 -40
  430. package/3d/WGPURenderer.d.ts +0 -61
  431. package/3d/animation/ExplodingSpriteEffect.d.ts +0 -71
  432. package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +0 -76
  433. package/3d/animation/SpriteAnimator.d.ts +0 -124
  434. package/3d/animation/SpriteParticleGenerator.d.ts +0 -62
  435. package/3d/canvas.d.ts +0 -44
  436. package/3d/index.d.ts +0 -12
  437. package/3d/physics/PlanckPhysicsAdapter.d.ts +0 -19
  438. package/3d/physics/RapierPhysicsAdapter.d.ts +0 -19
  439. package/3d/physics/physics-interface.d.ts +0 -27
  440. package/3d.d.ts +0 -2
  441. package/3d.js +0 -34042
  442. package/3d.js.map +0 -155
  443. package/LICENSE +0 -21
  444. package/NativeSpanFeed.d.ts +0 -41
  445. package/Renderable.d.ts +0 -334
  446. package/animation/Timeline.d.ts +0 -126
  447. package/ansi.d.ts +0 -13
  448. package/buffer.d.ts +0 -107
  449. package/console.d.ts +0 -143
  450. package/edit-buffer.d.ts +0 -98
  451. package/editor-view.d.ts +0 -73
  452. package/index-e4hzc2j2.js +0 -113
  453. package/index-e4hzc2j2.js.map +0 -10
  454. package/index-nkrr8a4c.js +0 -18415
  455. package/index-nkrr8a4c.js.map +0 -64
  456. package/index-nyw5p3ep.js +0 -12619
  457. package/index-nyw5p3ep.js.map +0 -43
  458. package/index.d.ts +0 -21
  459. package/index.js +0 -430
  460. package/index.js.map +0 -9
  461. package/lib/KeyHandler.d.ts +0 -61
  462. package/lib/RGBA.d.ts +0 -25
  463. package/lib/ascii.font.d.ts +0 -508
  464. package/lib/border.d.ts +0 -49
  465. package/lib/bunfs.d.ts +0 -7
  466. package/lib/clipboard.d.ts +0 -17
  467. package/lib/clock.d.ts +0 -15
  468. package/lib/data-paths.d.ts +0 -26
  469. package/lib/debounce.d.ts +0 -42
  470. package/lib/detect-links.d.ts +0 -6
  471. package/lib/env.d.ts +0 -42
  472. package/lib/extmarks-history.d.ts +0 -17
  473. package/lib/extmarks.d.ts +0 -89
  474. package/lib/hast-styled-text.d.ts +0 -17
  475. package/lib/index.d.ts +0 -21
  476. package/lib/keymapping.d.ts +0 -25
  477. package/lib/objects-in-viewport.d.ts +0 -24
  478. package/lib/output.capture.d.ts +0 -24
  479. package/lib/parse.keypress-kitty.d.ts +0 -2
  480. package/lib/parse.keypress.d.ts +0 -26
  481. package/lib/parse.mouse.d.ts +0 -30
  482. package/lib/paste.d.ts +0 -7
  483. package/lib/queue.d.ts +0 -15
  484. package/lib/renderable.validations.d.ts +0 -12
  485. package/lib/scroll-acceleration.d.ts +0 -43
  486. package/lib/selection.d.ts +0 -63
  487. package/lib/singleton.d.ts +0 -7
  488. package/lib/stdin-parser.d.ts +0 -76
  489. package/lib/styled-text.d.ts +0 -63
  490. package/lib/terminal-capability-detection.d.ts +0 -30
  491. package/lib/terminal-palette.d.ts +0 -50
  492. package/lib/tree-sitter/assets/update.d.ts +0 -11
  493. package/lib/tree-sitter/client.d.ts +0 -47
  494. package/lib/tree-sitter/default-parsers.d.ts +0 -2
  495. package/lib/tree-sitter/download-utils.d.ts +0 -21
  496. package/lib/tree-sitter/index.d.ts +0 -8
  497. package/lib/tree-sitter/parser.worker.d.ts +0 -1
  498. package/lib/tree-sitter/parsers-config.d.ts +0 -38
  499. package/lib/tree-sitter/resolve-ft.d.ts +0 -2
  500. package/lib/tree-sitter/types.d.ts +0 -81
  501. package/lib/tree-sitter-styled-text.d.ts +0 -14
  502. package/lib/validate-dir-name.d.ts +0 -1
  503. package/lib/yoga.options.d.ts +0 -32
  504. package/parser.worker.js +0 -869
  505. package/parser.worker.js.map +0 -12
  506. package/plugins/core-slot.d.ts +0 -72
  507. package/plugins/registry.d.ts +0 -38
  508. package/plugins/types.d.ts +0 -34
  509. package/post/filters.d.ts +0 -105
  510. package/renderables/ASCIIFont.d.ts +0 -52
  511. package/renderables/Box.d.ts +0 -72
  512. package/renderables/Code.d.ts +0 -78
  513. package/renderables/Diff.d.ts +0 -142
  514. package/renderables/EditBufferRenderable.d.ts +0 -162
  515. package/renderables/FrameBuffer.d.ts +0 -16
  516. package/renderables/Input.d.ts +0 -67
  517. package/renderables/LineNumberRenderable.d.ts +0 -74
  518. package/renderables/Markdown.d.ts +0 -173
  519. package/renderables/ScrollBar.d.ts +0 -77
  520. package/renderables/ScrollBox.d.ts +0 -124
  521. package/renderables/Select.d.ts +0 -115
  522. package/renderables/Slider.d.ts +0 -44
  523. package/renderables/TabSelect.d.ts +0 -96
  524. package/renderables/Text.d.ts +0 -36
  525. package/renderables/TextBufferRenderable.d.ts +0 -105
  526. package/renderables/TextNode.d.ts +0 -91
  527. package/renderables/TextTable.d.ts +0 -140
  528. package/renderables/Textarea.d.ts +0 -114
  529. package/renderables/TimeToFirstDraw.d.ts +0 -24
  530. package/renderables/__tests__/renderable-test-utils.d.ts +0 -12
  531. package/renderables/composition/VRenderable.d.ts +0 -16
  532. package/renderables/composition/constructs.d.ts +0 -35
  533. package/renderables/composition/vnode.d.ts +0 -46
  534. package/renderables/index.d.ts +0 -22
  535. package/renderables/markdown-parser.d.ts +0 -10
  536. package/renderer.d.ts +0 -388
  537. package/runtime-plugin-support.d.ts +0 -3
  538. package/runtime-plugin-support.js +0 -29
  539. package/runtime-plugin-support.js.map +0 -10
  540. package/runtime-plugin.d.ts +0 -11
  541. package/runtime-plugin.js +0 -16
  542. package/runtime-plugin.js.map +0 -9
  543. package/syntax-style.d.ts +0 -54
  544. package/testing/manual-clock.d.ts +0 -16
  545. package/testing/mock-keys.d.ts +0 -81
  546. package/testing/mock-mouse.d.ts +0 -38
  547. package/testing/mock-tree-sitter-client.d.ts +0 -23
  548. package/testing/spy.d.ts +0 -7
  549. package/testing/test-recorder.d.ts +0 -61
  550. package/testing/test-renderer.d.ts +0 -23
  551. package/testing.d.ts +0 -6
  552. package/testing.js +0 -675
  553. package/testing.js.map +0 -15
  554. package/text-buffer-view.d.ts +0 -42
  555. package/text-buffer.d.ts +0 -67
  556. package/types.d.ts +0 -131
  557. package/utils.d.ts +0 -14
  558. package/zig-structs.d.ts +0 -155
  559. package/zig.d.ts +0 -351
  560. /package/{assets → src/lib/tree-sitter/assets}/javascript/highlights.scm +0 -0
  561. /package/{assets → src/lib/tree-sitter/assets}/javascript/tree-sitter-javascript.wasm +0 -0
  562. /package/{assets → src/lib/tree-sitter/assets}/markdown/highlights.scm +0 -0
  563. /package/{assets → src/lib/tree-sitter/assets}/markdown/injections.scm +0 -0
  564. /package/{assets → src/lib/tree-sitter/assets}/markdown/tree-sitter-markdown.wasm +0 -0
  565. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/highlights.scm +0 -0
  566. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  567. /package/{assets → src/lib/tree-sitter/assets}/typescript/highlights.scm +0 -0
  568. /package/{assets → src/lib/tree-sitter/assets}/typescript/tree-sitter-typescript.wasm +0 -0
  569. /package/{assets → src/lib/tree-sitter/assets}/zig/highlights.scm +0 -0
  570. /package/{assets → src/lib/tree-sitter/assets}/zig/tree-sitter-zig.wasm +0 -0
@@ -0,0 +1,168 @@
1
+ import type { ColorInput } from "./RGBA.js"
2
+
3
+ export interface BorderCharacters {
4
+ topLeft: string
5
+ topRight: string
6
+ bottomLeft: string
7
+ bottomRight: string
8
+ horizontal: string
9
+ vertical: string
10
+ topT: string
11
+ bottomT: string
12
+ leftT: string
13
+ rightT: string
14
+ cross: string
15
+ }
16
+
17
+ export type BorderStyle = "single" | "double" | "rounded" | "heavy"
18
+ export type BorderSides = "top" | "right" | "bottom" | "left"
19
+
20
+ const VALID_BORDER_STYLES: readonly BorderStyle[] = ["single", "double", "rounded", "heavy"] as const
21
+
22
+ export function isValidBorderStyle(value: unknown): value is BorderStyle {
23
+ return typeof value === "string" && VALID_BORDER_STYLES.includes(value as BorderStyle)
24
+ }
25
+
26
+ export function parseBorderStyle(value: unknown, fallback: BorderStyle = "single"): BorderStyle {
27
+ if (isValidBorderStyle(value)) {
28
+ return value
29
+ }
30
+
31
+ if (value !== undefined && value !== null) {
32
+ console.warn(
33
+ `Invalid borderStyle "${value}", falling back to "${fallback}". Valid values are: ${VALID_BORDER_STYLES.join(", ")}`,
34
+ )
35
+ }
36
+ return fallback
37
+ }
38
+
39
+ export const BorderChars: Record<BorderStyle, BorderCharacters> = {
40
+ single: {
41
+ topLeft: "┌",
42
+ topRight: "┐",
43
+ bottomLeft: "└",
44
+ bottomRight: "┘",
45
+ horizontal: "─",
46
+ vertical: "│",
47
+ topT: "┬",
48
+ bottomT: "┴",
49
+ leftT: "├",
50
+ rightT: "┤",
51
+ cross: "┼",
52
+ },
53
+ double: {
54
+ topLeft: "╔",
55
+ topRight: "╗",
56
+ bottomLeft: "╚",
57
+ bottomRight: "╝",
58
+ horizontal: "═",
59
+ vertical: "║",
60
+ topT: "╦",
61
+ bottomT: "╩",
62
+ leftT: "╠",
63
+ rightT: "╣",
64
+ cross: "╬",
65
+ },
66
+ rounded: {
67
+ topLeft: "╭",
68
+ topRight: "╮",
69
+ bottomLeft: "╰",
70
+ bottomRight: "╯",
71
+ horizontal: "─",
72
+ vertical: "│",
73
+ topT: "┬",
74
+ bottomT: "┴",
75
+ leftT: "├",
76
+ rightT: "┤",
77
+ cross: "┼",
78
+ },
79
+ heavy: {
80
+ topLeft: "┏",
81
+ topRight: "┓",
82
+ bottomLeft: "┗",
83
+ bottomRight: "┛",
84
+ horizontal: "━",
85
+ vertical: "┃",
86
+ topT: "┳",
87
+ bottomT: "┻",
88
+ leftT: "┣",
89
+ rightT: "┫",
90
+ cross: "╋",
91
+ },
92
+ }
93
+
94
+ export interface BorderConfig {
95
+ borderStyle: BorderStyle
96
+ border: boolean | BorderSides[]
97
+ borderColor?: ColorInput
98
+ customBorderChars?: BorderCharacters
99
+ }
100
+
101
+ export interface BoxDrawOptions {
102
+ x: number
103
+ y: number
104
+ width: number
105
+ height: number
106
+ borderStyle: BorderStyle
107
+ border: boolean | BorderSides[]
108
+ borderColor: ColorInput
109
+ customBorderChars?: BorderCharacters
110
+ backgroundColor: ColorInput
111
+ shouldFill?: boolean
112
+ title?: string
113
+ titleAlignment?: "left" | "center" | "right"
114
+ }
115
+
116
+ export interface BorderSidesConfig {
117
+ top: boolean
118
+ right: boolean
119
+ bottom: boolean
120
+ left: boolean
121
+ }
122
+
123
+ export function getBorderFromSides(sides: BorderSidesConfig): boolean | BorderSides[] {
124
+ const result: BorderSides[] = []
125
+ if (sides.top) result.push("top")
126
+ if (sides.right) result.push("right")
127
+ if (sides.bottom) result.push("bottom")
128
+ if (sides.left) result.push("left")
129
+ return result.length > 0 ? result : false
130
+ }
131
+
132
+ export function getBorderSides(border: boolean | BorderSides[]): BorderSidesConfig {
133
+ return border === true
134
+ ? { top: true, right: true, bottom: true, left: true }
135
+ : Array.isArray(border)
136
+ ? {
137
+ top: border.includes("top"),
138
+ right: border.includes("right"),
139
+ bottom: border.includes("bottom"),
140
+ left: border.includes("left"),
141
+ }
142
+ : { top: false, right: false, bottom: false, left: false }
143
+ }
144
+
145
+ // Convert BorderCharacters to Uint32Array for passing to Zig
146
+ export function borderCharsToArray(chars: BorderCharacters): Uint32Array {
147
+ const array = new Uint32Array(11)
148
+ array[0] = chars.topLeft.codePointAt(0)!
149
+ array[1] = chars.topRight.codePointAt(0)!
150
+ array[2] = chars.bottomLeft.codePointAt(0)!
151
+ array[3] = chars.bottomRight.codePointAt(0)!
152
+ array[4] = chars.horizontal.codePointAt(0)!
153
+ array[5] = chars.vertical.codePointAt(0)!
154
+ array[6] = chars.topT.codePointAt(0)!
155
+ array[7] = chars.bottomT.codePointAt(0)!
156
+ array[8] = chars.leftT.codePointAt(0)!
157
+ array[9] = chars.rightT.codePointAt(0)!
158
+ array[10] = chars.cross.codePointAt(0)!
159
+ return array
160
+ }
161
+
162
+ // Pre-converted border character arrays for performance
163
+ export const BorderCharArrays: Record<BorderStyle, Uint32Array> = {
164
+ single: borderCharsToArray(BorderChars.single),
165
+ double: borderCharsToArray(BorderChars.double),
166
+ rounded: borderCharsToArray(BorderChars.rounded),
167
+ heavy: borderCharsToArray(BorderChars.heavy),
168
+ }
@@ -0,0 +1,27 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import { isBunfsPath, getBunfsRootPath } from "./bunfs.js"
3
+
4
+ describe("bunfs", () => {
5
+ test("isBunfsPath detects $bunfs paths", () => {
6
+ expect(isBunfsPath("/$bunfs/root/file.wasm")).toBe(true)
7
+ })
8
+
9
+ test("isBunfsPath detects Windows B: paths", () => {
10
+ expect(isBunfsPath("B:\\~BUN\\root\\file.wasm")).toBe(true)
11
+ expect(isBunfsPath("B:/~BUN/root/file.wasm")).toBe(true)
12
+ })
13
+
14
+ test("isBunfsPath ignores regular paths", () => {
15
+ expect(isBunfsPath("/usr/local/bin/file")).toBe(false)
16
+ expect(isBunfsPath("C:/Users/file.wasm")).toBe(false)
17
+ })
18
+
19
+ test("getBunfsRootPath", () => {
20
+ const root = getBunfsRootPath()
21
+ if (process.platform === "win32") {
22
+ expect(root).toBe("B:\\~BUN\\root")
23
+ } else {
24
+ expect(root).toBe("/$bunfs/root")
25
+ }
26
+ })
27
+ })
@@ -0,0 +1,18 @@
1
+ import { basename, join } from "node:path"
2
+
3
+ export function isBunfsPath(path: string): boolean {
4
+ // Removed ambiguous '//' check
5
+ return path.includes("$bunfs") || /^B:[\\/]~BUN/i.test(path)
6
+ }
7
+
8
+ export function getBunfsRootPath(): string {
9
+ return process.platform === "win32" ? "B:\\~BUN\\root" : "/$bunfs/root"
10
+ }
11
+
12
+ /**
13
+ * Normalizes a path to the embedded root.
14
+ * Flattens directory structure to ensure file exists at root.
15
+ */
16
+ export function normalizeBunfsPath(fileName: string): string {
17
+ return join(getBunfsRootPath(), basename(fileName))
18
+ }
@@ -0,0 +1,41 @@
1
+ import { describe, expect, it, afterEach } from "bun:test"
2
+ import { createTestRenderer, type TestRenderer } from "../testing/test-renderer.js"
3
+ import { ClipboardTarget, encodeOsc52Payload } from "./clipboard.js"
4
+ import type { RenderLib } from "../zig.js"
5
+
6
+ describe("clipboard", () => {
7
+ let renderer: TestRenderer | null = null
8
+
9
+ const enableOsc52 = (testRenderer: TestRenderer) => {
10
+ const lib = (testRenderer as unknown as { lib: RenderLib }).lib
11
+ lib.processCapabilityResponse(testRenderer.rendererPtr, "\x1bP>|kitty(0.40.1)\x1b\\")
12
+ }
13
+
14
+ afterEach(() => {
15
+ renderer?.destroy()
16
+ renderer = null
17
+ })
18
+
19
+ it("encodes payload as base64", () => {
20
+ const payload = encodeOsc52Payload("hello")
21
+ const decoded = new TextDecoder().decode(payload)
22
+ expect(decoded).toBe(Buffer.from("hello").toString("base64"))
23
+ })
24
+
25
+ it("gates clipboard writes on OSC 52 support", async () => {
26
+ ;({ renderer } = await createTestRenderer({ remote: true }))
27
+
28
+ expect(renderer.isOsc52Supported()).toBe(false)
29
+ expect(renderer.copyToClipboardOSC52("test")).toBe(false)
30
+ expect(renderer.clearClipboardOSC52()).toBe(false)
31
+
32
+ enableOsc52(renderer)
33
+
34
+ expect(renderer.isOsc52Supported()).toBe(true)
35
+ expect(renderer.copyToClipboardOSC52("test")).toBe(true)
36
+ expect(renderer.copyToClipboardOSC52("test", ClipboardTarget.Primary)).toBe(true)
37
+ expect(renderer.copyToClipboardOSC52("test", ClipboardTarget.Secondary)).toBe(true)
38
+ expect(renderer.copyToClipboardOSC52("test", ClipboardTarget.Query)).toBe(true)
39
+ expect(renderer.clearClipboardOSC52()).toBe(true)
40
+ })
41
+ })
@@ -0,0 +1,47 @@
1
+ // OSC 52 clipboard support for terminal applications.
2
+ // Delegates to native Zig implementation for ANSI sequence generation.
3
+
4
+ import type { Pointer } from "bun:ffi"
5
+ import type { RenderLib } from "../zig.js"
6
+
7
+ export enum ClipboardTarget {
8
+ Clipboard = 0,
9
+ Primary = 1,
10
+ Secondary = 2,
11
+ Query = 3,
12
+ }
13
+
14
+ export function encodeOsc52Payload(text: string, encoder: TextEncoder = new TextEncoder()): Uint8Array {
15
+ const base64 = Buffer.from(text).toString("base64")
16
+ return encoder.encode(base64)
17
+ }
18
+
19
+ export class Clipboard {
20
+ private lib: RenderLib
21
+ private rendererPtr: Pointer
22
+
23
+ constructor(lib: RenderLib, rendererPtr: Pointer) {
24
+ this.lib = lib
25
+ this.rendererPtr = rendererPtr
26
+ }
27
+
28
+ public copyToClipboardOSC52(text: string, target: ClipboardTarget = ClipboardTarget.Clipboard): boolean {
29
+ if (!this.isOsc52Supported()) {
30
+ return false
31
+ }
32
+ const payload = encodeOsc52Payload(text, this.lib.encoder)
33
+ return this.lib.copyToClipboardOSC52(this.rendererPtr, target, payload)
34
+ }
35
+
36
+ public clearClipboardOSC52(target: ClipboardTarget = ClipboardTarget.Clipboard): boolean {
37
+ if (!this.isOsc52Supported()) {
38
+ return false
39
+ }
40
+ return this.lib.clearClipboardOSC52(this.rendererPtr, target)
41
+ }
42
+
43
+ public isOsc52Supported(): boolean {
44
+ const caps = this.lib.getTerminalCapabilities(this.rendererPtr)
45
+ return Boolean(caps?.osc52)
46
+ }
47
+ }
@@ -0,0 +1,31 @@
1
+ export type TimerHandle = ReturnType<typeof globalThis.setTimeout> | number
2
+
3
+ export interface Clock {
4
+ now(): number
5
+ setTimeout(fn: () => void, delayMs: number): TimerHandle
6
+ clearTimeout(handle: TimerHandle): void
7
+ setInterval(fn: () => void, delayMs: number): TimerHandle
8
+ clearInterval(handle: TimerHandle): void
9
+ }
10
+
11
+ export class SystemClock implements Clock {
12
+ public now(): number {
13
+ return Date.now()
14
+ }
15
+
16
+ public setTimeout(fn: () => void, delayMs: number): TimerHandle {
17
+ return globalThis.setTimeout(fn, delayMs)
18
+ }
19
+
20
+ public clearTimeout(handle: TimerHandle): void {
21
+ globalThis.clearTimeout(handle as ReturnType<typeof globalThis.setTimeout>)
22
+ }
23
+
24
+ public setInterval(fn: () => void, delayMs: number): TimerHandle {
25
+ return globalThis.setInterval(fn, delayMs)
26
+ }
27
+
28
+ public clearInterval(handle: TimerHandle): void {
29
+ globalThis.clearInterval(handle as ReturnType<typeof globalThis.setTimeout>)
30
+ }
31
+ }
@@ -0,0 +1,133 @@
1
+ import { test, expect } from "bun:test"
2
+ import { DataPathsManager } from "./data-paths.js"
3
+
4
+ test("DataPathsManager validates appName", () => {
5
+ const manager = new DataPathsManager()
6
+
7
+ // Valid names should work
8
+ expect(() => {
9
+ manager.appName = "myapp"
10
+ }).not.toThrow()
11
+
12
+ expect(() => {
13
+ manager.appName = "my-app"
14
+ }).not.toThrow()
15
+
16
+ expect(() => {
17
+ manager.appName = "my_app"
18
+ }).not.toThrow()
19
+
20
+ expect(() => {
21
+ manager.appName = "MyApp123"
22
+ }).not.toThrow()
23
+
24
+ // Invalid names should throw
25
+ expect(() => {
26
+ manager.appName = ""
27
+ }).toThrow("Invalid app name")
28
+
29
+ expect(() => {
30
+ manager.appName = " "
31
+ }).toThrow("Invalid app name")
32
+
33
+ expect(() => {
34
+ manager.appName = "app/name"
35
+ }).toThrow("Invalid app name")
36
+
37
+ expect(() => {
38
+ manager.appName = "app\\name"
39
+ }).toThrow("Invalid app name")
40
+
41
+ expect(() => {
42
+ manager.appName = "app<name"
43
+ }).toThrow("Invalid app name")
44
+
45
+ expect(() => {
46
+ manager.appName = "app>name"
47
+ }).toThrow("Invalid app name")
48
+
49
+ expect(() => {
50
+ manager.appName = 'app"name'
51
+ }).toThrow("Invalid app name")
52
+
53
+ expect(() => {
54
+ manager.appName = "app|name"
55
+ }).toThrow("Invalid app name")
56
+
57
+ expect(() => {
58
+ manager.appName = "app?name"
59
+ }).toThrow("Invalid app name")
60
+
61
+ expect(() => {
62
+ manager.appName = "app*name"
63
+ }).toThrow("Invalid app name")
64
+
65
+ expect(() => {
66
+ manager.appName = "CON"
67
+ }).toThrow("Invalid app name")
68
+
69
+ expect(() => {
70
+ manager.appName = "PRN"
71
+ }).toThrow("Invalid app name")
72
+
73
+ expect(() => {
74
+ manager.appName = "app."
75
+ }).toThrow("Invalid app name")
76
+
77
+ expect(() => {
78
+ manager.appName = "app "
79
+ }).toThrow("Invalid app name")
80
+
81
+ expect(() => {
82
+ manager.appName = "."
83
+ }).toThrow("Invalid app name")
84
+
85
+ expect(() => {
86
+ manager.appName = ".."
87
+ }).toThrow("Invalid app name")
88
+ })
89
+
90
+ test("DataPathsManager constructor uses valid default appName", () => {
91
+ // Should not throw when creating a new instance
92
+ expect(() => {
93
+ new DataPathsManager()
94
+ }).not.toThrow()
95
+
96
+ const manager = new DataPathsManager()
97
+ expect(manager.appName).toBe("opentui")
98
+ })
99
+
100
+ test("DataPathsManager emits paths:changed event when appName changes", async () => {
101
+ const manager = new DataPathsManager()
102
+ let eventFired = false
103
+ let eventPaths: any = null
104
+
105
+ manager.on("paths:changed", (paths) => {
106
+ eventFired = true
107
+ eventPaths = paths
108
+ })
109
+
110
+ const originalAppName = manager.appName
111
+ manager.appName = "test-app-event"
112
+
113
+ expect(eventFired).toBe(true)
114
+ expect(eventPaths).toBeDefined()
115
+ expect(eventPaths.globalDataPath).toContain("test-app-event")
116
+ expect(eventPaths.globalConfigPath).toContain("test-app-event")
117
+ expect(eventPaths.globalConfigFile).toContain("test-app-event")
118
+ expect(eventPaths.localConfigFile).toContain("test-app-event")
119
+ })
120
+
121
+ test("DataPathsManager does not emit event when appName is set to same value", () => {
122
+ const manager = new DataPathsManager()
123
+ let eventFired = false
124
+
125
+ manager.on("paths:changed", () => {
126
+ eventFired = true
127
+ })
128
+
129
+ // Set to the same value
130
+ manager.appName = manager.appName
131
+
132
+ expect(eventFired).toBe(false)
133
+ })
@@ -0,0 +1,109 @@
1
+ import os from "os"
2
+ import path from "path"
3
+ import { EventEmitter } from "events"
4
+ import { singleton } from "./singleton.js"
5
+ import { env, registerEnvVar } from "./env.js"
6
+ import { isValidDirectoryName } from "./validate-dir-name.js"
7
+
8
+ // Register environment variables for XDG directories
9
+ registerEnvVar({
10
+ name: "XDG_CONFIG_HOME",
11
+ description: "Base directory for user-specific configuration files",
12
+ type: "string",
13
+ default: "",
14
+ })
15
+
16
+ registerEnvVar({
17
+ name: "XDG_DATA_HOME",
18
+ description: "Base directory for user-specific data files",
19
+ type: "string",
20
+ default: "",
21
+ })
22
+
23
+ export interface DataPaths {
24
+ globalConfigPath: string
25
+ globalConfigFile: string
26
+ localConfigFile: string
27
+ globalDataPath: string
28
+ }
29
+
30
+ export interface DataPathsEvents {
31
+ "paths:changed": [paths: DataPaths]
32
+ }
33
+
34
+ export class DataPathsManager extends EventEmitter<DataPathsEvents> {
35
+ private _appName: string
36
+ private _globalConfigPath?: string
37
+ private _globalConfigFile?: string
38
+ private _localConfigFile?: string
39
+ private _globalDataPath?: string
40
+ constructor() {
41
+ super()
42
+ this._appName = "opentui"
43
+ }
44
+
45
+ get appName(): string {
46
+ return this._appName
47
+ }
48
+
49
+ set appName(value: string) {
50
+ if (!isValidDirectoryName(value)) {
51
+ throw new Error(`Invalid app name "${value}": must be a valid directory name`)
52
+ }
53
+ if (this._appName !== value) {
54
+ this._appName = value
55
+ this._globalConfigPath = undefined
56
+ this._globalConfigFile = undefined
57
+ this._localConfigFile = undefined
58
+ this._globalDataPath = undefined
59
+ this.emit("paths:changed", this.toObject())
60
+ }
61
+ }
62
+
63
+ get globalConfigPath(): string {
64
+ if (this._globalConfigPath === undefined) {
65
+ const homeDir = os.homedir()
66
+ const xdgConfigHome = env.XDG_CONFIG_HOME
67
+ const baseConfigDir = xdgConfigHome || path.join(homeDir, ".config")
68
+ this._globalConfigPath = path.join(baseConfigDir, this._appName)
69
+ }
70
+ return this._globalConfigPath
71
+ }
72
+
73
+ get globalConfigFile(): string {
74
+ if (this._globalConfigFile === undefined) {
75
+ this._globalConfigFile = path.join(this.globalConfigPath, "init.ts")
76
+ }
77
+ return this._globalConfigFile
78
+ }
79
+
80
+ get localConfigFile(): string {
81
+ if (this._localConfigFile === undefined) {
82
+ this._localConfigFile = path.join(process.cwd(), `.${this._appName}.ts`)
83
+ }
84
+ return this._localConfigFile
85
+ }
86
+
87
+ get globalDataPath(): string {
88
+ if (this._globalDataPath === undefined) {
89
+ const homeDir = os.homedir()
90
+ const xdgDataHome = env.XDG_DATA_HOME
91
+ const baseDataDir = xdgDataHome || path.join(homeDir, ".local/share")
92
+ this._globalDataPath = path.join(baseDataDir, this._appName)
93
+ }
94
+ return this._globalDataPath
95
+ }
96
+
97
+ toObject(): DataPaths {
98
+ return {
99
+ globalConfigPath: this.globalConfigPath,
100
+ globalConfigFile: this.globalConfigFile,
101
+ localConfigFile: this.localConfigFile,
102
+ globalDataPath: this.globalDataPath,
103
+ }
104
+ }
105
+ }
106
+
107
+ export function getDataPaths(): DataPathsManager {
108
+ return singleton("data-paths-opentui", () => new DataPathsManager())
109
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * A module-level map to store timeout IDs for all debounced functions
3
+ * Structure: Map<scopeId, Map<debounceId, timerId>>
4
+ */
5
+ const TIMERS_MAP = new Map<string | number, Map<string | number, ReturnType<typeof setTimeout>>>()
6
+
7
+ /**
8
+ * Debounce controller that manages debounce instances for a specific scope
9
+ */
10
+ export class DebounceController {
11
+ constructor(private scopeId: string | number) {
12
+ // Initialize the scope map if it doesn't exist
13
+ if (!TIMERS_MAP.has(this.scopeId)) {
14
+ TIMERS_MAP.set(this.scopeId, new Map())
15
+ }
16
+ }
17
+
18
+ /**
19
+ * Debounces the provided function with the given ID
20
+ *
21
+ * @param id Unique identifier within this scope
22
+ * @param ms Milliseconds to wait before executing
23
+ * @param fn Function to execute
24
+ */
25
+ debounce<R>(id: string | number, ms: number, fn: () => Promise<R>): Promise<R> {
26
+ const scopeMap = TIMERS_MAP.get(this.scopeId)!
27
+
28
+ return new Promise((resolve, reject) => {
29
+ // Clear any existing timeout for this ID
30
+ if (scopeMap.has(id)) {
31
+ clearTimeout(scopeMap.get(id))
32
+ }
33
+
34
+ // Set a new timeout
35
+ const timerId = setTimeout(() => {
36
+ try {
37
+ resolve(fn())
38
+ } catch (error) {
39
+ reject(error)
40
+ }
41
+ scopeMap.delete(id)
42
+ }, ms)
43
+
44
+ // Store the new timeout ID
45
+ scopeMap.set(id, timerId)
46
+ })
47
+ }
48
+
49
+ /**
50
+ * Clear a specific debounce timer in this scope
51
+ *
52
+ * @param id The debounce ID to clear
53
+ */
54
+ clearDebounce(id: string | number): void {
55
+ const scopeMap = TIMERS_MAP.get(this.scopeId)
56
+ if (scopeMap && scopeMap.has(id)) {
57
+ clearTimeout(scopeMap.get(id))
58
+ scopeMap.delete(id)
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Clear all debounce timers in this scope
64
+ */
65
+ clear(): void {
66
+ const scopeMap = TIMERS_MAP.get(this.scopeId)
67
+ if (scopeMap) {
68
+ scopeMap.forEach((timerId) => clearTimeout(timerId))
69
+ scopeMap.clear()
70
+ }
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Creates a new debounce controller for a specific scope
76
+ *
77
+ * @param scopeId Unique identifier for this debounce scope
78
+ * @returns A DebounceController for the specified scope
79
+ */
80
+ export function createDebounce(scopeId: string | number): DebounceController {
81
+ return new DebounceController(scopeId)
82
+ }
83
+
84
+ /**
85
+ * Clears all debounce timers for a specific scope
86
+ *
87
+ * @param scopeId The scope identifier
88
+ */
89
+ export function clearDebounceScope(scopeId: string | number): void {
90
+ const scopeMap = TIMERS_MAP.get(scopeId)
91
+ if (scopeMap) {
92
+ scopeMap.forEach((timerId) => clearTimeout(timerId))
93
+ scopeMap.clear()
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Clears all active debounce timers across all scopes
99
+ */
100
+ export function clearAllDebounces(): void {
101
+ TIMERS_MAP.forEach((scopeMap) => {
102
+ scopeMap.forEach((timerId) => clearTimeout(timerId))
103
+ scopeMap.clear()
104
+ })
105
+ TIMERS_MAP.clear()
106
+ }