@fairyhunter13/opentui-core 0.1.113 → 0.1.114

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (591) hide show
  1. package/dev/keypress-debug-renderer.ts +148 -0
  2. package/dev/keypress-debug.ts +43 -0
  3. package/dev/print-env-vars.ts +32 -0
  4. package/dev/test-tmux-graphics-334.sh +68 -0
  5. package/dev/thai-debug-test.ts +68 -0
  6. package/docs/development.md +144 -0
  7. package/package.json +62 -53
  8. package/scripts/build.ts +400 -0
  9. package/scripts/publish.ts +60 -0
  10. package/src/3d/SpriteResourceManager.ts +286 -0
  11. package/src/3d/SpriteUtils.ts +70 -0
  12. package/src/3d/TextureUtils.ts +196 -0
  13. package/src/3d/ThreeRenderable.ts +197 -0
  14. package/src/3d/WGPURenderer.ts +294 -0
  15. package/src/3d/animation/ExplodingSpriteEffect.ts +513 -0
  16. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +429 -0
  17. package/src/3d/animation/SpriteAnimator.ts +633 -0
  18. package/src/3d/animation/SpriteParticleGenerator.ts +435 -0
  19. package/src/3d/canvas.ts +464 -0
  20. package/src/3d/index.ts +12 -0
  21. package/src/3d/physics/PlanckPhysicsAdapter.ts +72 -0
  22. package/src/3d/physics/RapierPhysicsAdapter.ts +66 -0
  23. package/src/3d/physics/physics-interface.ts +31 -0
  24. package/src/3d/shaders/supersampling.wgsl +201 -0
  25. package/src/3d.ts +3 -0
  26. package/src/NativeSpanFeed.ts +300 -0
  27. package/src/Renderable.ts +1704 -0
  28. package/src/__snapshots__/buffer.test.ts.snap +28 -0
  29. package/src/animation/Timeline.test.ts +2709 -0
  30. package/src/animation/Timeline.ts +598 -0
  31. package/src/ansi.ts +18 -0
  32. package/src/benchmark/attenuation-benchmark.ts +81 -0
  33. package/src/benchmark/colormatrix-benchmark.ts +128 -0
  34. package/src/benchmark/gain-benchmark.ts +80 -0
  35. package/src/benchmark/latest-all-bench-run.json +707 -0
  36. package/src/benchmark/latest-async-bench-run.json +336 -0
  37. package/src/benchmark/latest-default-bench-run.json +657 -0
  38. package/src/benchmark/latest-large-bench-run.json +707 -0
  39. package/src/benchmark/latest-quick-bench-run.json +207 -0
  40. package/src/benchmark/markdown-benchmark.ts +1796 -0
  41. package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
  42. package/src/benchmark/native-span-feed-benchmark.md +56 -0
  43. package/src/benchmark/native-span-feed-benchmark.ts +596 -0
  44. package/src/benchmark/native-span-feed-compare.ts +280 -0
  45. package/src/benchmark/renderer-benchmark.ts +754 -0
  46. package/src/benchmark/text-table-benchmark.ts +948 -0
  47. package/src/buffer.test.ts +291 -0
  48. package/src/buffer.ts +554 -0
  49. package/src/console.test.ts +612 -0
  50. package/src/console.ts +1254 -0
  51. package/src/edit-buffer.test.ts +1769 -0
  52. package/src/edit-buffer.ts +411 -0
  53. package/src/editor-view.test.ts +1032 -0
  54. package/src/editor-view.ts +284 -0
  55. package/src/examples/ascii-font-selection-demo.ts +245 -0
  56. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  57. package/src/examples/assets/concrete.png +0 -0
  58. package/src/examples/assets/crate.png +0 -0
  59. package/src/examples/assets/crate_emissive.png +0 -0
  60. package/src/examples/assets/forrest_background.png +0 -0
  61. package/src/examples/assets/hast-example.json +1018 -0
  62. package/src/examples/assets/heart.png +0 -0
  63. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  64. package/src/examples/assets/main_char_idle.png +0 -0
  65. package/src/examples/assets/main_char_jump_end.png +0 -0
  66. package/src/examples/assets/main_char_jump_landing.png +0 -0
  67. package/src/examples/assets/main_char_jump_start.png +0 -0
  68. package/src/examples/assets/main_char_run_loop.png +0 -0
  69. package/src/examples/assets/roughness_map.jpg +0 -0
  70. package/src/examples/build.ts +115 -0
  71. package/src/examples/code-demo.ts +924 -0
  72. package/src/examples/console-demo.ts +358 -0
  73. package/src/examples/core-plugin-slots-demo.ts +759 -0
  74. package/src/examples/diff-demo.ts +701 -0
  75. package/src/examples/draggable-three-demo.ts +259 -0
  76. package/src/examples/editor-demo.ts +322 -0
  77. package/src/examples/extmarks-demo.ts +196 -0
  78. package/src/examples/focus-restore-demo.ts +310 -0
  79. package/src/examples/fonts.ts +245 -0
  80. package/src/examples/fractal-shader-demo.ts +268 -0
  81. package/src/examples/framebuffer-demo.ts +674 -0
  82. package/src/examples/full-unicode-demo.ts +241 -0
  83. package/src/examples/golden-star-demo.ts +933 -0
  84. package/src/examples/grayscale-buffer-demo.ts +249 -0
  85. package/src/examples/hast-syntax-highlighting-demo.ts +129 -0
  86. package/src/examples/index.ts +926 -0
  87. package/src/examples/input-demo.ts +377 -0
  88. package/src/examples/input-select-layout-demo.ts +425 -0
  89. package/src/examples/install.sh +143 -0
  90. package/src/examples/keypress-debug-demo.ts +452 -0
  91. package/src/examples/lib/HexList.ts +122 -0
  92. package/src/examples/lib/PaletteGrid.ts +125 -0
  93. package/src/examples/lib/standalone-keys.ts +25 -0
  94. package/src/examples/lib/tab-controller.ts +243 -0
  95. package/src/examples/lights-phong-demo.ts +290 -0
  96. package/src/examples/link-demo.ts +220 -0
  97. package/src/examples/live-state-demo.ts +480 -0
  98. package/src/examples/markdown-demo.ts +725 -0
  99. package/src/examples/mouse-interaction-demo.ts +428 -0
  100. package/src/examples/nested-zindex-demo.ts +357 -0
  101. package/src/examples/opacity-example.ts +235 -0
  102. package/src/examples/opentui-demo.ts +1057 -0
  103. package/src/examples/physx-planck-2d-demo.ts +623 -0
  104. package/src/examples/physx-rapier-2d-demo.ts +655 -0
  105. package/src/examples/relative-positioning-demo.ts +323 -0
  106. package/src/examples/scroll-example.ts +214 -0
  107. package/src/examples/scrollbox-mouse-test.ts +112 -0
  108. package/src/examples/scrollbox-overlay-hit-test.ts +206 -0
  109. package/src/examples/select-demo.ts +237 -0
  110. package/src/examples/shader-cube-demo.ts +1015 -0
  111. package/src/examples/simple-layout-example.ts +591 -0
  112. package/src/examples/slider-demo.ts +617 -0
  113. package/src/examples/split-mode-demo.ts +453 -0
  114. package/src/examples/sprite-animation-demo.ts +443 -0
  115. package/src/examples/sprite-particle-generator-demo.ts +486 -0
  116. package/src/examples/static-sprite-demo.ts +193 -0
  117. package/src/examples/sticky-scroll-example.ts +308 -0
  118. package/src/examples/styled-text-demo.ts +282 -0
  119. package/src/examples/tab-select-demo.ts +219 -0
  120. package/src/examples/terminal-title.ts +29 -0
  121. package/src/examples/terminal.ts +305 -0
  122. package/src/examples/text-node-demo.ts +416 -0
  123. package/src/examples/text-selection-demo.ts +377 -0
  124. package/src/examples/text-table-demo.ts +503 -0
  125. package/src/examples/text-truncation-demo.ts +481 -0
  126. package/src/examples/text-wrap.ts +757 -0
  127. package/src/examples/texture-loading-demo.ts +259 -0
  128. package/src/examples/timeline-example.ts +670 -0
  129. package/src/examples/transparency-demo.ts +400 -0
  130. package/src/examples/vnode-composition-demo.ts +404 -0
  131. package/src/examples/wide-grapheme-overlay-demo.ts +280 -0
  132. package/src/index.ts +24 -0
  133. package/src/lib/KeyHandler.integration.test.ts +292 -0
  134. package/src/lib/KeyHandler.stopPropagation.test.ts +289 -0
  135. package/src/lib/KeyHandler.test.ts +662 -0
  136. package/src/lib/KeyHandler.ts +222 -0
  137. package/src/lib/RGBA.test.ts +984 -0
  138. package/src/lib/RGBA.ts +204 -0
  139. package/src/lib/ascii.font.ts +330 -0
  140. package/src/lib/border.test.ts +83 -0
  141. package/src/lib/border.ts +170 -0
  142. package/src/lib/bunfs.test.ts +27 -0
  143. package/src/lib/bunfs.ts +18 -0
  144. package/src/lib/clipboard.test.ts +41 -0
  145. package/src/lib/clipboard.ts +47 -0
  146. package/src/lib/clock.ts +35 -0
  147. package/src/lib/data-paths.test.ts +133 -0
  148. package/src/lib/data-paths.ts +109 -0
  149. package/src/lib/debounce.ts +106 -0
  150. package/src/lib/detect-links.test.ts +98 -0
  151. package/src/lib/detect-links.ts +56 -0
  152. package/src/lib/env.test.ts +228 -0
  153. package/src/lib/env.ts +209 -0
  154. package/src/lib/extmarks-history.ts +51 -0
  155. package/src/lib/extmarks-multiwidth.test.ts +322 -0
  156. package/src/lib/extmarks.test.ts +3457 -0
  157. package/src/lib/extmarks.ts +843 -0
  158. package/src/lib/fonts/block.json +405 -0
  159. package/src/lib/fonts/grid.json +265 -0
  160. package/src/lib/fonts/huge.json +741 -0
  161. package/src/lib/fonts/pallet.json +314 -0
  162. package/src/lib/fonts/shade.json +591 -0
  163. package/src/lib/fonts/slick.json +321 -0
  164. package/src/lib/fonts/tiny.json +69 -0
  165. package/src/lib/hast-styled-text.ts +59 -0
  166. package/src/lib/index.ts +21 -0
  167. package/src/lib/keymapping.test.ts +317 -0
  168. package/src/lib/keymapping.ts +115 -0
  169. package/src/lib/objects-in-viewport.test.ts +787 -0
  170. package/src/lib/objects-in-viewport.ts +153 -0
  171. package/src/lib/output.capture.ts +58 -0
  172. package/src/lib/parse.keypress-kitty.protocol.test.ts +340 -0
  173. package/src/lib/parse.keypress-kitty.test.ts +663 -0
  174. package/src/lib/parse.keypress-kitty.ts +439 -0
  175. package/src/lib/parse.keypress.test.ts +1849 -0
  176. package/src/lib/parse.keypress.ts +397 -0
  177. package/src/lib/parse.mouse.test.ts +552 -0
  178. package/src/lib/parse.mouse.ts +232 -0
  179. package/src/lib/paste.ts +16 -0
  180. package/src/lib/queue.ts +65 -0
  181. package/src/lib/renderable.validations.test.ts +87 -0
  182. package/src/lib/renderable.validations.ts +83 -0
  183. package/src/lib/scroll-acceleration.ts +98 -0
  184. package/src/lib/selection.ts +240 -0
  185. package/src/lib/singleton.ts +28 -0
  186. package/src/lib/stdin-parser.test.ts +2290 -0
  187. package/src/lib/stdin-parser.ts +1810 -0
  188. package/src/lib/styled-text.ts +178 -0
  189. package/src/lib/terminal-capability-detection.test.ts +202 -0
  190. package/src/lib/terminal-capability-detection.ts +79 -0
  191. package/src/lib/terminal-palette.test.ts +878 -0
  192. package/src/lib/terminal-palette.ts +383 -0
  193. package/src/lib/tree-sitter/assets/README.md +118 -0
  194. package/src/lib/tree-sitter/assets/update.ts +334 -0
  195. package/src/lib/tree-sitter/assets.d.ts +9 -0
  196. package/src/lib/tree-sitter/cache.test.ts +273 -0
  197. package/src/lib/tree-sitter/client.test.ts +1165 -0
  198. package/src/lib/tree-sitter/client.ts +607 -0
  199. package/src/lib/tree-sitter/default-parsers.ts +86 -0
  200. package/src/lib/tree-sitter/download-utils.ts +148 -0
  201. package/src/lib/tree-sitter/index.ts +28 -0
  202. package/src/lib/tree-sitter/parser.worker.ts +1042 -0
  203. package/src/lib/tree-sitter/parsers-config.ts +81 -0
  204. package/src/lib/tree-sitter/resolve-ft.test.ts +55 -0
  205. package/src/lib/tree-sitter/resolve-ft.ts +189 -0
  206. package/src/lib/tree-sitter/types.ts +82 -0
  207. package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
  208. package/src/lib/tree-sitter-styled-text.ts +306 -0
  209. package/src/lib/validate-dir-name.ts +55 -0
  210. package/src/lib/yoga.options.test.ts +628 -0
  211. package/src/lib/yoga.options.ts +346 -0
  212. package/src/plugins/core-slot.ts +579 -0
  213. package/src/plugins/registry.ts +402 -0
  214. package/src/plugins/types.ts +46 -0
  215. package/src/post/effects.ts +930 -0
  216. package/src/post/filters.ts +489 -0
  217. package/src/post/matrices.ts +288 -0
  218. package/src/renderables/ASCIIFont.ts +219 -0
  219. package/src/renderables/Box.test.ts +205 -0
  220. package/src/renderables/Box.ts +326 -0
  221. package/src/renderables/Code.test.ts +2062 -0
  222. package/src/renderables/Code.ts +357 -0
  223. package/src/renderables/Diff.regression.test.ts +226 -0
  224. package/src/renderables/Diff.test.ts +3101 -0
  225. package/src/renderables/Diff.ts +1211 -0
  226. package/src/renderables/EditBufferRenderable.test.ts +288 -0
  227. package/src/renderables/EditBufferRenderable.ts +1166 -0
  228. package/src/renderables/FrameBuffer.ts +47 -0
  229. package/src/renderables/Input.test.ts +1228 -0
  230. package/src/renderables/Input.ts +247 -0
  231. package/src/renderables/LineNumberRenderable.ts +724 -0
  232. package/src/renderables/Markdown.ts +1393 -0
  233. package/src/renderables/ScrollBar.ts +422 -0
  234. package/src/renderables/ScrollBox.ts +883 -0
  235. package/src/renderables/Select.test.ts +1033 -0
  236. package/src/renderables/Select.ts +524 -0
  237. package/src/renderables/Slider.test.ts +456 -0
  238. package/src/renderables/Slider.ts +342 -0
  239. package/src/renderables/TabSelect.test.ts +197 -0
  240. package/src/renderables/TabSelect.ts +455 -0
  241. package/src/renderables/Text.selection-buffer.test.ts +123 -0
  242. package/src/renderables/Text.test.ts +2660 -0
  243. package/src/renderables/Text.ts +147 -0
  244. package/src/renderables/TextBufferRenderable.ts +518 -0
  245. package/src/renderables/TextNode.test.ts +1058 -0
  246. package/src/renderables/TextNode.ts +325 -0
  247. package/src/renderables/TextTable.test.ts +1421 -0
  248. package/src/renderables/TextTable.ts +1344 -0
  249. package/src/renderables/Textarea.ts +430 -0
  250. package/src/renderables/TimeToFirstDraw.ts +89 -0
  251. package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
  252. package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
  253. package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
  254. package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
  255. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
  256. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +816 -0
  257. package/src/renderables/__tests__/LineNumberRenderable.test.ts +1865 -0
  258. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
  259. package/src/renderables/__tests__/Markdown.code-colors.test.ts +242 -0
  260. package/src/renderables/__tests__/Markdown.test.ts +2518 -0
  261. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
  262. package/src/renderables/__tests__/Textarea.buffer.test.ts +682 -0
  263. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
  264. package/src/renderables/__tests__/Textarea.editing.test.ts +2041 -0
  265. package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
  266. package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
  267. package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
  268. package/src/renderables/__tests__/Textarea.keybinding.test.ts +3149 -0
  269. package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
  270. package/src/renderables/__tests__/Textarea.rendering.test.ts +1866 -0
  271. package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
  272. package/src/renderables/__tests__/Textarea.selection.test.ts +1590 -0
  273. package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
  274. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
  275. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
  276. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
  277. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
  278. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
  279. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
  280. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
  281. package/src/renderables/__tests__/markdown-parser.test.ts +217 -0
  282. package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
  283. package/src/renderables/composition/README.md +8 -0
  284. package/src/renderables/composition/VRenderable.ts +32 -0
  285. package/src/renderables/composition/constructs.ts +127 -0
  286. package/src/renderables/composition/vnode.ts +289 -0
  287. package/src/renderables/index.ts +23 -0
  288. package/src/renderables/markdown-parser.ts +66 -0
  289. package/src/renderer.ts +2681 -0
  290. package/src/runtime-plugin-support.ts +39 -0
  291. package/src/runtime-plugin.ts +615 -0
  292. package/src/syntax-style.test.ts +841 -0
  293. package/src/syntax-style.ts +257 -0
  294. package/src/testing/README.md +210 -0
  295. package/src/testing/capture-spans.test.ts +194 -0
  296. package/src/testing/integration.test.ts +276 -0
  297. package/src/testing/manual-clock.ts +117 -0
  298. package/src/testing/mock-keys.test.ts +1378 -0
  299. package/src/testing/mock-keys.ts +457 -0
  300. package/src/testing/mock-mouse.test.ts +218 -0
  301. package/src/testing/mock-mouse.ts +247 -0
  302. package/src/testing/mock-tree-sitter-client.ts +73 -0
  303. package/src/testing/spy.ts +13 -0
  304. package/src/testing/test-recorder.test.ts +415 -0
  305. package/src/testing/test-recorder.ts +145 -0
  306. package/src/testing/test-renderer.ts +132 -0
  307. package/src/testing.ts +7 -0
  308. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
  309. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
  310. package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
  311. package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
  312. package/src/tests/allocator-stats.test.ts +38 -0
  313. package/src/tests/destroy-during-render.test.ts +200 -0
  314. package/src/tests/destroy-on-exit.fixture.ts +36 -0
  315. package/src/tests/destroy-on-exit.test.ts +41 -0
  316. package/src/tests/hover-cursor.test.ts +98 -0
  317. package/src/tests/native-span-feed-async.test.ts +173 -0
  318. package/src/tests/native-span-feed-close.test.ts +120 -0
  319. package/src/tests/native-span-feed-coverage.test.ts +227 -0
  320. package/src/tests/native-span-feed-edge-cases.test.ts +352 -0
  321. package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
  322. package/src/tests/opacity.test.ts +123 -0
  323. package/src/tests/renderable.snapshot.test.ts +524 -0
  324. package/src/tests/renderable.test.ts +1281 -0
  325. package/src/tests/renderer.clock.test.ts +158 -0
  326. package/src/tests/renderer.console-startup.test.ts +185 -0
  327. package/src/tests/renderer.control.test.ts +425 -0
  328. package/src/tests/renderer.core-slot-binding.test.ts +952 -0
  329. package/src/tests/renderer.cursor.test.ts +26 -0
  330. package/src/tests/renderer.destroy-during-render.test.ts +147 -0
  331. package/src/tests/renderer.focus-restore.test.ts +257 -0
  332. package/src/tests/renderer.focus.test.ts +294 -0
  333. package/src/tests/renderer.idle.test.ts +219 -0
  334. package/src/tests/renderer.input.test.ts +2237 -0
  335. package/src/tests/renderer.kitty-flags.test.ts +195 -0
  336. package/src/tests/renderer.mouse.test.ts +1274 -0
  337. package/src/tests/renderer.palette.test.ts +629 -0
  338. package/src/tests/renderer.selection.test.ts +49 -0
  339. package/src/tests/renderer.slot-registry.test.ts +684 -0
  340. package/src/tests/renderer.useMouse.test.ts +47 -0
  341. package/src/tests/runtime-plugin-node-modules-cycle.fixture.ts +76 -0
  342. package/src/tests/runtime-plugin-node-modules-mjs.fixture.ts +43 -0
  343. package/src/tests/runtime-plugin-node-modules-no-bare-rewrite.fixture.ts +67 -0
  344. package/src/tests/runtime-plugin-node-modules-package-type-cache.fixture.ts +72 -0
  345. package/src/tests/runtime-plugin-node-modules-runtime-specifier.fixture.ts +44 -0
  346. package/src/tests/runtime-plugin-node-modules-scoped-package-bare-rewrite.fixture.ts +85 -0
  347. package/src/tests/runtime-plugin-path-alias.fixture.ts +43 -0
  348. package/src/tests/runtime-plugin-resolve-roots.fixture.ts +65 -0
  349. package/src/tests/runtime-plugin-support.fixture.ts +11 -0
  350. package/src/tests/runtime-plugin-support.test.ts +19 -0
  351. package/src/tests/runtime-plugin-windows-file-url.fixture.ts +30 -0
  352. package/src/tests/runtime-plugin.fixture.ts +40 -0
  353. package/src/tests/runtime-plugin.test.ts +354 -0
  354. package/src/tests/scrollbox-culling-bug.test.ts +114 -0
  355. package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
  356. package/src/tests/scrollbox-hitgrid.test.ts +909 -0
  357. package/src/tests/scrollbox.test.ts +1530 -0
  358. package/src/tests/wrap-resize-perf.test.ts +276 -0
  359. package/src/tests/yoga-setters.test.ts +921 -0
  360. package/src/text-buffer-view.test.ts +705 -0
  361. package/src/text-buffer-view.ts +189 -0
  362. package/src/text-buffer.test.ts +347 -0
  363. package/src/text-buffer.ts +250 -0
  364. package/src/types.ts +161 -0
  365. package/src/utils.ts +88 -0
  366. package/src/zig/ansi.zig +268 -0
  367. package/src/zig/bench/README.md +50 -0
  368. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +887 -0
  369. package/src/zig/bench/edit-buffer_bench.zig +476 -0
  370. package/src/zig/bench/native-span-feed_bench.zig +100 -0
  371. package/src/zig/bench/rope-markers_bench.zig +713 -0
  372. package/src/zig/bench/rope_bench.zig +514 -0
  373. package/src/zig/bench/styled-text_bench.zig +470 -0
  374. package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
  375. package/src/zig/bench/text-buffer-view_bench.zig +459 -0
  376. package/src/zig/bench/text-chunk-graphemes_bench.zig +273 -0
  377. package/src/zig/bench/utf8_bench.zig +799 -0
  378. package/src/zig/bench-utils.zig +431 -0
  379. package/src/zig/bench.zig +217 -0
  380. package/src/zig/buffer-methods.zig +211 -0
  381. package/src/zig/buffer.zig +2281 -0
  382. package/src/zig/build.zig +289 -0
  383. package/src/zig/build.zig.zon +16 -0
  384. package/src/zig/edit-buffer.zig +825 -0
  385. package/src/zig/editor-view.zig +802 -0
  386. package/src/zig/event-bus.zig +13 -0
  387. package/src/zig/event-emitter.zig +65 -0
  388. package/src/zig/file-logger.zig +92 -0
  389. package/src/zig/grapheme.zig +599 -0
  390. package/src/zig/lib.zig +1854 -0
  391. package/src/zig/link.zig +333 -0
  392. package/src/zig/logger.zig +43 -0
  393. package/src/zig/mem-registry.zig +125 -0
  394. package/src/zig/native-span-feed-bench-lib.zig +7 -0
  395. package/src/zig/native-span-feed.zig +708 -0
  396. package/src/zig/renderer.zig +1393 -0
  397. package/src/zig/rope.zig +1220 -0
  398. package/src/zig/syntax-style.zig +161 -0
  399. package/src/zig/terminal.zig +987 -0
  400. package/src/zig/test.zig +72 -0
  401. package/src/zig/tests/README.md +18 -0
  402. package/src/zig/tests/buffer-methods_test.zig +1109 -0
  403. package/src/zig/tests/buffer_test.zig +2557 -0
  404. package/src/zig/tests/edit-buffer-history_test.zig +271 -0
  405. package/src/zig/tests/edit-buffer_test.zig +1689 -0
  406. package/src/zig/tests/editor-view_test.zig +3299 -0
  407. package/src/zig/tests/event-emitter_test.zig +249 -0
  408. package/src/zig/tests/grapheme_test.zig +1304 -0
  409. package/src/zig/tests/link_test.zig +190 -0
  410. package/src/zig/tests/mem-registry_test.zig +473 -0
  411. package/src/zig/tests/memory_leak_regression_test.zig +159 -0
  412. package/src/zig/tests/native-span-feed_test.zig +1264 -0
  413. package/src/zig/tests/renderer_test.zig +1017 -0
  414. package/src/zig/tests/rope-nested_test.zig +712 -0
  415. package/src/zig/tests/rope_fuzz_test.zig +238 -0
  416. package/src/zig/tests/rope_test.zig +2362 -0
  417. package/src/zig/tests/segment-merge.test.zig +148 -0
  418. package/src/zig/tests/syntax-style_test.zig +557 -0
  419. package/src/zig/tests/terminal_test.zig +754 -0
  420. package/src/zig/tests/text-buffer-drawing_test.zig +3237 -0
  421. package/src/zig/tests/text-buffer-highlights_test.zig +666 -0
  422. package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
  423. package/src/zig/tests/text-buffer-segment_test.zig +320 -0
  424. package/src/zig/tests/text-buffer-selection_test.zig +1035 -0
  425. package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
  426. package/src/zig/tests/text-buffer-view_test.zig +3649 -0
  427. package/src/zig/tests/text-buffer_test.zig +2191 -0
  428. package/src/zig/tests/unicode-width-map.zon +3909 -0
  429. package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
  430. package/src/zig/tests/utf8_test.zig +4057 -0
  431. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
  432. package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
  433. package/src/zig/tests/word-wrap-editing_test.zig +498 -0
  434. package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
  435. package/src/zig/text-buffer-iterators.zig +499 -0
  436. package/src/zig/text-buffer-segment.zig +404 -0
  437. package/src/zig/text-buffer-view.zig +1371 -0
  438. package/src/zig/text-buffer.zig +1180 -0
  439. package/src/zig/utf8.zig +1948 -0
  440. package/src/zig/utils.zig +9 -0
  441. package/src/zig-structs.ts +261 -0
  442. package/src/zig.ts +3884 -0
  443. package/tsconfig.build.json +24 -0
  444. package/tsconfig.json +27 -0
  445. package/3d/SpriteResourceManager.d.ts +0 -74
  446. package/3d/SpriteUtils.d.ts +0 -13
  447. package/3d/TextureUtils.d.ts +0 -24
  448. package/3d/ThreeRenderable.d.ts +0 -40
  449. package/3d/WGPURenderer.d.ts +0 -61
  450. package/3d/animation/ExplodingSpriteEffect.d.ts +0 -71
  451. package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +0 -76
  452. package/3d/animation/SpriteAnimator.d.ts +0 -124
  453. package/3d/animation/SpriteParticleGenerator.d.ts +0 -62
  454. package/3d/canvas.d.ts +0 -44
  455. package/3d/index.d.ts +0 -12
  456. package/3d/physics/PlanckPhysicsAdapter.d.ts +0 -19
  457. package/3d/physics/RapierPhysicsAdapter.d.ts +0 -19
  458. package/3d/physics/physics-interface.d.ts +0 -27
  459. package/3d.d.ts +0 -2
  460. package/3d.js +0 -34041
  461. package/3d.js.map +0 -155
  462. package/LICENSE +0 -21
  463. package/NativeSpanFeed.d.ts +0 -41
  464. package/Renderable.d.ts +0 -334
  465. package/animation/Timeline.d.ts +0 -126
  466. package/ansi.d.ts +0 -13
  467. package/buffer.d.ts +0 -111
  468. package/console.d.ts +0 -144
  469. package/edit-buffer.d.ts +0 -98
  470. package/editor-view.d.ts +0 -73
  471. package/index-9vwc3fg6.js +0 -12260
  472. package/index-9vwc3fg6.js.map +0 -42
  473. package/index-dcj62y8t.js +0 -20614
  474. package/index-dcj62y8t.js.map +0 -67
  475. package/index-f7n39gpy.js +0 -411
  476. package/index-f7n39gpy.js.map +0 -10
  477. package/index.d.ts +0 -23
  478. package/index.js +0 -478
  479. package/index.js.map +0 -9
  480. package/lib/KeyHandler.d.ts +0 -61
  481. package/lib/RGBA.d.ts +0 -25
  482. package/lib/ascii.font.d.ts +0 -508
  483. package/lib/border.d.ts +0 -51
  484. package/lib/bunfs.d.ts +0 -7
  485. package/lib/clipboard.d.ts +0 -17
  486. package/lib/clock.d.ts +0 -15
  487. package/lib/data-paths.d.ts +0 -26
  488. package/lib/debounce.d.ts +0 -42
  489. package/lib/detect-links.d.ts +0 -6
  490. package/lib/env.d.ts +0 -42
  491. package/lib/extmarks-history.d.ts +0 -17
  492. package/lib/extmarks.d.ts +0 -89
  493. package/lib/hast-styled-text.d.ts +0 -17
  494. package/lib/index.d.ts +0 -21
  495. package/lib/keymapping.d.ts +0 -25
  496. package/lib/objects-in-viewport.d.ts +0 -24
  497. package/lib/output.capture.d.ts +0 -24
  498. package/lib/parse.keypress-kitty.d.ts +0 -2
  499. package/lib/parse.keypress.d.ts +0 -26
  500. package/lib/parse.mouse.d.ts +0 -30
  501. package/lib/paste.d.ts +0 -7
  502. package/lib/queue.d.ts +0 -15
  503. package/lib/renderable.validations.d.ts +0 -12
  504. package/lib/scroll-acceleration.d.ts +0 -43
  505. package/lib/selection.d.ts +0 -63
  506. package/lib/singleton.d.ts +0 -7
  507. package/lib/stdin-parser.d.ts +0 -87
  508. package/lib/styled-text.d.ts +0 -63
  509. package/lib/terminal-capability-detection.d.ts +0 -30
  510. package/lib/terminal-palette.d.ts +0 -50
  511. package/lib/tree-sitter/assets/update.d.ts +0 -11
  512. package/lib/tree-sitter/client.d.ts +0 -47
  513. package/lib/tree-sitter/default-parsers.d.ts +0 -2
  514. package/lib/tree-sitter/download-utils.d.ts +0 -21
  515. package/lib/tree-sitter/index.d.ts +0 -8
  516. package/lib/tree-sitter/parser.worker.d.ts +0 -1
  517. package/lib/tree-sitter/parsers-config.d.ts +0 -53
  518. package/lib/tree-sitter/resolve-ft.d.ts +0 -5
  519. package/lib/tree-sitter/types.d.ts +0 -82
  520. package/lib/tree-sitter-styled-text.d.ts +0 -14
  521. package/lib/validate-dir-name.d.ts +0 -1
  522. package/lib/yoga.options.d.ts +0 -32
  523. package/parser.worker.js +0 -899
  524. package/parser.worker.js.map +0 -12
  525. package/plugins/core-slot.d.ts +0 -72
  526. package/plugins/registry.d.ts +0 -42
  527. package/plugins/types.d.ts +0 -34
  528. package/post/effects.d.ts +0 -147
  529. package/post/filters.d.ts +0 -65
  530. package/post/matrices.d.ts +0 -20
  531. package/renderables/ASCIIFont.d.ts +0 -52
  532. package/renderables/Box.d.ts +0 -81
  533. package/renderables/Code.d.ts +0 -78
  534. package/renderables/Diff.d.ts +0 -142
  535. package/renderables/EditBufferRenderable.d.ts +0 -237
  536. package/renderables/FrameBuffer.d.ts +0 -16
  537. package/renderables/Input.d.ts +0 -67
  538. package/renderables/LineNumberRenderable.d.ts +0 -78
  539. package/renderables/Markdown.d.ts +0 -185
  540. package/renderables/ScrollBar.d.ts +0 -77
  541. package/renderables/ScrollBox.d.ts +0 -124
  542. package/renderables/Select.d.ts +0 -115
  543. package/renderables/Slider.d.ts +0 -47
  544. package/renderables/TabSelect.d.ts +0 -96
  545. package/renderables/Text.d.ts +0 -36
  546. package/renderables/TextBufferRenderable.d.ts +0 -105
  547. package/renderables/TextNode.d.ts +0 -91
  548. package/renderables/TextTable.d.ts +0 -140
  549. package/renderables/Textarea.d.ts +0 -63
  550. package/renderables/TimeToFirstDraw.d.ts +0 -24
  551. package/renderables/__tests__/renderable-test-utils.d.ts +0 -12
  552. package/renderables/composition/VRenderable.d.ts +0 -16
  553. package/renderables/composition/constructs.d.ts +0 -35
  554. package/renderables/composition/vnode.d.ts +0 -46
  555. package/renderables/index.d.ts +0 -23
  556. package/renderables/markdown-parser.d.ts +0 -10
  557. package/renderer.d.ts +0 -419
  558. package/runtime-plugin-support.d.ts +0 -3
  559. package/runtime-plugin-support.js +0 -29
  560. package/runtime-plugin-support.js.map +0 -10
  561. package/runtime-plugin.d.ts +0 -16
  562. package/runtime-plugin.js +0 -16
  563. package/runtime-plugin.js.map +0 -9
  564. package/syntax-style.d.ts +0 -54
  565. package/testing/manual-clock.d.ts +0 -17
  566. package/testing/mock-keys.d.ts +0 -81
  567. package/testing/mock-mouse.d.ts +0 -38
  568. package/testing/mock-tree-sitter-client.d.ts +0 -23
  569. package/testing/spy.d.ts +0 -7
  570. package/testing/test-recorder.d.ts +0 -61
  571. package/testing/test-renderer.d.ts +0 -23
  572. package/testing.d.ts +0 -6
  573. package/testing.js +0 -697
  574. package/testing.js.map +0 -15
  575. package/text-buffer-view.d.ts +0 -42
  576. package/text-buffer.d.ts +0 -67
  577. package/types.d.ts +0 -139
  578. package/utils.d.ts +0 -14
  579. package/zig-structs.d.ts +0 -155
  580. package/zig.d.ts +0 -353
  581. /package/{assets → src/lib/tree-sitter/assets}/javascript/highlights.scm +0 -0
  582. /package/{assets → src/lib/tree-sitter/assets}/javascript/tree-sitter-javascript.wasm +0 -0
  583. /package/{assets → src/lib/tree-sitter/assets}/markdown/highlights.scm +0 -0
  584. /package/{assets → src/lib/tree-sitter/assets}/markdown/injections.scm +0 -0
  585. /package/{assets → src/lib/tree-sitter/assets}/markdown/tree-sitter-markdown.wasm +0 -0
  586. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/highlights.scm +0 -0
  587. /package/{assets → src/lib/tree-sitter/assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  588. /package/{assets → src/lib/tree-sitter/assets}/typescript/highlights.scm +0 -0
  589. /package/{assets → src/lib/tree-sitter/assets}/typescript/tree-sitter-typescript.wasm +0 -0
  590. /package/{assets → src/lib/tree-sitter/assets}/zig/highlights.scm +0 -0
  591. /package/{assets → src/lib/tree-sitter/assets}/zig/tree-sitter-zig.wasm +0 -0
@@ -0,0 +1,98 @@
1
+ import { test, expect, describe } from "bun:test"
2
+ import { detectLinks } from "./detect-links.js"
3
+ import type { TextChunk } from "../text-buffer.js"
4
+ import type { SimpleHighlight } from "./tree-sitter/types.js"
5
+ import { RGBA } from "./RGBA.js"
6
+
7
+ function chunk(text: string): TextChunk {
8
+ return { __isChunk: true, text, fg: RGBA.fromInts(255, 255, 255, 255), attributes: 0 }
9
+ }
10
+
11
+ describe("detectLinks", () => {
12
+ test("should set link on markup.link.url chunks", () => {
13
+ const content = "[Click here](https://example.com)"
14
+ const highlights: SimpleHighlight[] = [
15
+ [0, 1, "markup.link"],
16
+ [1, 11, "markup.link.label"],
17
+ [11, 13, "markup.link"],
18
+ [13, 32, "markup.link.url"],
19
+ [32, 33, "markup.link"],
20
+ ]
21
+ const chunks = [chunk("["), chunk("Click here"), chunk("]("), chunk("https://example.com"), chunk(")")]
22
+
23
+ const result = detectLinks(chunks, { content, highlights })
24
+
25
+ expect(result.find((c) => c.text === "https://example.com")!.link).toEqual({ url: "https://example.com" })
26
+ expect(result.find((c) => c.text === "Click here")!.link).toEqual({ url: "https://example.com" })
27
+ })
28
+
29
+ test("should set link on string.special.url chunks", () => {
30
+ const content = "// see https://example.com for details"
31
+ const highlights: SimpleHighlight[] = [
32
+ [0, 38, "comment"],
33
+ [7, 26, "string.special.url"],
34
+ ]
35
+ const chunks = [chunk("// see "), chunk("https://example.com"), chunk(" for details")]
36
+
37
+ const result = detectLinks(chunks, { content, highlights })
38
+
39
+ expect(result.find((c) => c.text === "https://example.com")!.link).toEqual({ url: "https://example.com" })
40
+ })
41
+
42
+ test("should not set link on non-URL chunks", () => {
43
+ const content = "const x = 42"
44
+ const highlights: SimpleHighlight[] = [
45
+ [0, 5, "keyword"],
46
+ [6, 7, "variable"],
47
+ [10, 12, "number"],
48
+ ]
49
+ const chunks = [chunk("const"), chunk(" "), chunk("x"), chunk(" = "), chunk("42")]
50
+
51
+ const result = detectLinks(chunks, { content, highlights })
52
+
53
+ for (const c of result) {
54
+ expect(c.link).toBeUndefined()
55
+ }
56
+ })
57
+
58
+ test("should return chunks unchanged when no URL scopes exist", () => {
59
+ const content = "hello world"
60
+ const highlights: SimpleHighlight[] = [[0, 5, "keyword"]]
61
+ const chunks = [chunk("hello"), chunk(" world")]
62
+
63
+ const result = detectLinks(chunks, { content, highlights })
64
+
65
+ expect(result).toBe(chunks)
66
+ })
67
+
68
+ test("should detect links when chunks have concealed text", () => {
69
+ // Original content: [Click here](https://example.com)
70
+ // With concealment, `[` and `]` are concealed to empty strings,
71
+ // and `(` and `)` are concealed to empty strings.
72
+ // This means chunk text lengths don't match original byte offsets.
73
+ const content = "[Click here](https://example.com)"
74
+ const highlights: SimpleHighlight[] = [
75
+ [0, 1, "markup.link"], // [
76
+ [1, 11, "markup.link.label"], // Click here
77
+ [11, 13, "markup.link"], // ](
78
+ [13, 32, "markup.link.url"], // https://example.com
79
+ [32, 33, "markup.link"], // )
80
+ ]
81
+ // Simulate concealed chunks: `[` -> "", `](` -> " ", `)` -> ""
82
+ // The URL and label chunks remain unchanged.
83
+ const chunks = [
84
+ chunk(""), // concealed `[`
85
+ chunk("Click here"), // label, unchanged
86
+ chunk(" "), // concealed `](`
87
+ chunk("https://example.com"), // URL, unchanged
88
+ chunk(""), // concealed `)`
89
+ ]
90
+
91
+ const result = detectLinks(chunks, { content, highlights })
92
+
93
+ // The URL chunk should still get its link despite concealed offsets
94
+ expect(result.find((c) => c.text === "https://example.com")!.link).toEqual({ url: "https://example.com" })
95
+ // The label chunk should also get the link
96
+ expect(result.find((c) => c.text === "Click here")!.link).toEqual({ url: "https://example.com" })
97
+ })
98
+ })
@@ -0,0 +1,56 @@
1
+ import type { TextChunk } from "../text-buffer.js"
2
+ import type { SimpleHighlight } from "./tree-sitter/types.js"
3
+
4
+ const URL_SCOPES = ["markup.link.url", "string.special.url"]
5
+
6
+ export function detectLinks(
7
+ chunks: TextChunk[],
8
+ context: { content: string; highlights: SimpleHighlight[] },
9
+ ): TextChunk[] {
10
+ const content = context.content
11
+ const highlights = context.highlights
12
+
13
+ const ranges: Array<{ start: number; end: number; url: string }> = []
14
+
15
+ for (let i = 0; i < highlights.length; i++) {
16
+ const [start, end, group] = highlights[i]
17
+ if (!URL_SCOPES.includes(group)) continue
18
+
19
+ const url = content.slice(start, end)
20
+ ranges.push({ start, end, url })
21
+
22
+ for (let j = i - 1; j >= 0; j--) {
23
+ const [labelStart, labelEnd, prev] = highlights[j]
24
+ if (prev === "markup.link.label") {
25
+ ranges.push({ start: labelStart, end: labelEnd, url })
26
+ break
27
+ }
28
+ if (!prev.startsWith("markup.link")) break
29
+ }
30
+ }
31
+
32
+ if (ranges.length === 0) return chunks
33
+
34
+ // Use content.indexOf to find each chunk's position in the original content.
35
+ // This handles concealed text correctly because concealed chunks are either
36
+ // empty (length 0, skipped) or single-char replacements (length 1, skipped).
37
+ // Non-concealed chunks with length > 1 are exact substrings of content in order.
38
+ let contentPos = 0
39
+ for (const chunk of chunks) {
40
+ if (chunk.text.length <= 1) continue
41
+
42
+ const idx = content.indexOf(chunk.text, contentPos)
43
+ if (idx < 0) continue
44
+
45
+ for (const range of ranges) {
46
+ if (idx < range.end && idx + chunk.text.length > range.start) {
47
+ chunk.link = { url: range.url }
48
+ break
49
+ }
50
+ }
51
+
52
+ contentPos = idx + chunk.text.length
53
+ }
54
+
55
+ return chunks
56
+ }
@@ -0,0 +1,228 @@
1
+ import { describe, test, expect, beforeEach, afterEach } from "bun:test"
2
+ import { envRegistry, registerEnvVar, env, clearEnvCache } from "./env.ts"
3
+
4
+ // Backup and restore registry to avoid interfering with module-level registrations
5
+ let registryBackup: Record<string, any> = {}
6
+
7
+ beforeEach(() => {
8
+ registryBackup = { ...envRegistry }
9
+
10
+ clearEnvCache()
11
+
12
+ Object.keys(process.env).forEach((key) => {
13
+ if (key.startsWith("TEST_")) {
14
+ delete process.env[key]
15
+ }
16
+ })
17
+ })
18
+
19
+ afterEach(() => {
20
+ Object.keys(envRegistry).forEach((key) => {
21
+ if (key.startsWith("TEST_") && !(key in registryBackup)) {
22
+ delete envRegistry[key]
23
+ }
24
+ })
25
+
26
+ Object.keys(process.env).forEach((key) => {
27
+ if (key.startsWith("TEST_")) {
28
+ delete process.env[key]
29
+ }
30
+ })
31
+ })
32
+
33
+ describe("env registry", () => {
34
+ test("should register and access string env vars", () => {
35
+ registerEnvVar({
36
+ name: "TEST_STRING",
37
+ description: "A test string variable",
38
+ type: "string",
39
+ default: "default_value",
40
+ })
41
+
42
+ // Set env var
43
+ process.env.TEST_STRING = "test_value"
44
+
45
+ expect(env.TEST_STRING).toBe("test_value")
46
+ })
47
+
48
+ test("should handle boolean env vars with various true values", () => {
49
+ registerEnvVar({
50
+ name: "TEST_BOOL_TRUE",
51
+ description: "A test boolean variable",
52
+ type: "boolean",
53
+ })
54
+
55
+ // Test various true values
56
+ process.env.TEST_BOOL_TRUE = "true"
57
+ expect(env.TEST_BOOL_TRUE).toBe(true)
58
+
59
+ process.env.TEST_BOOL_TRUE = "1"
60
+ expect(env.TEST_BOOL_TRUE).toBe(true)
61
+
62
+ process.env.TEST_BOOL_TRUE = "on"
63
+ expect(env.TEST_BOOL_TRUE).toBe(true)
64
+
65
+ process.env.TEST_BOOL_TRUE = "yes"
66
+ expect(env.TEST_BOOL_TRUE).toBe(true)
67
+ })
68
+
69
+ test("should handle boolean env vars with various false values", () => {
70
+ registerEnvVar({
71
+ name: "TEST_BOOL_FALSE",
72
+ description: "A test boolean variable",
73
+ type: "boolean",
74
+ })
75
+
76
+ // Test various false values
77
+ process.env.TEST_BOOL_FALSE = "false"
78
+ expect(env.TEST_BOOL_FALSE).toBe(false)
79
+
80
+ process.env.TEST_BOOL_FALSE = "0"
81
+ expect(env.TEST_BOOL_FALSE).toBe(false)
82
+
83
+ process.env.TEST_BOOL_FALSE = "off"
84
+ expect(env.TEST_BOOL_FALSE).toBe(false)
85
+ })
86
+
87
+ test("should handle number env vars", () => {
88
+ registerEnvVar({
89
+ name: "TEST_NUMBER",
90
+ description: "A test number variable",
91
+ type: "number",
92
+ })
93
+
94
+ process.env.TEST_NUMBER = "42"
95
+ expect(env.TEST_NUMBER).toBe(42)
96
+ })
97
+
98
+ test("should throw error for invalid number", () => {
99
+ registerEnvVar({
100
+ name: "TEST_INVALID_NUMBER",
101
+ description: "A test number variable",
102
+ type: "number",
103
+ })
104
+
105
+ process.env.TEST_INVALID_NUMBER = "not_a_number"
106
+
107
+ expect(() => env.TEST_INVALID_NUMBER).toThrow("must be a valid number")
108
+ })
109
+
110
+ test("should use default values when env var not set", () => {
111
+ registerEnvVar({
112
+ name: "TEST_DEFAULT",
113
+ description: "A test variable with default",
114
+ type: "string",
115
+ default: "default_value",
116
+ })
117
+
118
+ // Don't set the env var
119
+ expect(env.TEST_DEFAULT).toBe("default_value")
120
+ })
121
+
122
+ test("should throw error for required env var not set", () => {
123
+ registerEnvVar({
124
+ name: "TEST_REQUIRED",
125
+ description: "A required test variable",
126
+ })
127
+
128
+ expect(() => env.TEST_REQUIRED).toThrow("Required environment variable TEST_REQUIRED is not set")
129
+ })
130
+
131
+ test("should throw error for unregistered env var", () => {
132
+ expect(() => env.UNREGISTERED_VAR).toThrow("Environment variable UNREGISTERED_VAR is not registered")
133
+ })
134
+
135
+ test("should support proxy enumeration", () => {
136
+ registerEnvVar({
137
+ name: "TEST_ENUM_1",
138
+ description: "First test var",
139
+ default: "value1",
140
+ })
141
+
142
+ registerEnvVar({
143
+ name: "TEST_ENUM_2",
144
+ description: "Second test var",
145
+ default: "value2",
146
+ })
147
+
148
+ const keys = Object.keys(env)
149
+ expect(keys).toContain("TEST_ENUM_1")
150
+ expect(keys).toContain("TEST_ENUM_2")
151
+ })
152
+
153
+ test("should support 'in' operator", () => {
154
+ registerEnvVar({
155
+ name: "TEST_IN_OPERATOR",
156
+ description: "Test for 'in' operator",
157
+ default: "test",
158
+ })
159
+
160
+ expect("TEST_IN_OPERATOR" in env).toBe(true)
161
+ expect("NON_EXISTENT" in env).toBe(false)
162
+ })
163
+
164
+ test("should allow re-registering identical configuration", () => {
165
+ const config = {
166
+ name: "TEST_IDENTICAL",
167
+ description: "Test for identical re-registration",
168
+ type: "boolean" as const,
169
+ default: false,
170
+ }
171
+
172
+ registerEnvVar(config)
173
+ // Should not throw
174
+ registerEnvVar(config)
175
+
176
+ expect("TEST_IDENTICAL" in env).toBe(true)
177
+ })
178
+
179
+ test("should throw when re-registering with different type", () => {
180
+ registerEnvVar({
181
+ name: "TEST_DIFFERENT_TYPE",
182
+ description: "Test for different type",
183
+ type: "string",
184
+ })
185
+
186
+ expect(() => {
187
+ registerEnvVar({
188
+ name: "TEST_DIFFERENT_TYPE",
189
+ description: "Test for different type",
190
+ type: "boolean",
191
+ })
192
+ }).toThrow("already registered with different configuration")
193
+ })
194
+
195
+ test("should throw when re-registering with different default", () => {
196
+ registerEnvVar({
197
+ name: "TEST_DIFFERENT_DEFAULT",
198
+ description: "Test for different default",
199
+ type: "string",
200
+ default: "first",
201
+ })
202
+
203
+ expect(() => {
204
+ registerEnvVar({
205
+ name: "TEST_DIFFERENT_DEFAULT",
206
+ description: "Test for different default",
207
+ type: "string",
208
+ default: "second",
209
+ })
210
+ }).toThrow("already registered with different configuration")
211
+ })
212
+
213
+ test("should throw when re-registering with different description", () => {
214
+ registerEnvVar({
215
+ name: "TEST_DIFFERENT_DESC",
216
+ description: "First description",
217
+ type: "string",
218
+ })
219
+
220
+ expect(() => {
221
+ registerEnvVar({
222
+ name: "TEST_DIFFERENT_DESC",
223
+ description: "Second description",
224
+ type: "string",
225
+ })
226
+ }).toThrow("already registered with different configuration")
227
+ })
228
+ })
package/src/lib/env.ts ADDED
@@ -0,0 +1,209 @@
1
+ import { singleton } from "./singleton.js"
2
+
3
+ /**
4
+ * Environment variable registry
5
+ *
6
+ * Usage:
7
+ * ```ts
8
+ * import { registerEnvVar, env } from "./lib/env.ts";
9
+ *
10
+ * // Register environment variables
11
+ * registerEnvVar({
12
+ * name: "DEBUG",
13
+ * description: "Enable debug logging",
14
+ * type: "boolean",
15
+ * default: false
16
+ * });
17
+ *
18
+ * registerEnvVar({
19
+ * name: "PORT",
20
+ * description: "Server port number",
21
+ * type: "number",
22
+ * default: 3000
23
+ * });
24
+ *
25
+ * // Access environment variables
26
+ * if (env.DEBUG) {
27
+ * console.log("Debug mode enabled");
28
+ * }
29
+ *
30
+ * const port = env.PORT; // number
31
+ * ```
32
+ */
33
+
34
+ export interface EnvVarConfig {
35
+ name: string
36
+ description: string
37
+ default?: string | boolean | number
38
+ type?: "string" | "boolean" | "number"
39
+ }
40
+
41
+ export const envRegistry: Record<string, EnvVarConfig> = singleton("env-registry", () => ({}))
42
+
43
+ export function registerEnvVar(config: EnvVarConfig): void {
44
+ const existing = envRegistry[config.name]
45
+ if (existing) {
46
+ if (
47
+ existing.description !== config.description ||
48
+ existing.type !== config.type ||
49
+ existing.default !== config.default
50
+ ) {
51
+ throw new Error(
52
+ `Environment variable "${config.name}" is already registered with different configuration. ` +
53
+ `Existing: ${JSON.stringify(existing)}, New: ${JSON.stringify(config)}`,
54
+ )
55
+ }
56
+ return
57
+ }
58
+ envRegistry[config.name] = config
59
+ }
60
+
61
+ function normalizeBoolean(value: string): boolean {
62
+ const lowerValue = value.toLowerCase()
63
+ return ["true", "1", "on", "yes"].includes(lowerValue)
64
+ }
65
+
66
+ function parseEnvValue(config: EnvVarConfig): string | boolean | number {
67
+ const envValue = process.env[config.name]
68
+
69
+ if (envValue === undefined && config.default !== undefined) {
70
+ return config.default
71
+ }
72
+
73
+ if (envValue === undefined) {
74
+ throw new Error(`Required environment variable ${config.name} is not set. ${config.description}`)
75
+ }
76
+
77
+ switch (config.type) {
78
+ case "boolean":
79
+ return typeof envValue === "boolean" ? envValue : normalizeBoolean(envValue)
80
+ case "number":
81
+ const numValue = Number(envValue)
82
+ if (isNaN(numValue)) {
83
+ throw new Error(`Environment variable ${config.name} must be a valid number, got: ${envValue}`)
84
+ }
85
+ return numValue
86
+ case "string":
87
+ default:
88
+ return envValue
89
+ }
90
+ }
91
+
92
+ class EnvStore {
93
+ private parsedValues: Map<string, string | boolean | number> = new Map()
94
+
95
+ get(key: string): any {
96
+ if (this.parsedValues.has(key)) {
97
+ return this.parsedValues.get(key)!
98
+ }
99
+
100
+ if (!(key in envRegistry)) {
101
+ throw new Error(`Environment variable ${key} is not registered.`)
102
+ }
103
+
104
+ try {
105
+ const value = parseEnvValue(envRegistry[key])
106
+ this.parsedValues.set(key, value)
107
+ return value
108
+ } catch (error) {
109
+ throw new Error(`Failed to parse env var ${key}: ${error instanceof Error ? error.message : String(error)}`)
110
+ }
111
+ }
112
+
113
+ has(key: string): boolean {
114
+ return key in envRegistry
115
+ }
116
+
117
+ clearCache(): void {
118
+ this.parsedValues.clear()
119
+ }
120
+ }
121
+
122
+ const envStore = singleton("env-store", () => new EnvStore())
123
+
124
+ export function clearEnvCache(): void {
125
+ envStore.clearCache()
126
+ }
127
+
128
+ export function generateEnvMarkdown(): string {
129
+ const configs = Object.values(envRegistry)
130
+
131
+ if (configs.length === 0) {
132
+ return "# Environment Variables\n\nNo environment variables registered.\n"
133
+ }
134
+
135
+ let markdown = "# Environment Variables\n\n"
136
+
137
+ for (const config of configs) {
138
+ markdown += `## ${config.name}\n\n`
139
+ markdown += `${config.description}\n\n`
140
+
141
+ markdown += `**Type:** \`${config.type || "string"}\` \n`
142
+
143
+ if (config.default !== undefined) {
144
+ const defaultValue = typeof config.default === "string" ? `"${config.default}"` : String(config.default)
145
+ markdown += `**Default:** \`${defaultValue}\`\n`
146
+ } else {
147
+ markdown += "**Default:** *Required*\n"
148
+ }
149
+
150
+ markdown += "\n"
151
+ }
152
+
153
+ return markdown
154
+ }
155
+
156
+ export function generateEnvColored(): string {
157
+ const configs = Object.values(envRegistry)
158
+
159
+ if (configs.length === 0) {
160
+ return "\x1b[1;36mEnvironment Variables\x1b[0m\n\nNo environment variables registered.\n"
161
+ }
162
+
163
+ let output = "\x1b[1;36mEnvironment Variables\x1b[0m\n\n"
164
+
165
+ for (const config of configs) {
166
+ output += `\x1b[1;33m${config.name}\x1b[0m\n`
167
+ output += `${config.description}\n`
168
+ output += `\x1b[32mType:\x1b[0m \x1b[36m${config.type || "string"}\x1b[0m\n`
169
+
170
+ if (config.default !== undefined) {
171
+ const defaultValue = typeof config.default === "string" ? `"${config.default}"` : String(config.default)
172
+ output += `\x1b[32mDefault:\x1b[0m \x1b[35m${defaultValue}\x1b[0m\n`
173
+ } else {
174
+ output += `\x1b[32mDefault:\x1b[0m \x1b[31mRequired\x1b[0m\n`
175
+ }
176
+
177
+ output += "\n"
178
+ }
179
+
180
+ return output
181
+ }
182
+
183
+ export const env = new Proxy({} as Record<string, any>, {
184
+ get(target, prop: string) {
185
+ if (typeof prop !== "string") {
186
+ return undefined
187
+ }
188
+ return envStore.get(prop)
189
+ },
190
+
191
+ has(target, prop: string) {
192
+ return envStore.has(prop)
193
+ },
194
+
195
+ ownKeys() {
196
+ return Object.keys(envRegistry)
197
+ },
198
+
199
+ getOwnPropertyDescriptor(target, prop: string) {
200
+ if (envStore.has(prop)) {
201
+ return {
202
+ enumerable: true,
203
+ configurable: true,
204
+ get: () => envStore.get(prop),
205
+ }
206
+ }
207
+ return undefined
208
+ },
209
+ })
@@ -0,0 +1,51 @@
1
+ import type { Extmark } from "./extmarks.js"
2
+
3
+ export interface ExtmarksSnapshot {
4
+ extmarks: Map<number, Extmark>
5
+ nextId: number
6
+ }
7
+
8
+ export class ExtmarksHistory {
9
+ private undoStack: ExtmarksSnapshot[] = []
10
+ private redoStack: ExtmarksSnapshot[] = []
11
+
12
+ saveSnapshot(extmarks: Map<number, Extmark>, nextId: number): void {
13
+ const snapshot: ExtmarksSnapshot = {
14
+ extmarks: new Map(Array.from(extmarks.entries()).map(([id, extmark]) => [id, { ...extmark }])),
15
+ nextId,
16
+ }
17
+ this.undoStack.push(snapshot)
18
+ this.redoStack = []
19
+ }
20
+
21
+ undo(): ExtmarksSnapshot | null {
22
+ if (this.undoStack.length === 0) return null
23
+ return this.undoStack.pop()!
24
+ }
25
+
26
+ redo(): ExtmarksSnapshot | null {
27
+ if (this.redoStack.length === 0) return null
28
+ return this.redoStack.pop()!
29
+ }
30
+
31
+ pushRedo(snapshot: ExtmarksSnapshot): void {
32
+ this.redoStack.push(snapshot)
33
+ }
34
+
35
+ pushUndo(snapshot: ExtmarksSnapshot): void {
36
+ this.undoStack.push(snapshot)
37
+ }
38
+
39
+ clear(): void {
40
+ this.undoStack = []
41
+ this.redoStack = []
42
+ }
43
+
44
+ canUndo(): boolean {
45
+ return this.undoStack.length > 0
46
+ }
47
+
48
+ canRedo(): boolean {
49
+ return this.redoStack.length > 0
50
+ }
51
+ }