@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,555 @@
1
+ import { type LineInfo, type RenderContext } from "../types.js"
2
+ import { StyledText } from "../lib/styled-text.js"
3
+ import { SyntaxStyle } from "../syntax-style.js"
4
+ import { getTreeSitterClient, TreeSitterClient } from "../lib/tree-sitter/index.js"
5
+ import { TextBufferRenderable, type TextBufferOptions } from "./TextBufferRenderable.js"
6
+ import type { OptimizedBuffer } from "../buffer.js"
7
+ import type { SimpleHighlight } from "../lib/tree-sitter/types.js"
8
+ import type { TextChunk } from "../text-buffer.js"
9
+ import { treeSitterToTextChunks } from "../lib/tree-sitter-styled-text.js"
10
+
11
+ export interface HighlightContext {
12
+ content: string
13
+ filetype: string
14
+ syntaxStyle: SyntaxStyle
15
+ }
16
+
17
+ export type OnHighlightCallback = (
18
+ highlights: SimpleHighlight[],
19
+ context: HighlightContext,
20
+ ) => SimpleHighlight[] | undefined | Promise<SimpleHighlight[] | undefined>
21
+
22
+ export interface ChunkRenderContext extends HighlightContext {
23
+ highlights: SimpleHighlight[]
24
+ }
25
+
26
+ export type OnChunksCallback = (
27
+ chunks: TextChunk[],
28
+ context: ChunkRenderContext,
29
+ ) => TextChunk[] | undefined | Promise<TextChunk[] | undefined>
30
+
31
+ export interface CodeOptions extends TextBufferOptions {
32
+ content?: string
33
+ filetype?: string
34
+ syntaxStyle: SyntaxStyle
35
+ treeSitterClient?: TreeSitterClient
36
+ conceal?: boolean
37
+ drawUnstyledText?: boolean
38
+ streaming?: boolean
39
+ initialStyledText?: StyledText
40
+ baseHighlight?: string
41
+ onHighlight?: OnHighlightCallback
42
+ onChunks?: OnChunksCallback
43
+ }
44
+
45
+ type ConcealLineRange = [start: number, end: number]
46
+
47
+ export class CodeRenderable extends TextBufferRenderable {
48
+ private _content: string
49
+ private _filetype?: string
50
+ private _syntaxStyle: SyntaxStyle
51
+ private _isHighlighting: boolean = false
52
+ private _treeSitterClient: TreeSitterClient
53
+ private _highlightsDirty: boolean = false
54
+ private _highlightSnapshotId: number = 0
55
+ private _conceal: boolean
56
+ private _drawUnstyledText: boolean
57
+ private _shouldRenderTextBuffer: boolean = true
58
+ private _streaming: boolean
59
+ private _initialStyledText?: StyledText
60
+ private _hadInitialContent: boolean = false
61
+ private _lastHighlights: SimpleHighlight[] = []
62
+ private _baseHighlight?: string
63
+ private _onHighlight?: OnHighlightCallback
64
+ private _onChunks?: OnChunksCallback
65
+ private _highlightingPromise: Promise<void> = Promise.resolve()
66
+ // Temporary rendered-line -> source-line map for concealment; native extmarks should replace this.
67
+ private _renderedLineSources?: number[]
68
+ private _mappedLineInfo?: LineInfo
69
+
70
+ protected _contentDefaultOptions = {
71
+ content: "",
72
+ conceal: true,
73
+ drawUnstyledText: true,
74
+ streaming: false,
75
+ } satisfies Partial<CodeOptions>
76
+
77
+ constructor(ctx: RenderContext, options: CodeOptions) {
78
+ super(ctx, options)
79
+
80
+ this._content = options.content ?? this._contentDefaultOptions.content
81
+ this._filetype = options.filetype
82
+ this._syntaxStyle = options.syntaxStyle
83
+ this._treeSitterClient = options.treeSitterClient ?? getTreeSitterClient()
84
+ this._conceal = options.conceal ?? this._contentDefaultOptions.conceal
85
+ this._drawUnstyledText = options.drawUnstyledText ?? this._contentDefaultOptions.drawUnstyledText
86
+ this._streaming = options.streaming ?? this._contentDefaultOptions.streaming
87
+ this._initialStyledText = options.initialStyledText
88
+ this._baseHighlight = options.baseHighlight
89
+ this._onHighlight = options.onHighlight
90
+ this._onChunks = options.onChunks
91
+
92
+ if (this._content.length > 0) {
93
+ if (this._initialStyledText && this._drawUnstyledText) {
94
+ this.textBuffer.setStyledText(this._initialStyledText)
95
+ } else {
96
+ this.textBuffer.setText(this._content)
97
+ }
98
+ this.updateTextInfo()
99
+ this._shouldRenderTextBuffer = this._drawUnstyledText || !this._filetype
100
+ }
101
+
102
+ this._highlightsDirty = this._content.length > 0
103
+ }
104
+
105
+ get content(): string {
106
+ return this._content
107
+ }
108
+
109
+ set content(value: string) {
110
+ if (this._content !== value) {
111
+ this._content = value
112
+ this._highlightsDirty = true
113
+ this._highlightSnapshotId++
114
+
115
+ if (this._streaming && this._filetype && !this._drawUnstyledText) {
116
+ this.requestRender()
117
+ return
118
+ }
119
+
120
+ if (this._initialStyledText && this._drawUnstyledText) {
121
+ this.textBuffer.setStyledText(this._initialStyledText)
122
+ } else {
123
+ this.textBuffer.setText(value)
124
+ }
125
+ this.setRenderedLineSources(undefined)
126
+ this.updateTextInfo()
127
+ }
128
+ }
129
+
130
+ public override get lineInfo(): LineInfo {
131
+ if (!this._renderedLineSources) return super.lineInfo
132
+ if (this._mappedLineInfo) return this._mappedLineInfo
133
+
134
+ const lineInfo = super.lineInfo
135
+ const renderedLineSources = this._renderedLineSources
136
+
137
+ // Native reports visual rows for the rendered buffer; remap those rows back to source lines.
138
+ this._mappedLineInfo = {
139
+ ...lineInfo,
140
+ lineSources: lineInfo.lineSources.map((line) => renderedLineSources[line] ?? line),
141
+ }
142
+ return this._mappedLineInfo
143
+ }
144
+
145
+ public override get wrapMode(): "none" | "char" | "word" {
146
+ return super.wrapMode
147
+ }
148
+
149
+ public override set wrapMode(value: "none" | "char" | "word") {
150
+ if (super.wrapMode !== value) {
151
+ this._mappedLineInfo = undefined
152
+ super.wrapMode = value
153
+ }
154
+ }
155
+
156
+ protected override onResize(width: number, height: number): void {
157
+ this._mappedLineInfo = undefined
158
+ super.onResize(width, height)
159
+ }
160
+
161
+ protected override updateTextInfo(): void {
162
+ this._mappedLineInfo = undefined
163
+ super.updateTextInfo()
164
+ }
165
+
166
+ get filetype(): string | undefined {
167
+ return this._filetype
168
+ }
169
+
170
+ set filetype(value: string | undefined) {
171
+ if (this._filetype !== value) {
172
+ this._filetype = value
173
+ this._highlightsDirty = true
174
+ }
175
+ }
176
+
177
+ get syntaxStyle(): SyntaxStyle {
178
+ return this._syntaxStyle
179
+ }
180
+
181
+ set syntaxStyle(value: SyntaxStyle) {
182
+ if (this._syntaxStyle !== value) {
183
+ this._syntaxStyle = value
184
+ this._highlightsDirty = true
185
+ }
186
+ }
187
+
188
+ get conceal(): boolean {
189
+ return this._conceal
190
+ }
191
+
192
+ set conceal(value: boolean) {
193
+ if (this._conceal !== value) {
194
+ this._conceal = value
195
+ this._highlightsDirty = true
196
+ }
197
+ }
198
+
199
+ get drawUnstyledText(): boolean {
200
+ return this._drawUnstyledText
201
+ }
202
+
203
+ set drawUnstyledText(value: boolean) {
204
+ if (this._drawUnstyledText !== value) {
205
+ this._drawUnstyledText = value
206
+ this._highlightsDirty = true
207
+ }
208
+ }
209
+
210
+ get streaming(): boolean {
211
+ return this._streaming
212
+ }
213
+
214
+ set initialStyledText(value: StyledText | undefined) {
215
+ if (this._initialStyledText !== value) {
216
+ this._initialStyledText = value
217
+ this._highlightsDirty = true
218
+ }
219
+ }
220
+
221
+ set streaming(value: boolean) {
222
+ if (this._streaming !== value) {
223
+ this._streaming = value
224
+ this._hadInitialContent = false
225
+ this._lastHighlights = []
226
+ this._highlightsDirty = true
227
+ }
228
+ }
229
+
230
+ get treeSitterClient(): TreeSitterClient {
231
+ return this._treeSitterClient
232
+ }
233
+
234
+ set treeSitterClient(value: TreeSitterClient) {
235
+ if (this._treeSitterClient !== value) {
236
+ this._treeSitterClient = value
237
+ this._highlightsDirty = true
238
+ }
239
+ }
240
+
241
+ get onHighlight(): OnHighlightCallback | undefined {
242
+ return this._onHighlight
243
+ }
244
+
245
+ get baseHighlight(): string | undefined {
246
+ return this._baseHighlight
247
+ }
248
+
249
+ set baseHighlight(value: string | undefined) {
250
+ if (this._baseHighlight !== value) {
251
+ this._baseHighlight = value
252
+ this._highlightsDirty = true
253
+ }
254
+ }
255
+
256
+ set onHighlight(value: OnHighlightCallback | undefined) {
257
+ if (this._onHighlight !== value) {
258
+ this._onHighlight = value
259
+ this._highlightsDirty = true
260
+ }
261
+ }
262
+
263
+ get onChunks(): OnChunksCallback | undefined {
264
+ return this._onChunks
265
+ }
266
+
267
+ set onChunks(value: OnChunksCallback | undefined) {
268
+ if (this._onChunks !== value) {
269
+ this._onChunks = value
270
+ this._highlightsDirty = true
271
+ }
272
+ }
273
+
274
+ get isHighlighting(): boolean {
275
+ return this._isHighlighting
276
+ }
277
+
278
+ get highlightingDone(): Promise<void> {
279
+ return this._highlightingPromise
280
+ }
281
+
282
+ protected async transformChunks(chunks: TextChunk[], context: ChunkRenderContext): Promise<TextChunk[]> {
283
+ if (!this._onChunks) return chunks
284
+
285
+ const modified = await this._onChunks(chunks, context)
286
+ return modified ?? chunks
287
+ }
288
+
289
+ private ensureVisibleTextBeforeHighlight(): void {
290
+ if (this.isDestroyed) return
291
+
292
+ const content = this._content
293
+
294
+ if (!this._filetype) {
295
+ this._shouldRenderTextBuffer = true
296
+ return
297
+ }
298
+
299
+ const isInitialContent = this._streaming && !this._hadInitialContent
300
+ const shouldDrawUnstyledNow = this._streaming ? isInitialContent && this._drawUnstyledText : this._drawUnstyledText
301
+
302
+ if (this._streaming && !isInitialContent) {
303
+ this._shouldRenderTextBuffer = true
304
+ } else if (shouldDrawUnstyledNow) {
305
+ if (this._initialStyledText) {
306
+ this.textBuffer.setStyledText(this._initialStyledText)
307
+ } else {
308
+ this.textBuffer.setText(content)
309
+ }
310
+ this.setRenderedLineSources(undefined)
311
+ this._shouldRenderTextBuffer = true
312
+ } else {
313
+ this._shouldRenderTextBuffer = false
314
+ }
315
+ }
316
+
317
+ private async startHighlight(): Promise<void> {
318
+ const content = this._content
319
+ const filetype = this._filetype
320
+ const snapshotId = ++this._highlightSnapshotId
321
+
322
+ if (!filetype) return
323
+
324
+ const isInitialContent = this._streaming && !this._hadInitialContent
325
+ if (isInitialContent) {
326
+ this._hadInitialContent = true
327
+ }
328
+
329
+ this._isHighlighting = true
330
+
331
+ try {
332
+ const result = await this._treeSitterClient.highlightOnce(content, filetype)
333
+
334
+ if (snapshotId !== this._highlightSnapshotId) {
335
+ this.requestRender()
336
+ return
337
+ }
338
+
339
+ if (this.isDestroyed) return
340
+
341
+ let highlights = result.highlights ?? []
342
+
343
+ if (this._onHighlight && highlights.length >= 0) {
344
+ const context: HighlightContext = {
345
+ content,
346
+ filetype,
347
+ syntaxStyle: this._syntaxStyle,
348
+ }
349
+ const modified = await this._onHighlight(highlights, context)
350
+ if (modified !== undefined) {
351
+ highlights = modified
352
+ }
353
+ }
354
+
355
+ if (snapshotId !== this._highlightSnapshotId) {
356
+ this.requestRender()
357
+ return
358
+ }
359
+
360
+ if (this.isDestroyed) return
361
+
362
+ if (highlights.length > 0) {
363
+ if (this._streaming) {
364
+ this._lastHighlights = highlights
365
+ }
366
+ }
367
+
368
+ if (highlights.length > 0 || this._onChunks || this._baseHighlight) {
369
+ const context: ChunkRenderContext = {
370
+ content,
371
+ filetype,
372
+ syntaxStyle: this._syntaxStyle,
373
+ highlights,
374
+ }
375
+
376
+ let chunks = treeSitterToTextChunks(content, highlights, this._syntaxStyle, {
377
+ enabled: this._conceal,
378
+ baseHighlight: this._baseHighlight,
379
+ })
380
+ // onChunks may rewrite text arbitrarily, so the conceal-only source map would be invalid.
381
+ const renderedLineSources = this._onChunks ? undefined : this.getConcealLinesSourceMap(content, highlights)
382
+
383
+ chunks = await this.transformChunks(chunks, context)
384
+
385
+ if (snapshotId !== this._highlightSnapshotId) {
386
+ this.requestRender()
387
+ return
388
+ }
389
+
390
+ if (this.isDestroyed) return
391
+
392
+ const styledText = new StyledText(chunks)
393
+ this.textBuffer.setStyledText(styledText)
394
+ this.setRenderedLineSources(renderedLineSources)
395
+ } else {
396
+ this.textBuffer.setText(content)
397
+ this.setRenderedLineSources(undefined)
398
+ }
399
+
400
+ this._shouldRenderTextBuffer = true
401
+ this._isHighlighting = false
402
+ this._highlightsDirty = false
403
+ this.updateTextInfo()
404
+ this.requestRender()
405
+ } catch (error) {
406
+ if (snapshotId !== this._highlightSnapshotId) {
407
+ this.requestRender()
408
+ return
409
+ }
410
+
411
+ console.warn("Code highlighting failed, falling back to plain text:", error)
412
+ if (this.isDestroyed) return
413
+ this.textBuffer.setText(content)
414
+ this.setRenderedLineSources(undefined)
415
+ this._shouldRenderTextBuffer = true
416
+ this._isHighlighting = false
417
+ this._highlightsDirty = false
418
+ this.updateTextInfo()
419
+ this.requestRender()
420
+ }
421
+ }
422
+
423
+ private setRenderedLineSources(lineSources: number[] | undefined): void {
424
+ this._renderedLineSources = lineSources
425
+ this._mappedLineInfo = undefined
426
+ }
427
+
428
+ private static isIdentityLineSources(lineSources: number[]): boolean {
429
+ for (let i = 0; i < lineSources.length; i++) {
430
+ if (lineSources[i] !== i) return false
431
+ }
432
+ return true
433
+ }
434
+
435
+ private static getMergedConcealLineRanges(highlights: SimpleHighlight[]): ConcealLineRange[] {
436
+ const ranges: ConcealLineRange[] = []
437
+
438
+ for (const highlight of highlights) {
439
+ const meta = highlight[3]
440
+ if (meta?.concealLines === undefined) continue
441
+
442
+ const group = highlight[2]
443
+ const isEmptyConceal =
444
+ meta.conceal === "" || (meta.conceal === undefined && (group === "conceal" || group.startsWith("conceal.")))
445
+ if (isEmptyConceal) {
446
+ ranges.push([highlight[0], highlight[1]])
447
+ }
448
+ }
449
+
450
+ if (ranges.length <= 1) return ranges
451
+
452
+ // Overlapping conceal ranges must collapse before line-by-line source mapping.
453
+ ranges.sort((a, b) => a[0] - b[0])
454
+ let writeIndex = 0
455
+
456
+ for (let i = 1; i < ranges.length; i++) {
457
+ const current = ranges[writeIndex]
458
+ const next = ranges[i]
459
+
460
+ if (next[0] <= current[1]) {
461
+ current[1] = Math.max(current[1], next[1])
462
+ } else {
463
+ writeIndex++
464
+ ranges[writeIndex] = next
465
+ }
466
+ }
467
+
468
+ ranges.length = writeIndex + 1
469
+ return ranges
470
+ }
471
+
472
+ private getConcealLinesSourceMap(content: string, highlights: SimpleHighlight[]): number[] | undefined {
473
+ if (!this._conceal || content.length === 0) return undefined
474
+
475
+ // setStyledText gives native only rendered text; rebuild enough source identity for concealed lines.
476
+ // Native view-resolved extmarks should make this a layout query instead of a parallel map.
477
+ const concealLineRanges = CodeRenderable.getMergedConcealLineRanges(highlights)
478
+ if (concealLineRanges.length === 0) return undefined
479
+
480
+ const lineSources: number[] = []
481
+ let sourceLine = 0
482
+ let lineStart = 0
483
+ let rangeIndex = 0
484
+ let currentRenderedLineHasText = false
485
+
486
+ const setCurrentRenderedLineSource = (line: number, hasText: boolean): void => {
487
+ // Until visible text is emitted, a rendered line can still map to a later collapsed source line.
488
+ if (lineSources.length === 0) {
489
+ lineSources.push(line)
490
+ } else if (!currentRenderedLineHasText) {
491
+ lineSources[lineSources.length - 1] = line
492
+ }
493
+
494
+ if (hasText) currentRenderedLineHasText = true
495
+ }
496
+
497
+ while (lineStart <= content.length) {
498
+ const newlineOffset = content.indexOf("\n", lineStart)
499
+ const lineEnd = newlineOffset === -1 ? content.length : newlineOffset
500
+
501
+ while (rangeIndex < concealLineRanges.length && concealLineRanges[rangeIndex][1] <= lineStart) {
502
+ rangeIndex++
503
+ }
504
+
505
+ const range = concealLineRanges[rangeIndex]
506
+ const fullyConcealed = !!range && lineEnd > lineStart && range[0] <= lineStart && range[1] >= lineEnd
507
+ const lineBreakConcealed =
508
+ newlineOffset !== -1 && !!range && range[0] <= newlineOffset && range[1] >= newlineOffset
509
+
510
+ if (!fullyConcealed || !lineBreakConcealed) {
511
+ const hasText = lineEnd > lineStart && !fullyConcealed
512
+ if (hasText || newlineOffset !== -1 || !fullyConcealed) {
513
+ setCurrentRenderedLineSource(sourceLine, hasText)
514
+ }
515
+
516
+ if (newlineOffset !== -1 && !lineBreakConcealed) {
517
+ lineSources.push(sourceLine + 1)
518
+ currentRenderedLineHasText = false
519
+ }
520
+ }
521
+
522
+ sourceLine++
523
+ if (newlineOffset === -1) break
524
+ lineStart = newlineOffset + 1
525
+ }
526
+
527
+ if (lineSources.length === 0 || CodeRenderable.isIdentityLineSources(lineSources)) return undefined
528
+ return lineSources
529
+ }
530
+
531
+ public getLineHighlights(lineIdx: number) {
532
+ return this.textBuffer.getLineHighlights(lineIdx)
533
+ }
534
+
535
+ protected renderSelf(buffer: OptimizedBuffer): void {
536
+ if (this._highlightsDirty) {
537
+ if (this.isDestroyed) return
538
+
539
+ if (this._content.length === 0) {
540
+ this._shouldRenderTextBuffer = false
541
+ this._highlightsDirty = false
542
+ } else if (!this._filetype) {
543
+ this._shouldRenderTextBuffer = true
544
+ this._highlightsDirty = false
545
+ } else {
546
+ this.ensureVisibleTextBeforeHighlight()
547
+ this._highlightsDirty = false
548
+ this._highlightingPromise = this.startHighlight()
549
+ }
550
+ }
551
+
552
+ if (!this._shouldRenderTextBuffer) return
553
+ super.renderSelf(buffer)
554
+ }
555
+ }