@xincli/opentui-core 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (476) hide show
  1. package/README.md +63 -0
  2. package/dev/keypress-debug-renderer.ts +148 -0
  3. package/dev/keypress-debug.ts +43 -0
  4. package/dev/print-env-vars.ts +32 -0
  5. package/dev/test-tmux-graphics-334.sh +68 -0
  6. package/dev/test-tmux-theme-queries.sh +151 -0
  7. package/dev/thai-debug-test.ts +68 -0
  8. package/dev/theme-mode.ts +290 -0
  9. package/docs/development.md +144 -0
  10. package/package.json +102 -0
  11. package/prebuilt/aarch64-android/libopentui.so +0 -0
  12. package/scripts/build-android.ts +226 -0
  13. package/scripts/build-native-termux.sh +525 -0
  14. package/scripts/build.ts +530 -0
  15. package/scripts/dist-test.ts +312 -0
  16. package/scripts/package-prebuilt.ts +110 -0
  17. package/scripts/publish.ts +60 -0
  18. package/scripts/test-node-hook.mjs +16 -0
  19. package/scripts/test-node.ts +241 -0
  20. package/scripts/vendor-deps.sh +73 -0
  21. package/src/NativeSpanFeed.ts +375 -0
  22. package/src/Renderable.ts +1878 -0
  23. package/src/__snapshots__/buffer.test.ts.snap +28 -0
  24. package/src/animation/Timeline.test.ts +2709 -0
  25. package/src/animation/Timeline.ts +598 -0
  26. package/src/ansi.ts +22 -0
  27. package/src/audio.ts +479 -0
  28. package/src/benchmark/attenuation-benchmark.ts +81 -0
  29. package/src/benchmark/audio-playback-benchmark.ts +344 -0
  30. package/src/benchmark/box-draw-benchmark.ts +1042 -0
  31. package/src/benchmark/colormatrix-benchmark.ts +123 -0
  32. package/src/benchmark/gain-benchmark.ts +80 -0
  33. package/src/benchmark/latest-all-bench-run.json +707 -0
  34. package/src/benchmark/latest-async-bench-run.json +336 -0
  35. package/src/benchmark/latest-default-bench-run.json +657 -0
  36. package/src/benchmark/latest-large-bench-run.json +707 -0
  37. package/src/benchmark/latest-quick-bench-run.json +207 -0
  38. package/src/benchmark/layout-benchmark.ts +2547 -0
  39. package/src/benchmark/markdown-benchmark.ts +1796 -0
  40. package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
  41. package/src/benchmark/native-span-feed-benchmark.md +56 -0
  42. package/src/benchmark/native-span-feed-benchmark.ts +596 -0
  43. package/src/benchmark/native-span-feed-compare.ts +280 -0
  44. package/src/benchmark/render-traversal-benchmark.ts +928 -0
  45. package/src/benchmark/text-buffer-render-benchmark.ts +874 -0
  46. package/src/benchmark/text-table-benchmark.ts +948 -0
  47. package/src/buffer.test.ts +292 -0
  48. package/src/buffer.ts +564 -0
  49. package/src/console.test.ts +629 -0
  50. package/src/console.ts +1253 -0
  51. package/src/edit-buffer.test.ts +1852 -0
  52. package/src/edit-buffer.ts +417 -0
  53. package/src/editor-view.test.ts +1056 -0
  54. package/src/editor-view.ts +290 -0
  55. package/src/index.ts +25 -0
  56. package/src/lib/KeyHandler.integration.test.ts +292 -0
  57. package/src/lib/KeyHandler.stopPropagation.test.ts +289 -0
  58. package/src/lib/KeyHandler.test.ts +662 -0
  59. package/src/lib/KeyHandler.ts +222 -0
  60. package/src/lib/RGBA.test.ts +60 -0
  61. package/src/lib/RGBA.ts +343 -0
  62. package/src/lib/ascii.font.ts +330 -0
  63. package/src/lib/border.test.ts +83 -0
  64. package/src/lib/border.ts +170 -0
  65. package/src/lib/bunfs.test.ts +27 -0
  66. package/src/lib/bunfs.ts +18 -0
  67. package/src/lib/clipboard.test.ts +63 -0
  68. package/src/lib/clipboard.ts +41 -0
  69. package/src/lib/clock.ts +35 -0
  70. package/src/lib/data-paths.test.ts +133 -0
  71. package/src/lib/data-paths.ts +109 -0
  72. package/src/lib/debounce.ts +106 -0
  73. package/src/lib/detect-links.test.ts +98 -0
  74. package/src/lib/detect-links.ts +56 -0
  75. package/src/lib/env.test.ts +228 -0
  76. package/src/lib/env.ts +209 -0
  77. package/src/lib/extmarks-history.ts +51 -0
  78. package/src/lib/extmarks-multiwidth.test.ts +324 -0
  79. package/src/lib/extmarks.test.ts +3547 -0
  80. package/src/lib/extmarks.ts +861 -0
  81. package/src/lib/fonts/block.json +405 -0
  82. package/src/lib/fonts/grid.json +265 -0
  83. package/src/lib/fonts/huge.json +741 -0
  84. package/src/lib/fonts/pallet.json +314 -0
  85. package/src/lib/fonts/shade.json +591 -0
  86. package/src/lib/fonts/slick.json +321 -0
  87. package/src/lib/fonts/tiny.json +69 -0
  88. package/src/lib/hast-styled-text.ts +59 -0
  89. package/src/lib/index.ts +22 -0
  90. package/src/lib/keybinding.internal.test.ts +342 -0
  91. package/src/lib/keybinding.internal.ts +182 -0
  92. package/src/lib/objects-in-viewport.test.ts +789 -0
  93. package/src/lib/objects-in-viewport.ts +153 -0
  94. package/src/lib/output.capture.ts +58 -0
  95. package/src/lib/parse.keypress-kitty.protocol.test.ts +347 -0
  96. package/src/lib/parse.keypress-kitty.test.ts +712 -0
  97. package/src/lib/parse.keypress-kitty.ts +470 -0
  98. package/src/lib/parse.keypress.test.ts +2020 -0
  99. package/src/lib/parse.keypress.ts +480 -0
  100. package/src/lib/parse.mouse.test.ts +552 -0
  101. package/src/lib/parse.mouse.ts +232 -0
  102. package/src/lib/paste.ts +18 -0
  103. package/src/lib/queue.ts +65 -0
  104. package/src/lib/render-geometry.ts +36 -0
  105. package/src/lib/renderable.validations.test.ts +87 -0
  106. package/src/lib/renderable.validations.ts +83 -0
  107. package/src/lib/scroll-acceleration.ts +98 -0
  108. package/src/lib/selection.ts +261 -0
  109. package/src/lib/singleton.ts +34 -0
  110. package/src/lib/stdin-parser.test.ts +2439 -0
  111. package/src/lib/stdin-parser.ts +2007 -0
  112. package/src/lib/styled-text.ts +178 -0
  113. package/src/lib/terminal-capability-detection.test.ts +226 -0
  114. package/src/lib/terminal-capability-detection.ts +98 -0
  115. package/src/lib/terminal-palette.test.ts +954 -0
  116. package/src/lib/terminal-palette.ts +441 -0
  117. package/src/lib/tree-sitter/assets/README.md +119 -0
  118. package/src/lib/tree-sitter/assets/javascript/highlights.scm +205 -0
  119. package/src/lib/tree-sitter/assets/javascript/tree-sitter-javascript.wasm +0 -0
  120. package/src/lib/tree-sitter/assets/markdown/highlights.scm +150 -0
  121. package/src/lib/tree-sitter/assets/markdown/injections.scm +27 -0
  122. package/src/lib/tree-sitter/assets/markdown/tree-sitter-markdown.wasm +0 -0
  123. package/src/lib/tree-sitter/assets/markdown_inline/highlights.scm +115 -0
  124. package/src/lib/tree-sitter/assets/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  125. package/src/lib/tree-sitter/assets/typescript/highlights.scm +604 -0
  126. package/src/lib/tree-sitter/assets/typescript/tree-sitter-typescript.wasm +0 -0
  127. package/src/lib/tree-sitter/assets/update.ts +360 -0
  128. package/src/lib/tree-sitter/assets/zig/highlights.scm +284 -0
  129. package/src/lib/tree-sitter/assets/zig/tree-sitter-zig.wasm +0 -0
  130. package/src/lib/tree-sitter/assets.d.ts +9 -0
  131. package/src/lib/tree-sitter/cache.test.ts +291 -0
  132. package/src/lib/tree-sitter/client.test.ts +1434 -0
  133. package/src/lib/tree-sitter/client.ts +847 -0
  134. package/src/lib/tree-sitter/default-parsers.ts +133 -0
  135. package/src/lib/tree-sitter/download-utils.ts +148 -0
  136. package/src/lib/tree-sitter/index.ts +75 -0
  137. package/src/lib/tree-sitter/parser.worker.ts +1098 -0
  138. package/src/lib/tree-sitter/parsers-config.ts +81 -0
  139. package/src/lib/tree-sitter/resolve-ft.test.ts +55 -0
  140. package/src/lib/tree-sitter/resolve-ft.ts +189 -0
  141. package/src/lib/tree-sitter/types.ts +132 -0
  142. package/src/lib/tree-sitter/update-assets.ts +10 -0
  143. package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
  144. package/src/lib/tree-sitter-styled-text.ts +314 -0
  145. package/src/lib/validate-dir-name.ts +55 -0
  146. package/src/lib/yoga.options.test.ts +628 -0
  147. package/src/lib/yoga.options.ts +346 -0
  148. package/src/native-event-worker-repro.test.ts +48 -0
  149. package/src/native-event-worker-repro.worker.ts +9 -0
  150. package/src/native-handle.test.ts +221 -0
  151. package/src/platform/ffi.test.ts +516 -0
  152. package/src/platform/ffi.ts +653 -0
  153. package/src/platform/runtime.test.ts +52 -0
  154. package/src/platform/runtime.ts +121 -0
  155. package/src/platform/test.ts +45 -0
  156. package/src/platform/worker-handler-cleanup.fixture.ts +12 -0
  157. package/src/platform/worker-onmessage-startup.fixture.ts +10 -0
  158. package/src/platform/worker-startup.fixture.ts +9 -0
  159. package/src/platform/worker.node-test.ts +153 -0
  160. package/src/platform/worker.ts +425 -0
  161. package/src/plugins/core-slot.ts +579 -0
  162. package/src/plugins/registry.ts +402 -0
  163. package/src/plugins/types.ts +46 -0
  164. package/src/post/effects.ts +948 -0
  165. package/src/post/filters.ts +512 -0
  166. package/src/post/matrices.ts +288 -0
  167. package/src/renderables/ASCIIFont.ts +219 -0
  168. package/src/renderables/Box.test.ts +474 -0
  169. package/src/renderables/Box.ts +353 -0
  170. package/src/renderables/Code.test.ts +2388 -0
  171. package/src/renderables/Code.ts +555 -0
  172. package/src/renderables/Diff.regression.test.ts +381 -0
  173. package/src/renderables/Diff.test.ts +3212 -0
  174. package/src/renderables/Diff.ts +1278 -0
  175. package/src/renderables/EditBufferRenderable.test.ts +288 -0
  176. package/src/renderables/EditBufferRenderable.ts +1152 -0
  177. package/src/renderables/FrameBuffer.ts +47 -0
  178. package/src/renderables/Input.test.ts +1310 -0
  179. package/src/renderables/Input.ts +273 -0
  180. package/src/renderables/LineNumberRenderable.ts +725 -0
  181. package/src/renderables/Markdown.ts +2144 -0
  182. package/src/renderables/ScrollBar.ts +423 -0
  183. package/src/renderables/ScrollBox.ts +903 -0
  184. package/src/renderables/Select.test.ts +1134 -0
  185. package/src/renderables/Select.ts +535 -0
  186. package/src/renderables/Slider.test.ts +456 -0
  187. package/src/renderables/Slider.ts +342 -0
  188. package/src/renderables/TabSelect.test.ts +238 -0
  189. package/src/renderables/TabSelect.ts +447 -0
  190. package/src/renderables/Text.selection-buffer.test.ts +118 -0
  191. package/src/renderables/Text.test.ts +2662 -0
  192. package/src/renderables/Text.ts +147 -0
  193. package/src/renderables/TextBufferRenderable.ts +504 -0
  194. package/src/renderables/TextNode.test.ts +1137 -0
  195. package/src/renderables/TextNode.ts +379 -0
  196. package/src/renderables/TextTable.test.ts +1411 -0
  197. package/src/renderables/TextTable.ts +1434 -0
  198. package/src/renderables/Textarea.ts +425 -0
  199. package/src/renderables/TimeToFirstDraw.ts +89 -0
  200. package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
  201. package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
  202. package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
  203. package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
  204. package/src/renderables/__tests__/Code.test.ts +55 -0
  205. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
  206. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +827 -0
  207. package/src/renderables/__tests__/LineNumberRenderable.test.ts +1906 -0
  208. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
  209. package/src/renderables/__tests__/Markdown.code-colors.test.ts +288 -0
  210. package/src/renderables/__tests__/Markdown.test.ts +4175 -0
  211. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
  212. package/src/renderables/__tests__/Textarea.buffer.test.ts +683 -0
  213. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
  214. package/src/renderables/__tests__/Textarea.editing.test.ts +2120 -0
  215. package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
  216. package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
  217. package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
  218. package/src/renderables/__tests__/Textarea.keybinding.test.ts +3275 -0
  219. package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
  220. package/src/renderables/__tests__/Textarea.rendering.test.ts +1927 -0
  221. package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
  222. package/src/renderables/__tests__/Textarea.selection.test.ts +1589 -0
  223. package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
  224. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
  225. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
  226. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
  227. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
  228. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
  229. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
  230. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
  231. package/src/renderables/__tests__/markdown-parser.test.ts +241 -0
  232. package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
  233. package/src/renderables/composition/README.md +8 -0
  234. package/src/renderables/composition/VRenderable.ts +32 -0
  235. package/src/renderables/composition/constructs.ts +127 -0
  236. package/src/renderables/composition/vnode.ts +277 -0
  237. package/src/renderables/index.ts +23 -0
  238. package/src/renderables/markdown-parser.ts +79 -0
  239. package/src/renderer-theme-mode.ts +199 -0
  240. package/src/renderer.ts +4975 -0
  241. package/src/runtime-plugin-support-configure.ts +63 -0
  242. package/src/runtime-plugin-support.ts +13 -0
  243. package/src/runtime-plugin.ts +626 -0
  244. package/src/specs/terminal-startup.md +64 -0
  245. package/src/syntax-style.test.ts +841 -0
  246. package/src/syntax-style.ts +274 -0
  247. package/src/testing/README.md +219 -0
  248. package/src/testing/bun-test-node.ts +880 -0
  249. package/src/testing/capture-spans.test.ts +216 -0
  250. package/src/testing/integration.test.ts +276 -0
  251. package/src/testing/manual-clock.ts +117 -0
  252. package/src/testing/mock-keys.test.ts +1378 -0
  253. package/src/testing/mock-keys.ts +457 -0
  254. package/src/testing/mock-mouse.test.ts +218 -0
  255. package/src/testing/mock-mouse.ts +247 -0
  256. package/src/testing/mock-tree-sitter-client.ts +81 -0
  257. package/src/testing/spy.ts +13 -0
  258. package/src/testing/terminal-capabilities.ts +47 -0
  259. package/src/testing/test-recorder.test.ts +410 -0
  260. package/src/testing/test-recorder.ts +133 -0
  261. package/src/testing/test-renderer.ts +375 -0
  262. package/src/testing/test-renderer.wait.test.ts +278 -0
  263. package/src/testing/test-streams.ts +31 -0
  264. package/src/testing.ts +9 -0
  265. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
  266. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
  267. package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
  268. package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
  269. package/src/tests/allocator-stats.test.ts +53 -0
  270. package/src/tests/audio.test.ts +303 -0
  271. package/src/tests/destroy-during-render.test.ts +200 -0
  272. package/src/tests/destroy-on-exit.fixture.ts +36 -0
  273. package/src/tests/destroy-on-exit.test.ts +62 -0
  274. package/src/tests/ffi-borrowed-pointer-callsites.test.ts +153 -0
  275. package/src/tests/hover-cursor.test.ts +98 -0
  276. package/src/tests/native-backed-measurement-lifecycle.test.ts +133 -0
  277. package/src/tests/native-backed-measurement-parity.test.ts +322 -0
  278. package/src/tests/native-span-feed-async.test.ts +173 -0
  279. package/src/tests/native-span-feed-close.test.ts +120 -0
  280. package/src/tests/native-span-feed-coverage.test.ts +227 -0
  281. package/src/tests/native-span-feed-edge-cases.test.ts +384 -0
  282. package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
  283. package/src/tests/opacity.test.ts +123 -0
  284. package/src/tests/renderable.snapshot.test.ts +524 -0
  285. package/src/tests/renderable.test.ts +1851 -0
  286. package/src/tests/renderer.clock.test.ts +270 -0
  287. package/src/tests/renderer.console-startup.test.ts +2151 -0
  288. package/src/tests/renderer.control.test.ts +458 -0
  289. package/src/tests/renderer.core-slot-binding.test.ts +962 -0
  290. package/src/tests/renderer.cursor.test.ts +26 -0
  291. package/src/tests/renderer.custom-stdout.test.ts +1112 -0
  292. package/src/tests/renderer.destroy-during-render.test.ts +147 -0
  293. package/src/tests/renderer.focus-restore.test.ts +257 -0
  294. package/src/tests/renderer.focus.test.ts +329 -0
  295. package/src/tests/renderer.idle.test.ts +219 -0
  296. package/src/tests/renderer.input.test.ts +2615 -0
  297. package/src/tests/renderer.kitty-flags.test.ts +195 -0
  298. package/src/tests/renderer.lifecycle.test.ts +34 -0
  299. package/src/tests/renderer.mouse.test.ts +1315 -0
  300. package/src/tests/renderer.notifications.test.ts +27 -0
  301. package/src/tests/renderer.palette.test.ts +1199 -0
  302. package/src/tests/renderer.remote.test.ts +247 -0
  303. package/src/tests/renderer.render-stats.test.ts +146 -0
  304. package/src/tests/renderer.scrollback-surface.test.ts +474 -0
  305. package/src/tests/renderer.selection.test.ts +138 -0
  306. package/src/tests/renderer.slot-registry.test.ts +684 -0
  307. package/src/tests/renderer.tracker.test.ts +202 -0
  308. package/src/tests/renderer.useMouse.test.ts +83 -0
  309. package/src/tests/runtime-plugin-node-modules-cycle.fixture.ts +76 -0
  310. package/src/tests/runtime-plugin-node-modules-import-like-string.fixture.ts +48 -0
  311. package/src/tests/runtime-plugin-node-modules-mjs.fixture.ts +43 -0
  312. package/src/tests/runtime-plugin-node-modules-no-bare-rewrite.fixture.ts +67 -0
  313. package/src/tests/runtime-plugin-node-modules-package-type-cache.fixture.ts +72 -0
  314. package/src/tests/runtime-plugin-node-modules-runtime-specifier.fixture.ts +44 -0
  315. package/src/tests/runtime-plugin-node-modules-scoped-package-bare-rewrite.fixture.ts +85 -0
  316. package/src/tests/runtime-plugin-path-alias.fixture.ts +43 -0
  317. package/src/tests/runtime-plugin-resolve-roots.fixture.ts +65 -0
  318. package/src/tests/runtime-plugin-support-configure.fixture.ts +31 -0
  319. package/src/tests/runtime-plugin-support-late-addition.fixture.ts +17 -0
  320. package/src/tests/runtime-plugin-support.fixture.ts +11 -0
  321. package/src/tests/runtime-plugin-support.test.ts +54 -0
  322. package/src/tests/runtime-plugin-windows-file-url.fixture.ts +30 -0
  323. package/src/tests/runtime-plugin.fixture.ts +40 -0
  324. package/src/tests/runtime-plugin.test.ts +369 -0
  325. package/src/tests/scrollbox-culling-bug.test.ts +114 -0
  326. package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
  327. package/src/tests/scrollbox-hitgrid.test.ts +909 -0
  328. package/src/tests/scrollbox.test.ts +1895 -0
  329. package/src/tests/wrap-resize-perf.test.ts +276 -0
  330. package/src/tests/yoga-api-coverage.test.ts +409 -0
  331. package/src/tests/yoga-callback-stress.test.ts +122 -0
  332. package/src/tests/yoga-ffi.test.ts +117 -0
  333. package/src/tests/yoga-setters.test.ts +921 -0
  334. package/src/tests/yoga-upstream/YGAlignBaselineTest.test.ts +124 -0
  335. package/src/tests/yoga-upstream/YGComputedBorderTest.test.ts +27 -0
  336. package/src/tests/yoga-upstream/YGComputedMarginTest.test.ts +27 -0
  337. package/src/tests/yoga-upstream/YGComputedPaddingTest.test.ts +27 -0
  338. package/src/tests/yoga-upstream/YGDirtiedTest.test.ts +157 -0
  339. package/src/tests/yoga-upstream/YGErrataTest.test.ts +40 -0
  340. package/src/tests/yoga-upstream/YGFlexBasisAuto.test.ts +23 -0
  341. package/src/tests/yoga-upstream/YGHasNewLayout.test.ts +81 -0
  342. package/src/tests/yoga-upstream/YGMeasureCacheTest.test.ts +31 -0
  343. package/src/tests/yoga-upstream/YGMeasureTest.test.ts +70 -0
  344. package/src/tests/yoga-upstream/generated/YGAbsolutePositionTest.test.ts +1864 -0
  345. package/src/tests/yoga-upstream/generated/YGAlignContentTest.test.ts +5829 -0
  346. package/src/tests/yoga-upstream/generated/YGAlignItemsTest.test.ts +2444 -0
  347. package/src/tests/yoga-upstream/generated/YGAlignSelfTest.test.ts +293 -0
  348. package/src/tests/yoga-upstream/generated/YGAndroidNewsFeed.test.ts +315 -0
  349. package/src/tests/yoga-upstream/generated/YGAspectRatioTest.test.ts +231 -0
  350. package/src/tests/yoga-upstream/generated/YGAutoTest.test.ts +347 -0
  351. package/src/tests/yoga-upstream/generated/YGBorderTest.test.ts +256 -0
  352. package/src/tests/yoga-upstream/generated/YGBoxSizingTest.test.ts +2747 -0
  353. package/src/tests/yoga-upstream/generated/YGDimensionTest.test.ts +129 -0
  354. package/src/tests/yoga-upstream/generated/YGDisplayContentsTest.test.ts +109 -0
  355. package/src/tests/yoga-upstream/generated/YGDisplayTest.test.ts +1097 -0
  356. package/src/tests/yoga-upstream/generated/YGFlexDirectionTest.test.ts +4562 -0
  357. package/src/tests/yoga-upstream/generated/YGFlexTest.test.ts +677 -0
  358. package/src/tests/yoga-upstream/generated/YGFlexWrapTest.test.ts +2071 -0
  359. package/src/tests/yoga-upstream/generated/YGGapTest.test.ts +3303 -0
  360. package/src/tests/yoga-upstream/generated/YGIntrinsicSizeTest.test.ts +582 -0
  361. package/src/tests/yoga-upstream/generated/YGJustifyContentTest.test.ts +2150 -0
  362. package/src/tests/yoga-upstream/generated/YGMarginTest.test.ts +1963 -0
  363. package/src/tests/yoga-upstream/generated/YGMinMaxDimensionTest.test.ts +1446 -0
  364. package/src/tests/yoga-upstream/generated/YGPaddingTest.test.ts +354 -0
  365. package/src/tests/yoga-upstream/generated/YGPercentageTest.test.ts +1760 -0
  366. package/src/tests/yoga-upstream/generated/YGRoundingTest.test.ts +1161 -0
  367. package/src/tests/yoga-upstream/generated/YGSizeOverflowTest.test.ts +207 -0
  368. package/src/tests/yoga-upstream/generated/YGStaticPositionTest.test.ts +6338 -0
  369. package/src/tests/yoga-upstream/tools/MeasureCounter.ts +54 -0
  370. package/src/tests/yoga-upstream/tools/utils.ts +81 -0
  371. package/src/text-buffer-view.test.ts +722 -0
  372. package/src/text-buffer-view.ts +193 -0
  373. package/src/text-buffer.test.ts +512 -0
  374. package/src/text-buffer.ts +250 -0
  375. package/src/types.ts +199 -0
  376. package/src/utils.ts +88 -0
  377. package/src/yoga.ts +1146 -0
  378. package/src/zig/ansi.zig +502 -0
  379. package/src/zig/audio.zig +1206 -0
  380. package/src/zig/bench/README.md +50 -0
  381. package/src/zig/bench/buffer-color-blending_bench.zig +350 -0
  382. package/src/zig/bench/buffer-draw-box_bench.zig +786 -0
  383. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +894 -0
  384. package/src/zig/bench/edit-buffer_bench.zig +476 -0
  385. package/src/zig/bench/editor-view_bench.zig +169 -0
  386. package/src/zig/bench/native-span-feed_bench.zig +107 -0
  387. package/src/zig/bench/rope-markers_bench.zig +713 -0
  388. package/src/zig/bench/rope_bench.zig +514 -0
  389. package/src/zig/bench/styled-text_bench.zig +476 -0
  390. package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
  391. package/src/zig/bench/text-buffer-view_bench.zig +459 -0
  392. package/src/zig/bench/text-chunk-graphemes_bench.zig +272 -0
  393. package/src/zig/bench/utf8_bench.zig +799 -0
  394. package/src/zig/bench-utils.zig +431 -0
  395. package/src/zig/bench.zig +223 -0
  396. package/src/zig/buffer-methods.zig +215 -0
  397. package/src/zig/buffer.zig +2515 -0
  398. package/src/zig/build.zig +700 -0
  399. package/src/zig/build.zig.zon +19 -0
  400. package/src/zig/edit-buffer.zig +900 -0
  401. package/src/zig/editor-view.zig +812 -0
  402. package/src/zig/event-bus.zig +28 -0
  403. package/src/zig/event-emitter.zig +65 -0
  404. package/src/zig/file-logger.zig +92 -0
  405. package/src/zig/grapheme.zig +838 -0
  406. package/src/zig/handles.zig +267 -0
  407. package/src/zig/lib.zig +2813 -0
  408. package/src/zig/link.zig +349 -0
  409. package/src/zig/logger.zig +43 -0
  410. package/src/zig/mem-registry.zig +126 -0
  411. package/src/zig/miniaudio_shim.c +21 -0
  412. package/src/zig/native-renderable.zig +112 -0
  413. package/src/zig/native-span-feed-bench-lib.zig +7 -0
  414. package/src/zig/native-span-feed.zig +747 -0
  415. package/src/zig/renderer-output.zig +677 -0
  416. package/src/zig/renderer.zig +2106 -0
  417. package/src/zig/rope.zig +1220 -0
  418. package/src/zig/split-scrollback.zig +88 -0
  419. package/src/zig/syntax-style.zig +174 -0
  420. package/src/zig/terminal.zig +1652 -0
  421. package/src/zig/test.zig +82 -0
  422. package/src/zig/tests/README.md +18 -0
  423. package/src/zig/tests/ansi_test.zig +18 -0
  424. package/src/zig/tests/audio_test.zig +439 -0
  425. package/src/zig/tests/buffer-methods_test.zig +1111 -0
  426. package/src/zig/tests/buffer_test.zig +2926 -0
  427. package/src/zig/tests/edit-buffer-history_test.zig +299 -0
  428. package/src/zig/tests/edit-buffer_test.zig +1688 -0
  429. package/src/zig/tests/editor-view_test.zig +3454 -0
  430. package/src/zig/tests/event-emitter_test.zig +249 -0
  431. package/src/zig/tests/grapheme_test.zig +1329 -0
  432. package/src/zig/tests/handles_test.zig +123 -0
  433. package/src/zig/tests/link_test.zig +220 -0
  434. package/src/zig/tests/mem-registry_test.zig +473 -0
  435. package/src/zig/tests/memory_leak_regression_test.zig +234 -0
  436. package/src/zig/tests/native-renderable_test.zig +16 -0
  437. package/src/zig/tests/native-span-feed_test.zig +1266 -0
  438. package/src/zig/tests/renderer_test.zig +2604 -0
  439. package/src/zig/tests/rope-nested_test.zig +712 -0
  440. package/src/zig/tests/rope_fuzz_test.zig +238 -0
  441. package/src/zig/tests/rope_test.zig +2362 -0
  442. package/src/zig/tests/segment-merge.test.zig +148 -0
  443. package/src/zig/tests/split-scrollback_test.zig +70 -0
  444. package/src/zig/tests/syntax-style_test.zig +558 -0
  445. package/src/zig/tests/terminal_test.zig +1489 -0
  446. package/src/zig/tests/test-renderer.zig +126 -0
  447. package/src/zig/tests/text-buffer-drawing_test.zig +3291 -0
  448. package/src/zig/tests/text-buffer-highlights_test.zig +706 -0
  449. package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
  450. package/src/zig/tests/text-buffer-segment_test.zig +320 -0
  451. package/src/zig/tests/text-buffer-selection_test.zig +1056 -0
  452. package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
  453. package/src/zig/tests/text-buffer-view_test.zig +3672 -0
  454. package/src/zig/tests/text-buffer_test.zig +2191 -0
  455. package/src/zig/tests/unicode-width-map.zon +3909 -0
  456. package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
  457. package/src/zig/tests/utf8_test.zig +4060 -0
  458. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
  459. package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
  460. package/src/zig/tests/word-wrap-editing_test.zig +498 -0
  461. package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
  462. package/src/zig/tests/yoga_test.zig +65 -0
  463. package/src/zig/text-buffer-iterators.zig +496 -0
  464. package/src/zig/text-buffer-segment.zig +403 -0
  465. package/src/zig/text-buffer-view.zig +1428 -0
  466. package/src/zig/text-buffer.zig +1272 -0
  467. package/src/zig/utf8.zig +1954 -0
  468. package/src/zig/utils.zig +12 -0
  469. package/src/zig/uucode-stub.zig +76 -0
  470. package/src/zig/vendor/miniaudio/miniaudio.h +93468 -0
  471. package/src/zig/yoga.zig +658 -0
  472. package/src/zig-structs.ts +381 -0
  473. package/src/zig.ts +5260 -0
  474. package/tsconfig.build.json +17 -0
  475. package/tsconfig.json +27 -0
  476. package/tsconfig.node-test.json +138 -0
@@ -0,0 +1,60 @@
1
+ import { TextareaRenderable } from "../Textarea.js"
2
+ import { type TestRenderer } from "../../testing/test-renderer.js"
3
+ import { type TextareaOptions } from "../Textarea.js"
4
+ import type { DiffRenderable } from "../Diff.js"
5
+ import type { CodeRenderable } from "../Code.js"
6
+ import type { MockTreeSitterClient } from "../../testing/mock-tree-sitter-client.js"
7
+ import type { ManualClock } from "../../testing/manual-clock.js"
8
+
9
+ export async function createTextareaRenderable(
10
+ renderer: TestRenderer,
11
+ renderOnce: () => Promise<void>,
12
+ options: TextareaOptions,
13
+ ): Promise<{ textarea: TextareaRenderable; root: any }> {
14
+ const textareaRenderable = new TextareaRenderable(renderer, { left: 0, top: 0, ...options })
15
+ renderer.root.add(textareaRenderable)
16
+ await renderOnce()
17
+
18
+ return { textarea: textareaRenderable, root: renderer.root }
19
+ }
20
+
21
+ // Settle Diff highlighting deterministically. Each iteration:
22
+ // 1. Render twice — the first render may trigger Diff.requestRebuild via microtask
23
+ // (runs during renderOnce's internal awaits), which calls requestRender while
24
+ // rendering=true, setting immediateRerenderRequested. The resulting re-render
25
+ // is scheduled via clock.setTimeout (ManualClock), so needs a second renderOnce.
26
+ // 2. Resolve all pending highlights (proper signal via mock)
27
+ // 3. Await Code.highlightingDone on both sides (proper signal from Code)
28
+ // Loop exits when mock has no more pending requests (state-based, not count-based).
29
+ export async function settleDiffHighlighting(
30
+ diff: DiffRenderable,
31
+ client: MockTreeSitterClient,
32
+ render: () => Promise<void>,
33
+ ) {
34
+ const MAX = 15
35
+ for (let i = 0; i < MAX; i++) {
36
+ await render()
37
+ await render()
38
+ if (!client.isHighlighting()) break
39
+ client.resolveAllHighlightOnce()
40
+ const left: CodeRenderable | null = (diff as any).leftCodeRenderable
41
+ const right: CodeRenderable | null = (diff as any).rightCodeRenderable
42
+ if (left) await left.highlightingDone
43
+ if (right) await right.highlightingDone
44
+ }
45
+ }
46
+
47
+ // Simulate the passage of time by advancing a ManualClock and rendering frames.
48
+ // Useful for testing animations, scroll momentum, and other time-dependent behavior.
49
+ export async function simulateFrames(
50
+ clock: ManualClock,
51
+ renderOnce: () => Promise<void>,
52
+ ms: number,
53
+ frameInterval: number = 50,
54
+ ): Promise<void> {
55
+ const frames = Math.ceil(ms / frameInterval)
56
+ for (let i = 0; i < frames; i++) {
57
+ clock.advance(frameInterval)
58
+ await renderOnce()
59
+ }
60
+ }
@@ -0,0 +1,8 @@
1
+ # Composition Exploration
2
+
3
+ This is a simple exploration of how to compose renderables into a tree.
4
+
5
+ It's not react and not reactive, it's just a way to compose renderables
6
+ and mount them into a parent container.
7
+
8
+ It's a work in progress and not in any way meant to be a replacement for react.
@@ -0,0 +1,32 @@
1
+ import { Renderable, type RenderableOptions } from "../../Renderable.js"
2
+ import type { OptimizedBuffer } from "../../buffer.js"
3
+ import type { RenderContext } from "../../types.js"
4
+
5
+ export interface VRenderableOptions extends RenderableOptions<VRenderable> {
6
+ render?: (
7
+ this: VRenderable | VRenderableOptions,
8
+ buffer: OptimizedBuffer,
9
+ deltaTime: number,
10
+ renderable: VRenderable,
11
+ ) => void
12
+ }
13
+
14
+ /**
15
+ * A generic renderable that accepts a custom render function as a prop.
16
+ * This allows functional constructs to specify custom rendering behavior
17
+ * without needing to subclass Renderable.
18
+ */
19
+ export class VRenderable extends Renderable {
20
+ private options: VRenderableOptions
21
+
22
+ constructor(ctx: RenderContext, options: VRenderableOptions) {
23
+ super(ctx, options)
24
+ this.options = options
25
+ }
26
+
27
+ protected renderSelf(buffer: OptimizedBuffer, deltaTime: number): void {
28
+ if (this.options.render) {
29
+ this.options.render.call(this.options, buffer, deltaTime, this)
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,127 @@
1
+ import {
2
+ ASCIIFontRenderable,
3
+ BoxRenderable,
4
+ CodeRenderable,
5
+ InputRenderable,
6
+ ScrollBoxRenderable,
7
+ SelectRenderable,
8
+ TabSelectRenderable,
9
+ TextRenderable,
10
+ VRenderable,
11
+ FrameBufferRenderable,
12
+ type ASCIIFontOptions,
13
+ type BoxOptions,
14
+ type CodeOptions,
15
+ type TextOptions,
16
+ type VRenderableOptions,
17
+ type InputRenderableOptions,
18
+ type ScrollBoxOptions,
19
+ type SelectRenderableOptions,
20
+ type TabSelectRenderableOptions,
21
+ type FrameBufferOptions,
22
+ } from "..//index.js"
23
+ import { TextNodeRenderable, type TextNodeOptions } from "../TextNode.js"
24
+ import { h, type VChild } from "./vnode.js"
25
+ import { TextAttributes } from "../../types.js"
26
+ import type { RGBA } from "../../lib/RGBA.js"
27
+
28
+ export function Generic(props?: VRenderableOptions, ...children: VChild[]) {
29
+ return h(VRenderable, props || {}, ...children)
30
+ }
31
+
32
+ export function Box(props?: BoxOptions, ...children: VChild[]) {
33
+ return h(BoxRenderable, props || {}, ...children)
34
+ }
35
+
36
+ export function Text(props?: TextOptions & { content?: any }, ...children: VChild[] | TextNodeRenderable[]) {
37
+ return h(TextRenderable, props || {}, ...(children as VChild[]))
38
+ }
39
+
40
+ export function ASCIIFont(props?: ASCIIFontOptions, ...children: VChild[]) {
41
+ return h(ASCIIFontRenderable, props || {}, ...children)
42
+ }
43
+
44
+ export function Input(props?: InputRenderableOptions, ...children: VChild[]) {
45
+ return h(InputRenderable, props || {}, ...children)
46
+ }
47
+
48
+ export function Select(props?: SelectRenderableOptions, ...children: VChild[]) {
49
+ return h(SelectRenderable, props || {}, ...children)
50
+ }
51
+
52
+ export function TabSelect(props?: TabSelectRenderableOptions, ...children: VChild[]) {
53
+ return h(TabSelectRenderable, props || {}, ...children)
54
+ }
55
+
56
+ export function FrameBuffer(props: FrameBufferOptions, ...children: VChild[]) {
57
+ return h(FrameBufferRenderable, props, ...children)
58
+ }
59
+
60
+ export function Code(props: CodeOptions, ...children: VChild[]) {
61
+ return h(CodeRenderable, props, ...children)
62
+ }
63
+
64
+ export function ScrollBox(props?: ScrollBoxOptions, ...children: VChild[]) {
65
+ return h(ScrollBoxRenderable, props || {}, ...children)
66
+ }
67
+
68
+ interface StyledTextProps extends Omit<TextNodeOptions, "attributes"> {
69
+ attributes?: number
70
+ }
71
+
72
+ function StyledText(props?: StyledTextProps, ...children: (string | TextNodeRenderable)[]): TextNodeRenderable {
73
+ const styledProps = props as StyledTextProps
74
+ const textNodeOptions: TextNodeOptions = {
75
+ ...styledProps,
76
+ attributes: styledProps?.attributes ?? 0,
77
+ }
78
+
79
+ const textNode = new TextNodeRenderable(textNodeOptions)
80
+
81
+ for (const child of children) {
82
+ textNode.add(child)
83
+ }
84
+
85
+ return textNode
86
+ }
87
+
88
+ // Text styling convenience functions - these create TextNodeRenderable instances that can be nested and stacked
89
+ export const vstyles = {
90
+ // Basic text styles
91
+ bold: (...children: (string | TextNodeRenderable)[]) => StyledText({ attributes: TextAttributes.BOLD }, ...children),
92
+ italic: (...children: (string | TextNodeRenderable)[]) =>
93
+ StyledText({ attributes: TextAttributes.ITALIC }, ...children),
94
+ underline: (...children: (string | TextNodeRenderable)[]) =>
95
+ StyledText({ attributes: TextAttributes.UNDERLINE }, ...children),
96
+ dim: (...children: (string | TextNodeRenderable)[]) => StyledText({ attributes: TextAttributes.DIM }, ...children),
97
+ blink: (...children: (string | TextNodeRenderable)[]) =>
98
+ StyledText({ attributes: TextAttributes.BLINK }, ...children),
99
+ inverse: (...children: (string | TextNodeRenderable)[]) =>
100
+ StyledText({ attributes: TextAttributes.INVERSE }, ...children),
101
+ hidden: (...children: (string | TextNodeRenderable)[]) =>
102
+ StyledText({ attributes: TextAttributes.HIDDEN }, ...children),
103
+ strikethrough: (...children: (string | TextNodeRenderable)[]) =>
104
+ StyledText({ attributes: TextAttributes.STRIKETHROUGH }, ...children),
105
+
106
+ // Combined styles
107
+ boldItalic: (...children: (string | TextNodeRenderable)[]) =>
108
+ StyledText({ attributes: TextAttributes.BOLD | TextAttributes.ITALIC }, ...children),
109
+ boldUnderline: (...children: (string | TextNodeRenderable)[]) =>
110
+ StyledText({ attributes: TextAttributes.BOLD | TextAttributes.UNDERLINE }, ...children),
111
+ italicUnderline: (...children: (string | TextNodeRenderable)[]) =>
112
+ StyledText({ attributes: TextAttributes.ITALIC | TextAttributes.UNDERLINE }, ...children),
113
+ boldItalicUnderline: (...children: (string | TextNodeRenderable)[]) =>
114
+ StyledText({ attributes: TextAttributes.BOLD | TextAttributes.ITALIC | TextAttributes.UNDERLINE }, ...children),
115
+
116
+ // Color helpers
117
+ color: (color: string | RGBA, ...children: (string | TextNodeRenderable)[]) => StyledText({ fg: color }, ...children),
118
+ bgColor: (bgColor: string | RGBA, ...children: (string | TextNodeRenderable)[]) =>
119
+ StyledText({ bg: bgColor }, ...children),
120
+ fg: (color: string | RGBA, ...children: (string | TextNodeRenderable)[]) => StyledText({ fg: color }, ...children),
121
+ bg: (bgColor: string | RGBA, ...children: (string | TextNodeRenderable)[]) =>
122
+ StyledText({ bg: bgColor }, ...children),
123
+
124
+ // Custom styling function
125
+ styled: (attributes: number = 0, ...children: (string | TextNodeRenderable)[]) =>
126
+ StyledText({ attributes }, ...children),
127
+ }
@@ -0,0 +1,277 @@
1
+ import { isRenderable, Renderable, type RenderableOptions } from "../../Renderable.js"
2
+ import type { RenderContext } from "../../types.js"
3
+ import util from "node:util"
4
+
5
+ export type VChild = VNode | Renderable | VChild[] | null | undefined | false
6
+
7
+ export interface PendingCall {
8
+ method: string
9
+ args: any[]
10
+ isProperty?: boolean
11
+ }
12
+
13
+ const BrandedVNode: unique symbol = Symbol.for("@opentui/core/VNode")
14
+
15
+ export interface VNode<P = any, C = VChild[]> {
16
+ [BrandedVNode]: true
17
+ type: Construct<P>
18
+ props?: P
19
+ children?: C
20
+ __delegateMap?: Record<string, string>
21
+ __pendingCalls?: PendingCall[]
22
+ }
23
+
24
+ // Type that represents a VNode with Renderable methods available for chaining
25
+ export type ProxiedVNode<TCtor extends RenderableConstructor<any>> = VNode<
26
+ TCtor extends RenderableConstructor<infer P> ? P : any
27
+ > & {
28
+ [K in keyof InstanceType<TCtor>]: InstanceType<TCtor>[K] extends (...args: infer Args) => any
29
+ ? (...args: Args) => ProxiedVNode<TCtor>
30
+ : InstanceType<TCtor>[K]
31
+ }
32
+
33
+ export interface RenderableConstructor<P extends RenderableOptions<any> = RenderableOptions<any>> {
34
+ new (ctx: RenderContext, options: P): Renderable
35
+ }
36
+
37
+ export type FunctionalConstruct<P = any> = (props: P, children?: VChild[]) => VNode
38
+
39
+ export type Construct<P = any> =
40
+ | RenderableConstructor<P extends RenderableOptions<any> ? P : never>
41
+ | FunctionalConstruct<P>
42
+
43
+ function isRenderableConstructor<P extends RenderableOptions<any> = RenderableOptions<any>>(
44
+ value: any,
45
+ ): value is RenderableConstructor<P> {
46
+ return typeof value === "function" && value.prototype && Renderable.prototype.isPrototypeOf(value.prototype)
47
+ }
48
+
49
+ function flattenChildren(children: VChild[]): VChild[] {
50
+ const result: VChild[] = []
51
+ for (const child of children) {
52
+ if (Array.isArray(child)) {
53
+ result.push(...flattenChildren(child))
54
+ } else if (child !== null && child !== undefined && child !== false) {
55
+ result.push(child)
56
+ }
57
+ }
58
+ return result
59
+ }
60
+
61
+ // Overloads for proper typing
62
+ export function h<TCtor extends RenderableConstructor<any>>(
63
+ type: TCtor,
64
+ props?: TCtor extends RenderableConstructor<infer P> ? P : never,
65
+ ...children: VChild[]
66
+ ): ProxiedVNode<TCtor>
67
+ export function h<P>(type: FunctionalConstruct<P>, props?: P, ...children: VChild[]): VNode<P>
68
+ export function h<P>(type: Construct<P>, props?: P, ...children: VChild[]): VNode<P> | ProxiedVNode<any>
69
+ export function h<P>(type: Construct<P>, props?: P, ...children: VChild[]): any {
70
+ if (typeof type !== "function") {
71
+ throw new TypeError("h() received an invalid vnode type")
72
+ }
73
+
74
+ const vnode: VNode<P> = {
75
+ [BrandedVNode]: true,
76
+ type,
77
+ props,
78
+ children: flattenChildren(children),
79
+ __pendingCalls: [],
80
+ }
81
+
82
+ if (isRenderableConstructor(type)) {
83
+ return new Proxy(vnode, {
84
+ get(target, prop, receiver) {
85
+ // Return VNode properties directly
86
+ if (prop in target) {
87
+ return Reflect.get(target, prop, receiver)
88
+ }
89
+
90
+ if (typeof prop === "string") {
91
+ const prototype = type.prototype
92
+ const hasMethod =
93
+ prototype &&
94
+ (typeof prototype[prop] === "function" ||
95
+ Object.getOwnPropertyDescriptor(prototype, prop) ||
96
+ Object.getOwnPropertyDescriptor(Object.getPrototypeOf(prototype), prop))
97
+
98
+ if (hasMethod) {
99
+ return (...args: any[]) => {
100
+ target.__pendingCalls = target.__pendingCalls || []
101
+ target.__pendingCalls.push({ method: prop, args })
102
+ return target
103
+ }
104
+ }
105
+ }
106
+
107
+ return Reflect.get(target, prop, receiver)
108
+ },
109
+
110
+ set(target, prop, value, receiver) {
111
+ if (typeof prop === "string" && isRenderableConstructor(type)) {
112
+ const prototype = type.prototype
113
+ const descriptor =
114
+ Object.getOwnPropertyDescriptor(prototype, prop) ||
115
+ Object.getOwnPropertyDescriptor(Object.getPrototypeOf(prototype), prop)
116
+
117
+ if (descriptor && descriptor.set) {
118
+ target.__pendingCalls = target.__pendingCalls || []
119
+ target.__pendingCalls.push({ method: prop, args: [value], isProperty: true })
120
+ return true
121
+ }
122
+ }
123
+
124
+ return Reflect.set(target, prop, value, receiver)
125
+ },
126
+ })
127
+ }
128
+
129
+ return vnode
130
+ }
131
+
132
+ export function isVNode(node: any): node is VNode {
133
+ return node && node[BrandedVNode]
134
+ }
135
+
136
+ export function maybeMakeRenderable(
137
+ ctx: RenderContext,
138
+ node: Renderable | VNode<any, any[]> | unknown,
139
+ ): Renderable | null {
140
+ if (isRenderable(node)) return node
141
+ if (isVNode(node)) return instantiate(ctx, node)
142
+ if (process.env.NODE_ENV !== "production") {
143
+ console.warn("maybeMakeRenderable received an invalid node", util.inspect(node, { depth: 2 }))
144
+ }
145
+ return null
146
+ }
147
+
148
+ export function wrapWithDelegates<T extends InstanceType<RenderableConstructor>>(
149
+ instance: T,
150
+ delegateMap: Record<string, string> | undefined,
151
+ ): T {
152
+ if (!delegateMap || Object.keys(delegateMap).length === 0) return instance
153
+
154
+ const getDescendant = (id: string): Renderable | undefined => {
155
+ return (instance as Renderable).findDescendantById(id)
156
+ }
157
+
158
+ const proxy = new Proxy(instance as any, {
159
+ get(target, prop, receiver) {
160
+ if (typeof prop === "string" && delegateMap[prop]) {
161
+ const host = getDescendant(delegateMap[prop])
162
+ if (host) {
163
+ const value = (host as any)[prop]
164
+ if (typeof value === "function") {
165
+ return value.bind(host)
166
+ }
167
+ return value
168
+ }
169
+ }
170
+ return Reflect.get(target, prop, receiver)
171
+ },
172
+ set(target, prop, value, receiver) {
173
+ if (typeof prop === "string" && delegateMap[prop]) {
174
+ const host = getDescendant(delegateMap[prop])
175
+ if (host) {
176
+ return Reflect.set(host as any, prop, value)
177
+ }
178
+ }
179
+ return Reflect.set(target, prop, value, receiver)
180
+ },
181
+ })
182
+ return proxy
183
+ }
184
+
185
+ export type InstantiateFn<NodeType extends VNode | Renderable> = Renderable & { __node?: NodeType }
186
+
187
+ export function instantiate<NodeType extends VNode | Renderable>(
188
+ ctx: RenderContext,
189
+ node: NodeType,
190
+ ): InstantiateFn<NodeType> {
191
+ if (isRenderable(node)) return node
192
+
193
+ if (!node || typeof node !== "object") {
194
+ throw new TypeError("mount() received an invalid vnode")
195
+ }
196
+
197
+ const vnode = node as VNode
198
+ const { type, props } = vnode
199
+ const children = flattenChildren(vnode.children || [])
200
+ const delegateMap = (vnode as any).__delegateMap as Record<string, string> | undefined
201
+
202
+ if (isRenderableConstructor(type)) {
203
+ const instance = new type(ctx, (props || {}) as any)
204
+
205
+ for (const child of children) {
206
+ if (isRenderable(child)) {
207
+ instance.add(child)
208
+ } else {
209
+ const mounted = instantiate(ctx, child as NodeType)
210
+ instance.add(mounted)
211
+ }
212
+ }
213
+
214
+ const delegatedInstance = wrapWithDelegates(instance, delegateMap)
215
+
216
+ const pendingCalls = (vnode as any).__pendingCalls as PendingCall[] | undefined
217
+ if (pendingCalls) {
218
+ for (const call of pendingCalls) {
219
+ if (call.isProperty) {
220
+ ;(delegatedInstance as any)[call.method] = call.args[0]
221
+ } else {
222
+ ;(delegatedInstance as any)[call.method].apply(delegatedInstance, call.args)
223
+ }
224
+ }
225
+ }
226
+
227
+ return delegatedInstance
228
+ }
229
+
230
+ // Functional construct: resolve to a concrete vnode and mount it
231
+ const resolved = (type as FunctionalConstruct)(props || ({} as any), children)
232
+ const inst = instantiate(ctx, resolved)
233
+
234
+ return wrapWithDelegates(inst, delegateMap) as InstantiateFn<NodeType>
235
+ }
236
+
237
+ export type DelegateMap<T> = Partial<Record<keyof T, string>>
238
+
239
+ export type ValidateShape<Given, AllowedKeys> = {
240
+ [K in keyof Given]: K extends keyof AllowedKeys ? NonNullable<Given[K]> : never
241
+ }
242
+
243
+ type InferNode<T> = T extends InstantiateFn<infer U> ? U : never
244
+
245
+ export function delegate<
246
+ Factory extends InstantiateFn<any>,
247
+ InnerNode extends InferNode<Factory>,
248
+ TargetMap extends Record<keyof InnerNode, string>,
249
+ const Mapping extends Partial<TargetMap>,
250
+ >(mapping: ValidateShape<Mapping, TargetMap>, vnode: Factory): Renderable
251
+
252
+ export function delegate<
253
+ ConstructorType extends RenderableConstructor<any>,
254
+ TargetMap extends Record<keyof InstanceType<ConstructorType>, string>,
255
+ const Mapping extends Partial<TargetMap>,
256
+ >(mapping: ValidateShape<Mapping, TargetMap>, vnode: ProxiedVNode<ConstructorType>): ProxiedVNode<ConstructorType>
257
+
258
+ export function delegate<
259
+ ConstructorType extends RenderableConstructor<any>,
260
+ const Mapping extends DelegateMap<InstanceType<ConstructorType>>,
261
+ >(mapping: ValidateShape<Mapping, string>, vnode: VNode & { type: ConstructorType }): VNode
262
+
263
+ /**
264
+ * Controlled delegation that routes selected properties/methods
265
+ * to a descendant renderable identified by ID.
266
+ */
267
+ export function delegate<NodeType extends VNode | Renderable | InstantiateFn<any>>(
268
+ mapping: Record<string, string>,
269
+ vnode: NodeType,
270
+ ): VNode | Renderable {
271
+ if (isRenderable(vnode)) {
272
+ return wrapWithDelegates(vnode, mapping)
273
+ }
274
+ if (!vnode || typeof vnode !== "object") return vnode
275
+ vnode.__delegateMap = { ...(vnode.__delegateMap || {}), ...mapping }
276
+ return vnode
277
+ }
@@ -0,0 +1,23 @@
1
+ export * from "./ASCIIFont.js"
2
+ export * from "./Box.js"
3
+ export * from "./Code.js"
4
+ export * from "./composition/constructs.js"
5
+ export * from "./composition/VRenderable.js"
6
+ export * from "./composition/vnode.js"
7
+ export * from "./Diff.js"
8
+ export * from "./EditBufferRenderable.js"
9
+ export * from "./FrameBuffer.js"
10
+ export * from "./Input.js"
11
+ export * from "./LineNumberRenderable.js"
12
+ export * from "./Markdown.js"
13
+ export * from "./ScrollBar.js"
14
+ export * from "./ScrollBox.js"
15
+ export * from "./Select.js"
16
+ export * from "./Slider.js"
17
+ export * from "./TextTable.js"
18
+ export * from "./TabSelect.js"
19
+ export * from "./Text.js"
20
+ export * from "./TimeToFirstDraw.js"
21
+ export * from "./TextBufferRenderable.js"
22
+ export * from "./TextNode.js"
23
+ export * from "./Textarea.js"
@@ -0,0 +1,79 @@
1
+ import { Lexer, type MarkedToken } from "marked"
2
+
3
+ export interface ParseState {
4
+ content: string
5
+ tokens: MarkedToken[]
6
+ stableTokenCount?: number
7
+ }
8
+
9
+ /**
10
+ * Incrementally parse markdown, reusing unchanged tokens from previous parse.
11
+ * Compares token.raw at each offset - matching tokens keep same object reference.
12
+ */
13
+ export function parseMarkdownIncremental(
14
+ newContent: string,
15
+ prevState: ParseState | null,
16
+ trailingUnstable: number = 2,
17
+ ): ParseState {
18
+ if (!prevState || prevState.tokens.length === 0) {
19
+ try {
20
+ const tokens = Lexer.lex(newContent, { gfm: true }) as MarkedToken[]
21
+ return {
22
+ content: newContent,
23
+ tokens,
24
+ stableTokenCount: Math.max(0, tokens.length - trailingUnstable),
25
+ }
26
+ } catch {
27
+ return { content: newContent, tokens: [], stableTokenCount: 0 }
28
+ }
29
+ }
30
+
31
+ // Find how many tokens from start are unchanged
32
+ let offset = 0
33
+ let reuseCount = 0
34
+
35
+ for (const token of prevState.tokens) {
36
+ const tokenLength = token.raw.length
37
+ if (offset + tokenLength <= newContent.length && newContent.startsWith(token.raw, offset)) {
38
+ reuseCount++
39
+ offset += tokenLength
40
+ } else {
41
+ break
42
+ }
43
+ }
44
+
45
+ // Keep last N tokens unstable (e.g. "# Hello" might become "# Hello World")
46
+ reuseCount = Math.max(0, reuseCount - trailingUnstable)
47
+
48
+ offset = 0
49
+ for (let i = 0; i < reuseCount; i++) {
50
+ offset += prevState.tokens[i].raw.length
51
+ }
52
+
53
+ const stableTokens = prevState.tokens.slice(0, reuseCount)
54
+ const remainingContent = newContent.slice(offset)
55
+
56
+ if (!remainingContent) {
57
+ return {
58
+ content: newContent,
59
+ tokens: stableTokens,
60
+ stableTokenCount: stableTokens.length,
61
+ }
62
+ }
63
+
64
+ try {
65
+ const newTokens = Lexer.lex(remainingContent, { gfm: true }) as MarkedToken[]
66
+ return {
67
+ content: newContent,
68
+ tokens: [...stableTokens, ...newTokens],
69
+ stableTokenCount: trailingUnstable === 0 ? stableTokens.length + newTokens.length : stableTokens.length,
70
+ }
71
+ } catch {
72
+ try {
73
+ const fullTokens = Lexer.lex(newContent, { gfm: true }) as MarkedToken[]
74
+ return { content: newContent, tokens: fullTokens, stableTokenCount: 0 }
75
+ } catch {
76
+ return { content: newContent, tokens: [], stableTokenCount: 0 }
77
+ }
78
+ }
79
+ }