@fairyhunter13/opentui-core 0.1.114 → 0.1.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (591) hide show
  1. package/3d/SpriteResourceManager.d.ts +74 -0
  2. package/3d/SpriteUtils.d.ts +13 -0
  3. package/3d/TextureUtils.d.ts +24 -0
  4. package/3d/ThreeRenderable.d.ts +40 -0
  5. package/3d/WGPURenderer.d.ts +61 -0
  6. package/3d/animation/ExplodingSpriteEffect.d.ts +71 -0
  7. package/3d/animation/PhysicsExplodingSpriteEffect.d.ts +76 -0
  8. package/3d/animation/SpriteAnimator.d.ts +124 -0
  9. package/3d/animation/SpriteParticleGenerator.d.ts +62 -0
  10. package/3d/canvas.d.ts +44 -0
  11. package/3d/index.d.ts +12 -0
  12. package/3d/physics/PlanckPhysicsAdapter.d.ts +19 -0
  13. package/3d/physics/RapierPhysicsAdapter.d.ts +19 -0
  14. package/3d/physics/physics-interface.d.ts +27 -0
  15. package/3d.d.ts +2 -0
  16. package/3d.js +34041 -0
  17. package/3d.js.map +155 -0
  18. package/LICENSE +21 -0
  19. package/NativeSpanFeed.d.ts +41 -0
  20. package/Renderable.d.ts +334 -0
  21. package/animation/Timeline.d.ts +126 -0
  22. package/ansi.d.ts +13 -0
  23. package/buffer.d.ts +111 -0
  24. package/console.d.ts +144 -0
  25. package/edit-buffer.d.ts +98 -0
  26. package/editor-view.d.ts +73 -0
  27. package/index-j4m38kjn.js +411 -0
  28. package/index-j4m38kjn.js.map +10 -0
  29. package/index-tse8gzh0.js +20614 -0
  30. package/index-tse8gzh0.js.map +67 -0
  31. package/index-vv2jcd4r.js +12299 -0
  32. package/index-vv2jcd4r.js.map +42 -0
  33. package/index.d.ts +23 -0
  34. package/index.js +478 -0
  35. package/index.js.map +9 -0
  36. package/lib/KeyHandler.d.ts +61 -0
  37. package/lib/RGBA.d.ts +25 -0
  38. package/lib/ascii.font.d.ts +508 -0
  39. package/lib/border.d.ts +51 -0
  40. package/lib/bunfs.d.ts +7 -0
  41. package/lib/clipboard.d.ts +17 -0
  42. package/lib/clock.d.ts +15 -0
  43. package/lib/data-paths.d.ts +26 -0
  44. package/lib/debounce.d.ts +42 -0
  45. package/lib/detect-links.d.ts +6 -0
  46. package/lib/env.d.ts +42 -0
  47. package/lib/extmarks-history.d.ts +17 -0
  48. package/lib/extmarks.d.ts +89 -0
  49. package/lib/hast-styled-text.d.ts +17 -0
  50. package/lib/index.d.ts +21 -0
  51. package/lib/keymapping.d.ts +25 -0
  52. package/lib/objects-in-viewport.d.ts +24 -0
  53. package/lib/output.capture.d.ts +24 -0
  54. package/lib/parse.keypress-kitty.d.ts +2 -0
  55. package/lib/parse.keypress.d.ts +26 -0
  56. package/lib/parse.mouse.d.ts +30 -0
  57. package/lib/paste.d.ts +7 -0
  58. package/lib/queue.d.ts +15 -0
  59. package/lib/renderable.validations.d.ts +12 -0
  60. package/lib/scroll-acceleration.d.ts +43 -0
  61. package/lib/selection.d.ts +63 -0
  62. package/lib/singleton.d.ts +7 -0
  63. package/lib/stdin-parser.d.ts +87 -0
  64. package/lib/styled-text.d.ts +63 -0
  65. package/lib/terminal-capability-detection.d.ts +30 -0
  66. package/lib/terminal-palette.d.ts +50 -0
  67. package/lib/tree-sitter/assets/update.d.ts +11 -0
  68. package/lib/tree-sitter/client.d.ts +47 -0
  69. package/lib/tree-sitter/default-parsers.d.ts +2 -0
  70. package/lib/tree-sitter/download-utils.d.ts +21 -0
  71. package/lib/tree-sitter/index.d.ts +8 -0
  72. package/lib/tree-sitter/parser.worker.d.ts +1 -0
  73. package/lib/tree-sitter/parsers-config.d.ts +53 -0
  74. package/lib/tree-sitter/resolve-ft.d.ts +5 -0
  75. package/lib/tree-sitter/types.d.ts +82 -0
  76. package/lib/tree-sitter-styled-text.d.ts +14 -0
  77. package/lib/validate-dir-name.d.ts +1 -0
  78. package/lib/yoga.options.d.ts +32 -0
  79. package/package.json +50 -62
  80. package/parser.worker.js +899 -0
  81. package/parser.worker.js.map +12 -0
  82. package/plugins/core-slot.d.ts +72 -0
  83. package/plugins/registry.d.ts +42 -0
  84. package/plugins/types.d.ts +34 -0
  85. package/post/effects.d.ts +147 -0
  86. package/post/filters.d.ts +65 -0
  87. package/post/matrices.d.ts +20 -0
  88. package/renderables/ASCIIFont.d.ts +52 -0
  89. package/renderables/Box.d.ts +81 -0
  90. package/renderables/Code.d.ts +78 -0
  91. package/renderables/Diff.d.ts +142 -0
  92. package/renderables/EditBufferRenderable.d.ts +237 -0
  93. package/renderables/FrameBuffer.d.ts +16 -0
  94. package/renderables/Input.d.ts +67 -0
  95. package/renderables/LineNumberRenderable.d.ts +78 -0
  96. package/renderables/Markdown.d.ts +185 -0
  97. package/renderables/ScrollBar.d.ts +77 -0
  98. package/renderables/ScrollBox.d.ts +124 -0
  99. package/renderables/Select.d.ts +115 -0
  100. package/renderables/Slider.d.ts +47 -0
  101. package/renderables/TabSelect.d.ts +96 -0
  102. package/renderables/Text.d.ts +36 -0
  103. package/renderables/TextBufferRenderable.d.ts +105 -0
  104. package/renderables/TextNode.d.ts +91 -0
  105. package/renderables/TextTable.d.ts +140 -0
  106. package/renderables/Textarea.d.ts +63 -0
  107. package/renderables/TimeToFirstDraw.d.ts +24 -0
  108. package/renderables/__tests__/renderable-test-utils.d.ts +12 -0
  109. package/renderables/composition/VRenderable.d.ts +16 -0
  110. package/renderables/composition/constructs.d.ts +35 -0
  111. package/renderables/composition/vnode.d.ts +46 -0
  112. package/renderables/index.d.ts +23 -0
  113. package/renderables/markdown-parser.d.ts +10 -0
  114. package/renderer.d.ts +419 -0
  115. package/runtime-plugin-support.d.ts +3 -0
  116. package/runtime-plugin-support.js +29 -0
  117. package/runtime-plugin-support.js.map +10 -0
  118. package/runtime-plugin.d.ts +16 -0
  119. package/runtime-plugin.js +16 -0
  120. package/runtime-plugin.js.map +9 -0
  121. package/syntax-style.d.ts +54 -0
  122. package/testing/manual-clock.d.ts +17 -0
  123. package/testing/mock-keys.d.ts +81 -0
  124. package/testing/mock-mouse.d.ts +38 -0
  125. package/testing/mock-tree-sitter-client.d.ts +23 -0
  126. package/testing/spy.d.ts +7 -0
  127. package/testing/test-recorder.d.ts +61 -0
  128. package/testing/test-renderer.d.ts +23 -0
  129. package/testing.d.ts +6 -0
  130. package/testing.js +697 -0
  131. package/testing.js.map +15 -0
  132. package/text-buffer-view.d.ts +42 -0
  133. package/text-buffer.d.ts +67 -0
  134. package/types.d.ts +139 -0
  135. package/utils.d.ts +14 -0
  136. package/zig-structs.d.ts +155 -0
  137. package/zig.d.ts +353 -0
  138. package/dev/keypress-debug-renderer.ts +0 -148
  139. package/dev/keypress-debug.ts +0 -43
  140. package/dev/print-env-vars.ts +0 -32
  141. package/dev/test-tmux-graphics-334.sh +0 -68
  142. package/dev/thai-debug-test.ts +0 -68
  143. package/docs/development.md +0 -144
  144. package/scripts/build.ts +0 -400
  145. package/scripts/publish.ts +0 -60
  146. package/src/3d/SpriteResourceManager.ts +0 -286
  147. package/src/3d/SpriteUtils.ts +0 -70
  148. package/src/3d/TextureUtils.ts +0 -196
  149. package/src/3d/ThreeRenderable.ts +0 -197
  150. package/src/3d/WGPURenderer.ts +0 -294
  151. package/src/3d/animation/ExplodingSpriteEffect.ts +0 -513
  152. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +0 -429
  153. package/src/3d/animation/SpriteAnimator.ts +0 -633
  154. package/src/3d/animation/SpriteParticleGenerator.ts +0 -435
  155. package/src/3d/canvas.ts +0 -464
  156. package/src/3d/index.ts +0 -12
  157. package/src/3d/physics/PlanckPhysicsAdapter.ts +0 -72
  158. package/src/3d/physics/RapierPhysicsAdapter.ts +0 -66
  159. package/src/3d/physics/physics-interface.ts +0 -31
  160. package/src/3d/shaders/supersampling.wgsl +0 -201
  161. package/src/3d.ts +0 -3
  162. package/src/NativeSpanFeed.ts +0 -300
  163. package/src/Renderable.ts +0 -1704
  164. package/src/__snapshots__/buffer.test.ts.snap +0 -28
  165. package/src/animation/Timeline.test.ts +0 -2709
  166. package/src/animation/Timeline.ts +0 -598
  167. package/src/ansi.ts +0 -18
  168. package/src/benchmark/attenuation-benchmark.ts +0 -81
  169. package/src/benchmark/colormatrix-benchmark.ts +0 -128
  170. package/src/benchmark/gain-benchmark.ts +0 -80
  171. package/src/benchmark/latest-all-bench-run.json +0 -707
  172. package/src/benchmark/latest-async-bench-run.json +0 -336
  173. package/src/benchmark/latest-default-bench-run.json +0 -657
  174. package/src/benchmark/latest-large-bench-run.json +0 -707
  175. package/src/benchmark/latest-quick-bench-run.json +0 -207
  176. package/src/benchmark/markdown-benchmark.ts +0 -1796
  177. package/src/benchmark/native-span-feed-async-benchmark.ts +0 -355
  178. package/src/benchmark/native-span-feed-benchmark.md +0 -56
  179. package/src/benchmark/native-span-feed-benchmark.ts +0 -596
  180. package/src/benchmark/native-span-feed-compare.ts +0 -280
  181. package/src/benchmark/renderer-benchmark.ts +0 -754
  182. package/src/benchmark/text-table-benchmark.ts +0 -948
  183. package/src/buffer.test.ts +0 -291
  184. package/src/buffer.ts +0 -554
  185. package/src/console.test.ts +0 -612
  186. package/src/console.ts +0 -1254
  187. package/src/edit-buffer.test.ts +0 -1769
  188. package/src/edit-buffer.ts +0 -411
  189. package/src/editor-view.test.ts +0 -1032
  190. package/src/editor-view.ts +0 -284
  191. package/src/examples/ascii-font-selection-demo.ts +0 -245
  192. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  193. package/src/examples/assets/concrete.png +0 -0
  194. package/src/examples/assets/crate.png +0 -0
  195. package/src/examples/assets/crate_emissive.png +0 -0
  196. package/src/examples/assets/forrest_background.png +0 -0
  197. package/src/examples/assets/hast-example.json +0 -1018
  198. package/src/examples/assets/heart.png +0 -0
  199. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  200. package/src/examples/assets/main_char_idle.png +0 -0
  201. package/src/examples/assets/main_char_jump_end.png +0 -0
  202. package/src/examples/assets/main_char_jump_landing.png +0 -0
  203. package/src/examples/assets/main_char_jump_start.png +0 -0
  204. package/src/examples/assets/main_char_run_loop.png +0 -0
  205. package/src/examples/assets/roughness_map.jpg +0 -0
  206. package/src/examples/build.ts +0 -115
  207. package/src/examples/code-demo.ts +0 -924
  208. package/src/examples/console-demo.ts +0 -358
  209. package/src/examples/core-plugin-slots-demo.ts +0 -759
  210. package/src/examples/diff-demo.ts +0 -701
  211. package/src/examples/draggable-three-demo.ts +0 -259
  212. package/src/examples/editor-demo.ts +0 -322
  213. package/src/examples/extmarks-demo.ts +0 -196
  214. package/src/examples/focus-restore-demo.ts +0 -310
  215. package/src/examples/fonts.ts +0 -245
  216. package/src/examples/fractal-shader-demo.ts +0 -268
  217. package/src/examples/framebuffer-demo.ts +0 -674
  218. package/src/examples/full-unicode-demo.ts +0 -241
  219. package/src/examples/golden-star-demo.ts +0 -933
  220. package/src/examples/grayscale-buffer-demo.ts +0 -249
  221. package/src/examples/hast-syntax-highlighting-demo.ts +0 -129
  222. package/src/examples/index.ts +0 -926
  223. package/src/examples/input-demo.ts +0 -377
  224. package/src/examples/input-select-layout-demo.ts +0 -425
  225. package/src/examples/install.sh +0 -143
  226. package/src/examples/keypress-debug-demo.ts +0 -452
  227. package/src/examples/lib/HexList.ts +0 -122
  228. package/src/examples/lib/PaletteGrid.ts +0 -125
  229. package/src/examples/lib/standalone-keys.ts +0 -25
  230. package/src/examples/lib/tab-controller.ts +0 -243
  231. package/src/examples/lights-phong-demo.ts +0 -290
  232. package/src/examples/link-demo.ts +0 -220
  233. package/src/examples/live-state-demo.ts +0 -480
  234. package/src/examples/markdown-demo.ts +0 -725
  235. package/src/examples/mouse-interaction-demo.ts +0 -428
  236. package/src/examples/nested-zindex-demo.ts +0 -357
  237. package/src/examples/opacity-example.ts +0 -235
  238. package/src/examples/opentui-demo.ts +0 -1057
  239. package/src/examples/physx-planck-2d-demo.ts +0 -623
  240. package/src/examples/physx-rapier-2d-demo.ts +0 -655
  241. package/src/examples/relative-positioning-demo.ts +0 -323
  242. package/src/examples/scroll-example.ts +0 -214
  243. package/src/examples/scrollbox-mouse-test.ts +0 -112
  244. package/src/examples/scrollbox-overlay-hit-test.ts +0 -206
  245. package/src/examples/select-demo.ts +0 -237
  246. package/src/examples/shader-cube-demo.ts +0 -1015
  247. package/src/examples/simple-layout-example.ts +0 -591
  248. package/src/examples/slider-demo.ts +0 -617
  249. package/src/examples/split-mode-demo.ts +0 -453
  250. package/src/examples/sprite-animation-demo.ts +0 -443
  251. package/src/examples/sprite-particle-generator-demo.ts +0 -486
  252. package/src/examples/static-sprite-demo.ts +0 -193
  253. package/src/examples/sticky-scroll-example.ts +0 -308
  254. package/src/examples/styled-text-demo.ts +0 -282
  255. package/src/examples/tab-select-demo.ts +0 -219
  256. package/src/examples/terminal-title.ts +0 -29
  257. package/src/examples/terminal.ts +0 -305
  258. package/src/examples/text-node-demo.ts +0 -416
  259. package/src/examples/text-selection-demo.ts +0 -377
  260. package/src/examples/text-table-demo.ts +0 -503
  261. package/src/examples/text-truncation-demo.ts +0 -481
  262. package/src/examples/text-wrap.ts +0 -757
  263. package/src/examples/texture-loading-demo.ts +0 -259
  264. package/src/examples/timeline-example.ts +0 -670
  265. package/src/examples/transparency-demo.ts +0 -400
  266. package/src/examples/vnode-composition-demo.ts +0 -404
  267. package/src/examples/wide-grapheme-overlay-demo.ts +0 -280
  268. package/src/index.ts +0 -24
  269. package/src/lib/KeyHandler.integration.test.ts +0 -292
  270. package/src/lib/KeyHandler.stopPropagation.test.ts +0 -289
  271. package/src/lib/KeyHandler.test.ts +0 -662
  272. package/src/lib/KeyHandler.ts +0 -222
  273. package/src/lib/RGBA.test.ts +0 -984
  274. package/src/lib/RGBA.ts +0 -204
  275. package/src/lib/ascii.font.ts +0 -330
  276. package/src/lib/border.test.ts +0 -83
  277. package/src/lib/border.ts +0 -170
  278. package/src/lib/bunfs.test.ts +0 -27
  279. package/src/lib/bunfs.ts +0 -18
  280. package/src/lib/clipboard.test.ts +0 -41
  281. package/src/lib/clipboard.ts +0 -47
  282. package/src/lib/clock.ts +0 -35
  283. package/src/lib/data-paths.test.ts +0 -133
  284. package/src/lib/data-paths.ts +0 -109
  285. package/src/lib/debounce.ts +0 -106
  286. package/src/lib/detect-links.test.ts +0 -98
  287. package/src/lib/detect-links.ts +0 -56
  288. package/src/lib/env.test.ts +0 -228
  289. package/src/lib/env.ts +0 -209
  290. package/src/lib/extmarks-history.ts +0 -51
  291. package/src/lib/extmarks-multiwidth.test.ts +0 -322
  292. package/src/lib/extmarks.test.ts +0 -3457
  293. package/src/lib/extmarks.ts +0 -843
  294. package/src/lib/fonts/block.json +0 -405
  295. package/src/lib/fonts/grid.json +0 -265
  296. package/src/lib/fonts/huge.json +0 -741
  297. package/src/lib/fonts/pallet.json +0 -314
  298. package/src/lib/fonts/shade.json +0 -591
  299. package/src/lib/fonts/slick.json +0 -321
  300. package/src/lib/fonts/tiny.json +0 -69
  301. package/src/lib/hast-styled-text.ts +0 -59
  302. package/src/lib/index.ts +0 -21
  303. package/src/lib/keymapping.test.ts +0 -317
  304. package/src/lib/keymapping.ts +0 -115
  305. package/src/lib/objects-in-viewport.test.ts +0 -787
  306. package/src/lib/objects-in-viewport.ts +0 -153
  307. package/src/lib/output.capture.ts +0 -58
  308. package/src/lib/parse.keypress-kitty.protocol.test.ts +0 -340
  309. package/src/lib/parse.keypress-kitty.test.ts +0 -663
  310. package/src/lib/parse.keypress-kitty.ts +0 -439
  311. package/src/lib/parse.keypress.test.ts +0 -1849
  312. package/src/lib/parse.keypress.ts +0 -397
  313. package/src/lib/parse.mouse.test.ts +0 -552
  314. package/src/lib/parse.mouse.ts +0 -232
  315. package/src/lib/paste.ts +0 -16
  316. package/src/lib/queue.ts +0 -65
  317. package/src/lib/renderable.validations.test.ts +0 -87
  318. package/src/lib/renderable.validations.ts +0 -83
  319. package/src/lib/scroll-acceleration.ts +0 -98
  320. package/src/lib/selection.ts +0 -240
  321. package/src/lib/singleton.ts +0 -28
  322. package/src/lib/stdin-parser.test.ts +0 -2290
  323. package/src/lib/stdin-parser.ts +0 -1810
  324. package/src/lib/styled-text.ts +0 -178
  325. package/src/lib/terminal-capability-detection.test.ts +0 -202
  326. package/src/lib/terminal-capability-detection.ts +0 -79
  327. package/src/lib/terminal-palette.test.ts +0 -878
  328. package/src/lib/terminal-palette.ts +0 -383
  329. package/src/lib/tree-sitter/assets/README.md +0 -118
  330. package/src/lib/tree-sitter/assets/update.ts +0 -334
  331. package/src/lib/tree-sitter/assets.d.ts +0 -9
  332. package/src/lib/tree-sitter/cache.test.ts +0 -273
  333. package/src/lib/tree-sitter/client.test.ts +0 -1165
  334. package/src/lib/tree-sitter/client.ts +0 -607
  335. package/src/lib/tree-sitter/default-parsers.ts +0 -86
  336. package/src/lib/tree-sitter/download-utils.ts +0 -148
  337. package/src/lib/tree-sitter/index.ts +0 -28
  338. package/src/lib/tree-sitter/parser.worker.ts +0 -1042
  339. package/src/lib/tree-sitter/parsers-config.ts +0 -81
  340. package/src/lib/tree-sitter/resolve-ft.test.ts +0 -55
  341. package/src/lib/tree-sitter/resolve-ft.ts +0 -189
  342. package/src/lib/tree-sitter/types.ts +0 -82
  343. package/src/lib/tree-sitter-styled-text.test.ts +0 -1253
  344. package/src/lib/tree-sitter-styled-text.ts +0 -306
  345. package/src/lib/validate-dir-name.ts +0 -55
  346. package/src/lib/yoga.options.test.ts +0 -628
  347. package/src/lib/yoga.options.ts +0 -346
  348. package/src/plugins/core-slot.ts +0 -579
  349. package/src/plugins/registry.ts +0 -402
  350. package/src/plugins/types.ts +0 -46
  351. package/src/post/effects.ts +0 -930
  352. package/src/post/filters.ts +0 -489
  353. package/src/post/matrices.ts +0 -288
  354. package/src/renderables/ASCIIFont.ts +0 -219
  355. package/src/renderables/Box.test.ts +0 -205
  356. package/src/renderables/Box.ts +0 -326
  357. package/src/renderables/Code.test.ts +0 -2062
  358. package/src/renderables/Code.ts +0 -357
  359. package/src/renderables/Diff.regression.test.ts +0 -226
  360. package/src/renderables/Diff.test.ts +0 -3101
  361. package/src/renderables/Diff.ts +0 -1211
  362. package/src/renderables/EditBufferRenderable.test.ts +0 -288
  363. package/src/renderables/EditBufferRenderable.ts +0 -1166
  364. package/src/renderables/FrameBuffer.ts +0 -47
  365. package/src/renderables/Input.test.ts +0 -1228
  366. package/src/renderables/Input.ts +0 -247
  367. package/src/renderables/LineNumberRenderable.ts +0 -724
  368. package/src/renderables/Markdown.ts +0 -1393
  369. package/src/renderables/ScrollBar.ts +0 -422
  370. package/src/renderables/ScrollBox.ts +0 -883
  371. package/src/renderables/Select.test.ts +0 -1033
  372. package/src/renderables/Select.ts +0 -524
  373. package/src/renderables/Slider.test.ts +0 -456
  374. package/src/renderables/Slider.ts +0 -342
  375. package/src/renderables/TabSelect.test.ts +0 -197
  376. package/src/renderables/TabSelect.ts +0 -455
  377. package/src/renderables/Text.selection-buffer.test.ts +0 -123
  378. package/src/renderables/Text.test.ts +0 -2660
  379. package/src/renderables/Text.ts +0 -147
  380. package/src/renderables/TextBufferRenderable.ts +0 -518
  381. package/src/renderables/TextNode.test.ts +0 -1058
  382. package/src/renderables/TextNode.ts +0 -325
  383. package/src/renderables/TextTable.test.ts +0 -1421
  384. package/src/renderables/TextTable.ts +0 -1344
  385. package/src/renderables/Textarea.ts +0 -430
  386. package/src/renderables/TimeToFirstDraw.ts +0 -89
  387. package/src/renderables/__snapshots__/Code.test.ts.snap +0 -13
  388. package/src/renderables/__snapshots__/Diff.test.ts.snap +0 -785
  389. package/src/renderables/__snapshots__/Text.test.ts.snap +0 -421
  390. package/src/renderables/__snapshots__/TextTable.test.ts.snap +0 -215
  391. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +0 -144
  392. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +0 -816
  393. package/src/renderables/__tests__/LineNumberRenderable.test.ts +0 -1865
  394. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +0 -85
  395. package/src/renderables/__tests__/Markdown.code-colors.test.ts +0 -242
  396. package/src/renderables/__tests__/Markdown.test.ts +0 -2518
  397. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +0 -87
  398. package/src/renderables/__tests__/Textarea.buffer.test.ts +0 -682
  399. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +0 -675
  400. package/src/renderables/__tests__/Textarea.editing.test.ts +0 -2041
  401. package/src/renderables/__tests__/Textarea.error-handling.test.ts +0 -35
  402. package/src/renderables/__tests__/Textarea.events.test.ts +0 -738
  403. package/src/renderables/__tests__/Textarea.highlights.test.ts +0 -590
  404. package/src/renderables/__tests__/Textarea.keybinding.test.ts +0 -3149
  405. package/src/renderables/__tests__/Textarea.paste.test.ts +0 -357
  406. package/src/renderables/__tests__/Textarea.rendering.test.ts +0 -1866
  407. package/src/renderables/__tests__/Textarea.scroll.test.ts +0 -733
  408. package/src/renderables/__tests__/Textarea.selection.test.ts +0 -1590
  409. package/src/renderables/__tests__/Textarea.stress.test.ts +0 -670
  410. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +0 -383
  411. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +0 -310
  412. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +0 -221
  413. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +0 -89
  414. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +0 -457
  415. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +0 -158
  416. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +0 -387
  417. package/src/renderables/__tests__/markdown-parser.test.ts +0 -217
  418. package/src/renderables/__tests__/renderable-test-utils.ts +0 -60
  419. package/src/renderables/composition/README.md +0 -8
  420. package/src/renderables/composition/VRenderable.ts +0 -32
  421. package/src/renderables/composition/constructs.ts +0 -127
  422. package/src/renderables/composition/vnode.ts +0 -289
  423. package/src/renderables/index.ts +0 -23
  424. package/src/renderables/markdown-parser.ts +0 -66
  425. package/src/renderer.ts +0 -2681
  426. package/src/runtime-plugin-support.ts +0 -39
  427. package/src/runtime-plugin.ts +0 -615
  428. package/src/syntax-style.test.ts +0 -841
  429. package/src/syntax-style.ts +0 -257
  430. package/src/testing/README.md +0 -210
  431. package/src/testing/capture-spans.test.ts +0 -194
  432. package/src/testing/integration.test.ts +0 -276
  433. package/src/testing/manual-clock.ts +0 -117
  434. package/src/testing/mock-keys.test.ts +0 -1378
  435. package/src/testing/mock-keys.ts +0 -457
  436. package/src/testing/mock-mouse.test.ts +0 -218
  437. package/src/testing/mock-mouse.ts +0 -247
  438. package/src/testing/mock-tree-sitter-client.ts +0 -73
  439. package/src/testing/spy.ts +0 -13
  440. package/src/testing/test-recorder.test.ts +0 -415
  441. package/src/testing/test-recorder.ts +0 -145
  442. package/src/testing/test-renderer.ts +0 -132
  443. package/src/testing.ts +0 -7
  444. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +0 -481
  445. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +0 -19
  446. package/src/tests/__snapshots__/scrollbox.test.ts.snap +0 -29
  447. package/src/tests/absolute-positioning.snapshot.test.ts +0 -638
  448. package/src/tests/allocator-stats.test.ts +0 -38
  449. package/src/tests/destroy-during-render.test.ts +0 -200
  450. package/src/tests/destroy-on-exit.fixture.ts +0 -36
  451. package/src/tests/destroy-on-exit.test.ts +0 -41
  452. package/src/tests/hover-cursor.test.ts +0 -98
  453. package/src/tests/native-span-feed-async.test.ts +0 -173
  454. package/src/tests/native-span-feed-close.test.ts +0 -120
  455. package/src/tests/native-span-feed-coverage.test.ts +0 -227
  456. package/src/tests/native-span-feed-edge-cases.test.ts +0 -352
  457. package/src/tests/native-span-feed-use-after-free.test.ts +0 -45
  458. package/src/tests/opacity.test.ts +0 -123
  459. package/src/tests/renderable.snapshot.test.ts +0 -524
  460. package/src/tests/renderable.test.ts +0 -1281
  461. package/src/tests/renderer.clock.test.ts +0 -158
  462. package/src/tests/renderer.console-startup.test.ts +0 -185
  463. package/src/tests/renderer.control.test.ts +0 -425
  464. package/src/tests/renderer.core-slot-binding.test.ts +0 -952
  465. package/src/tests/renderer.cursor.test.ts +0 -26
  466. package/src/tests/renderer.destroy-during-render.test.ts +0 -147
  467. package/src/tests/renderer.focus-restore.test.ts +0 -257
  468. package/src/tests/renderer.focus.test.ts +0 -294
  469. package/src/tests/renderer.idle.test.ts +0 -219
  470. package/src/tests/renderer.input.test.ts +0 -2237
  471. package/src/tests/renderer.kitty-flags.test.ts +0 -195
  472. package/src/tests/renderer.mouse.test.ts +0 -1274
  473. package/src/tests/renderer.palette.test.ts +0 -629
  474. package/src/tests/renderer.selection.test.ts +0 -49
  475. package/src/tests/renderer.slot-registry.test.ts +0 -684
  476. package/src/tests/renderer.useMouse.test.ts +0 -47
  477. package/src/tests/runtime-plugin-node-modules-cycle.fixture.ts +0 -76
  478. package/src/tests/runtime-plugin-node-modules-mjs.fixture.ts +0 -43
  479. package/src/tests/runtime-plugin-node-modules-no-bare-rewrite.fixture.ts +0 -67
  480. package/src/tests/runtime-plugin-node-modules-package-type-cache.fixture.ts +0 -72
  481. package/src/tests/runtime-plugin-node-modules-runtime-specifier.fixture.ts +0 -44
  482. package/src/tests/runtime-plugin-node-modules-scoped-package-bare-rewrite.fixture.ts +0 -85
  483. package/src/tests/runtime-plugin-path-alias.fixture.ts +0 -43
  484. package/src/tests/runtime-plugin-resolve-roots.fixture.ts +0 -65
  485. package/src/tests/runtime-plugin-support.fixture.ts +0 -11
  486. package/src/tests/runtime-plugin-support.test.ts +0 -19
  487. package/src/tests/runtime-plugin-windows-file-url.fixture.ts +0 -30
  488. package/src/tests/runtime-plugin.fixture.ts +0 -40
  489. package/src/tests/runtime-plugin.test.ts +0 -354
  490. package/src/tests/scrollbox-culling-bug.test.ts +0 -114
  491. package/src/tests/scrollbox-hitgrid-resize.test.ts +0 -136
  492. package/src/tests/scrollbox-hitgrid.test.ts +0 -909
  493. package/src/tests/scrollbox.test.ts +0 -1530
  494. package/src/tests/wrap-resize-perf.test.ts +0 -276
  495. package/src/tests/yoga-setters.test.ts +0 -921
  496. package/src/text-buffer-view.test.ts +0 -705
  497. package/src/text-buffer-view.ts +0 -189
  498. package/src/text-buffer.test.ts +0 -347
  499. package/src/text-buffer.ts +0 -250
  500. package/src/types.ts +0 -161
  501. package/src/utils.ts +0 -88
  502. package/src/zig/ansi.zig +0 -268
  503. package/src/zig/bench/README.md +0 -50
  504. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +0 -887
  505. package/src/zig/bench/edit-buffer_bench.zig +0 -476
  506. package/src/zig/bench/native-span-feed_bench.zig +0 -100
  507. package/src/zig/bench/rope-markers_bench.zig +0 -713
  508. package/src/zig/bench/rope_bench.zig +0 -514
  509. package/src/zig/bench/styled-text_bench.zig +0 -470
  510. package/src/zig/bench/text-buffer-coords_bench.zig +0 -362
  511. package/src/zig/bench/text-buffer-view_bench.zig +0 -459
  512. package/src/zig/bench/text-chunk-graphemes_bench.zig +0 -273
  513. package/src/zig/bench/utf8_bench.zig +0 -799
  514. package/src/zig/bench-utils.zig +0 -431
  515. package/src/zig/bench.zig +0 -217
  516. package/src/zig/buffer-methods.zig +0 -211
  517. package/src/zig/buffer.zig +0 -2281
  518. package/src/zig/build.zig +0 -289
  519. package/src/zig/build.zig.zon +0 -16
  520. package/src/zig/edit-buffer.zig +0 -825
  521. package/src/zig/editor-view.zig +0 -802
  522. package/src/zig/event-bus.zig +0 -13
  523. package/src/zig/event-emitter.zig +0 -65
  524. package/src/zig/file-logger.zig +0 -92
  525. package/src/zig/grapheme.zig +0 -599
  526. package/src/zig/lib.zig +0 -1854
  527. package/src/zig/link.zig +0 -333
  528. package/src/zig/logger.zig +0 -43
  529. package/src/zig/mem-registry.zig +0 -125
  530. package/src/zig/native-span-feed-bench-lib.zig +0 -7
  531. package/src/zig/native-span-feed.zig +0 -708
  532. package/src/zig/renderer.zig +0 -1393
  533. package/src/zig/rope.zig +0 -1220
  534. package/src/zig/syntax-style.zig +0 -161
  535. package/src/zig/terminal.zig +0 -987
  536. package/src/zig/test.zig +0 -72
  537. package/src/zig/tests/README.md +0 -18
  538. package/src/zig/tests/buffer-methods_test.zig +0 -1109
  539. package/src/zig/tests/buffer_test.zig +0 -2557
  540. package/src/zig/tests/edit-buffer-history_test.zig +0 -271
  541. package/src/zig/tests/edit-buffer_test.zig +0 -1689
  542. package/src/zig/tests/editor-view_test.zig +0 -3299
  543. package/src/zig/tests/event-emitter_test.zig +0 -249
  544. package/src/zig/tests/grapheme_test.zig +0 -1304
  545. package/src/zig/tests/link_test.zig +0 -190
  546. package/src/zig/tests/mem-registry_test.zig +0 -473
  547. package/src/zig/tests/memory_leak_regression_test.zig +0 -159
  548. package/src/zig/tests/native-span-feed_test.zig +0 -1264
  549. package/src/zig/tests/renderer_test.zig +0 -1017
  550. package/src/zig/tests/rope-nested_test.zig +0 -712
  551. package/src/zig/tests/rope_fuzz_test.zig +0 -238
  552. package/src/zig/tests/rope_test.zig +0 -2362
  553. package/src/zig/tests/segment-merge.test.zig +0 -148
  554. package/src/zig/tests/syntax-style_test.zig +0 -557
  555. package/src/zig/tests/terminal_test.zig +0 -754
  556. package/src/zig/tests/text-buffer-drawing_test.zig +0 -3237
  557. package/src/zig/tests/text-buffer-highlights_test.zig +0 -666
  558. package/src/zig/tests/text-buffer-iterators_test.zig +0 -776
  559. package/src/zig/tests/text-buffer-segment_test.zig +0 -320
  560. package/src/zig/tests/text-buffer-selection_test.zig +0 -1035
  561. package/src/zig/tests/text-buffer-selection_viewport_test.zig +0 -358
  562. package/src/zig/tests/text-buffer-view_test.zig +0 -3649
  563. package/src/zig/tests/text-buffer_test.zig +0 -2191
  564. package/src/zig/tests/unicode-width-map.zon +0 -3909
  565. package/src/zig/tests/utf8_no_zwj_test.zig +0 -260
  566. package/src/zig/tests/utf8_test.zig +0 -4057
  567. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +0 -267
  568. package/src/zig/tests/utf8_wcwidth_test.zig +0 -357
  569. package/src/zig/tests/word-wrap-editing_test.zig +0 -498
  570. package/src/zig/tests/wrap-cache-perf_test.zig +0 -113
  571. package/src/zig/text-buffer-iterators.zig +0 -499
  572. package/src/zig/text-buffer-segment.zig +0 -404
  573. package/src/zig/text-buffer-view.zig +0 -1371
  574. package/src/zig/text-buffer.zig +0 -1180
  575. package/src/zig/utf8.zig +0 -1948
  576. package/src/zig/utils.zig +0 -9
  577. package/src/zig-structs.ts +0 -261
  578. package/src/zig.ts +0 -3884
  579. package/tsconfig.build.json +0 -24
  580. package/tsconfig.json +0 -27
  581. /package/{src/lib/tree-sitter/assets → assets}/javascript/highlights.scm +0 -0
  582. /package/{src/lib/tree-sitter/assets → assets}/javascript/tree-sitter-javascript.wasm +0 -0
  583. /package/{src/lib/tree-sitter/assets → assets}/markdown/highlights.scm +0 -0
  584. /package/{src/lib/tree-sitter/assets → assets}/markdown/injections.scm +0 -0
  585. /package/{src/lib/tree-sitter/assets → assets}/markdown/tree-sitter-markdown.wasm +0 -0
  586. /package/{src/lib/tree-sitter/assets → assets}/markdown_inline/highlights.scm +0 -0
  587. /package/{src/lib/tree-sitter/assets → assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  588. /package/{src/lib/tree-sitter/assets → assets}/typescript/highlights.scm +0 -0
  589. /package/{src/lib/tree-sitter/assets → assets}/typescript/tree-sitter-typescript.wasm +0 -0
  590. /package/{src/lib/tree-sitter/assets → assets}/zig/highlights.scm +0 -0
  591. /package/{src/lib/tree-sitter/assets → assets}/zig/tree-sitter-zig.wasm +0 -0
@@ -1,1253 +0,0 @@
1
- import { test, expect, beforeAll, afterAll, describe } from "bun:test"
2
- import { TreeSitterClient } from "./tree-sitter/client.js"
3
- import { treeSitterToStyledText, treeSitterToTextChunks } from "./tree-sitter-styled-text.js"
4
- import { SyntaxStyle } from "../syntax-style.js"
5
- import { RGBA } from "./RGBA.js"
6
- import { createTextAttributes } from "../utils.js"
7
- import { tmpdir } from "os"
8
- import { join } from "path"
9
- import { mkdir } from "fs/promises"
10
- import type { SimpleHighlight } from "./tree-sitter/types.js"
11
-
12
- describe("TreeSitter Styled Text", () => {
13
- let client: TreeSitterClient
14
- let syntaxStyle: SyntaxStyle
15
- const dataPath = join(tmpdir(), "tree-sitter-styled-text-test")
16
-
17
- beforeAll(async () => {
18
- await mkdir(dataPath, { recursive: true })
19
- client = new TreeSitterClient({ dataPath })
20
- await client.initialize()
21
-
22
- // Create a syntax style similar to common themes
23
- syntaxStyle = SyntaxStyle.fromStyles({
24
- default: { fg: RGBA.fromInts(255, 255, 255, 255) }, // white
25
- keyword: { fg: RGBA.fromInts(255, 100, 100, 255), bold: true }, // red bold
26
- string: { fg: RGBA.fromInts(100, 255, 100, 255) }, // green
27
- number: { fg: RGBA.fromInts(100, 100, 255, 255) }, // blue
28
- function: { fg: RGBA.fromInts(255, 255, 100, 255), italic: true }, // yellow italic
29
- comment: { fg: RGBA.fromInts(128, 128, 128, 255), italic: true }, // gray italic
30
- variable: { fg: RGBA.fromInts(200, 200, 255, 255) }, // light blue
31
- type: { fg: RGBA.fromInts(255, 200, 100, 255) }, // orange
32
- "markup.heading": { fg: RGBA.fromInts(255, 200, 200, 255), bold: true }, // light red bold
33
- "markup.strong": { bold: true }, // bold
34
- "markup.italic": { italic: true }, // italic
35
- "markup.raw": { fg: RGBA.fromInts(200, 255, 200, 255) }, // light green
36
- "markup.quote": { fg: RGBA.fromInts(180, 180, 180, 255), italic: true }, // gray italic
37
- "markup.list": { fg: RGBA.fromInts(255, 200, 100, 255) }, // orange
38
- })
39
- })
40
-
41
- afterAll(async () => {
42
- await client.destroy()
43
- syntaxStyle.destroy()
44
- })
45
-
46
- test("should convert JavaScript code to styled text", async () => {
47
- const jsCode = 'const greeting = "Hello, world!";\nfunction test() { return 42; }'
48
-
49
- const styledText = await treeSitterToStyledText(jsCode, "javascript", syntaxStyle, client)
50
-
51
- expect(styledText).toBeDefined()
52
-
53
- const chunks = styledText.chunks
54
- expect(chunks.length).toBeGreaterThan(1) // Should have multiple styled chunks
55
-
56
- const chunksWithColor = chunks.filter((chunk) => chunk.fg)
57
- expect(chunksWithColor.length).toBeGreaterThan(0) // Some chunks should have colors
58
- })
59
-
60
- test("should convert TypeScript code to styled text", async () => {
61
- const tsCode = "interface User {\n name: string;\n age: number;\n}"
62
-
63
- const styledText = await treeSitterToStyledText(tsCode, "typescript", syntaxStyle, client)
64
-
65
- expect(styledText).toBeDefined()
66
-
67
- const chunks = styledText.chunks
68
- expect(chunks.length).toBeGreaterThan(1)
69
-
70
- const styledChunks = chunks.filter((chunk) => chunk.fg)
71
- expect(styledChunks.length).toBeGreaterThan(0)
72
- })
73
-
74
- test("should handle unsupported filetype gracefully", async () => {
75
- const content = "some random content"
76
-
77
- const styledText = await treeSitterToStyledText(content, "unsupported", syntaxStyle, client)
78
-
79
- expect(styledText).toBeDefined()
80
-
81
- const chunks = styledText.chunks
82
- expect(chunks).toHaveLength(1)
83
- expect(chunks[0].text).toBe(content)
84
-
85
- expect(chunks[0].fg).toBeDefined()
86
- })
87
-
88
- test("should handle empty content", async () => {
89
- const styledText = await treeSitterToStyledText("", "javascript", syntaxStyle, client)
90
-
91
- expect(styledText).toBeDefined()
92
-
93
- const chunks = styledText.chunks
94
- expect(chunks).toHaveLength(1)
95
- expect(chunks[0].text).toBe("")
96
- })
97
-
98
- test("should handle multiline content correctly", async () => {
99
- const multilineCode = `// This is a comment
100
- const value = 123;
101
- const text = "hello";
102
- function add(a, b) {
103
- return a + b;
104
- }`
105
-
106
- const styledText = await treeSitterToStyledText(multilineCode, "javascript", syntaxStyle, client)
107
-
108
- expect(styledText).toBeDefined()
109
-
110
- const chunks = styledText.chunks
111
- expect(chunks.length).toBeGreaterThan(5) // Multiple chunks for different elements
112
-
113
- // Should contain newlines
114
- const newlineChunks = chunks.filter((chunk) => chunk.text.includes("\n"))
115
- expect(newlineChunks.length).toBeGreaterThan(0)
116
- })
117
-
118
- test("should preserve original text content", async () => {
119
- const originalCode = 'const test = "preserve this exact text";'
120
-
121
- const styledText = await treeSitterToStyledText(originalCode, "javascript", syntaxStyle, client)
122
-
123
- const reconstructed = styledText.chunks.map((chunk) => chunk.text).join("")
124
- expect(reconstructed).toBe(originalCode)
125
- })
126
-
127
- test("should apply different styles to different syntax elements", async () => {
128
- const jsCode = "const number = 42; // comment"
129
-
130
- const styledText = await treeSitterToStyledText(jsCode, "javascript", syntaxStyle, client)
131
- const chunks = styledText.chunks
132
-
133
- // Should have some chunks with colors
134
- const chunksWithColors = chunks.filter((chunk) => chunk.fg)
135
- expect(chunksWithColors.length).toBeGreaterThan(0)
136
-
137
- // Should have some chunks with attributes (bold, italic, etc.)
138
- const chunksWithAttributes = chunks.filter((chunk) => chunk.attributes && chunk.attributes > 0)
139
- expect(chunksWithAttributes.length).toBeGreaterThan(0)
140
- })
141
-
142
- test("should handle template literals correctly without duplication", async () => {
143
- const templateLiteralCode = "console.log(`Total users: ${manager.getUserCount()}`);"
144
-
145
- const styledText = await treeSitterToStyledText(templateLiteralCode, "javascript", syntaxStyle, client)
146
- const chunks = styledText.chunks
147
-
148
- // Reconstruct the text from chunks to check for duplication
149
- const reconstructed = chunks.map((chunk) => chunk.text).join("")
150
-
151
- expect(reconstructed).toBe(templateLiteralCode)
152
-
153
- expect(chunks.length).toBeGreaterThan(1)
154
-
155
- const styledChunks = chunks.filter((chunk) => chunk.fg)
156
- expect(styledChunks.length).toBeGreaterThan(0)
157
- })
158
-
159
- test("should handle complex template literals with multiple expressions", async () => {
160
- const complexTemplateCode =
161
- 'console.log(`User: ${user.name}, Age: ${user.age}, Status: ${user.active ? "active" : "inactive"}`);'
162
-
163
- const styledText = await treeSitterToStyledText(complexTemplateCode, "javascript", syntaxStyle, client)
164
- const chunks = styledText.chunks
165
-
166
- const reconstructed = chunks.map((chunk) => chunk.text).join("")
167
-
168
- expect(reconstructed).toBe(complexTemplateCode)
169
- })
170
-
171
- test("should correctly highlight template literal with embedded expressions", async () => {
172
- const templateLiteralCode = "console.log(`Total users: ${manager.getUserCount()}`);"
173
-
174
- const result = await client.highlightOnce(templateLiteralCode, "javascript")
175
-
176
- expect(result.highlights).toBeDefined()
177
- expect(result.highlights!.length).toBeGreaterThan(0)
178
-
179
- const groups = result.highlights!.map(([, , group]) => group)
180
- expect(groups).toContain("variable") // console, manager
181
- expect(groups).toContain("property") // log, getUserCount
182
- expect(groups).toContain("string") // template literal
183
- expect(groups).toContain("embedded") // ${...} expression
184
- expect(groups).toContain("punctuation.bracket") // (), {}
185
-
186
- const styledText = await treeSitterToStyledText(templateLiteralCode, "javascript", syntaxStyle, client)
187
- const chunks = styledText.chunks
188
-
189
- expect(chunks.length).toBeGreaterThan(5)
190
-
191
- const reconstructed = chunks.map((chunk) => chunk.text).join("")
192
- expect(reconstructed).toBe(templateLiteralCode)
193
-
194
- const styledChunks = chunks.filter((chunk) => chunk.fg !== syntaxStyle.mergeStyles("default").fg)
195
- expect(styledChunks.length).toBeGreaterThan(0) // Some chunks should be styled differently
196
- })
197
-
198
- test("should work with real tree-sitter output containing dot-delimited groups", async () => {
199
- const tsCode = "interface User { name: string; age?: number; }"
200
-
201
- const result = await client.highlightOnce(tsCode, "typescript")
202
- expect(result.highlights).toBeDefined()
203
-
204
- const groups = result.highlights!.map(([, , group]) => group)
205
- const dotDelimitedGroups = groups.filter((group) => group.includes("."))
206
- expect(dotDelimitedGroups.length).toBeGreaterThan(0)
207
-
208
- const styledText = await treeSitterToStyledText(tsCode, "typescript", syntaxStyle, client)
209
- const chunks = styledText.chunks
210
-
211
- expect(chunks.length).toBeGreaterThan(1)
212
-
213
- const styledChunks = chunks.filter((chunk) => chunk.fg !== syntaxStyle.mergeStyles("default").fg)
214
- expect(styledChunks.length).toBeGreaterThan(0)
215
-
216
- const reconstructed = chunks.map((chunk) => chunk.text).join("")
217
- expect(reconstructed).toBe(tsCode)
218
- })
219
-
220
- test("should resolve styles correctly for dot-delimited groups and multiple overlapping groups", async () => {
221
- // Test the getStyle method directly
222
- expect(syntaxStyle.getStyle("function.method")).toEqual(syntaxStyle.getStyle("function"))
223
- expect(syntaxStyle.getStyle("variable.member")).toEqual(syntaxStyle.getStyle("variable"))
224
- expect(syntaxStyle.getStyle("nonexistent.fallback")).toBeUndefined()
225
- expect(syntaxStyle.getStyle("function")).toBeDefined()
226
- expect(syntaxStyle.getStyle("constructor")).toBeUndefined() // Should not return Object constructor
227
-
228
- // Test with mock highlights that have multiple groups for same range
229
- const mockHighlights: Array<[number, number, string]> = [
230
- [0, 4, "variable.member"], // should resolve to 'variable' style
231
- [0, 4, "function.method"], // should resolve to 'function' style (last valid)
232
- [0, 4, "nonexistent"], // undefined, should not override
233
- [4, 8, "keyword"], // should resolve to 'keyword' style
234
- ]
235
-
236
- const content = "testfunc"
237
- const chunks = treeSitterToTextChunks(content, mockHighlights, syntaxStyle)
238
-
239
- expect(chunks.length).toBe(2) // Two highlight ranges, no gaps
240
-
241
- // First chunk [0,4] should have function style (last valid style)
242
- const functionStyle = syntaxStyle.getStyle("function")!
243
- expect(chunks[0].text).toBe("test")
244
- expect(chunks[0].fg).toEqual(functionStyle.fg)
245
- expect(chunks[0].attributes).toBe(
246
- createTextAttributes({
247
- bold: functionStyle.bold,
248
- italic: functionStyle.italic,
249
- underline: functionStyle.underline,
250
- dim: functionStyle.dim,
251
- }),
252
- )
253
-
254
- // Second chunk [4,8] should have keyword style
255
- const keywordStyle = syntaxStyle.getStyle("keyword")!
256
- expect(chunks[1].text).toBe("func")
257
- expect(chunks[1].fg).toEqual(keywordStyle.fg)
258
- expect(chunks[1].attributes).toBe(
259
- createTextAttributes({
260
- bold: keywordStyle.bold,
261
- italic: keywordStyle.italic,
262
- underline: keywordStyle.underline,
263
- dim: keywordStyle.dim,
264
- }),
265
- )
266
- })
267
-
268
- test("should handle constructor group correctly", async () => {
269
- expect(syntaxStyle.getStyle("constructor")).toBeUndefined()
270
-
271
- const mockHighlights: Array<[number, number, string]> = [
272
- [0, 11, "variable.member"], // should resolve to 'variable' style
273
- [0, 11, "constructor"], // should resolve to undefined
274
- [0, 11, "function.method"], // should resolve to 'function' style (last valid)
275
- ]
276
-
277
- const content = "constructor"
278
- const chunks = treeSitterToTextChunks(content, mockHighlights, syntaxStyle)
279
-
280
- expect(chunks.length).toBe(1)
281
-
282
- const functionStyle = syntaxStyle.getStyle("function")!
283
- expect(chunks[0].text).toBe("constructor")
284
- expect(chunks[0].fg).toEqual(functionStyle.fg)
285
- expect(chunks[0].attributes).toBe(
286
- createTextAttributes({
287
- bold: functionStyle.bold,
288
- italic: functionStyle.italic,
289
- underline: functionStyle.underline,
290
- dim: functionStyle.dim,
291
- }),
292
- )
293
- })
294
-
295
- test("should handle markdown with TypeScript injection - suppress parent block styles", async () => {
296
- const markdownCode = `\`\`\`typescript
297
- const x: string = "hello";
298
- \`\`\``
299
-
300
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
301
- conceal: { enabled: false }, // Disable concealing to test text preservation
302
- })
303
- const chunks = styledText.chunks
304
-
305
- const reconstructed = chunks.map((c) => c.text).join("")
306
- expect(reconstructed).toBe(markdownCode)
307
-
308
- const tsStart = markdownCode.indexOf("const")
309
- const tsEnd = markdownCode.lastIndexOf(";") + 1
310
-
311
- let currentPos = 0
312
- const tsChunks: typeof chunks = []
313
- for (const chunk of chunks) {
314
- const chunkStart = currentPos
315
- const chunkEnd = currentPos + chunk.text.length
316
- if (chunkStart >= tsStart && chunkEnd <= tsEnd) {
317
- tsChunks.push(chunk)
318
- }
319
- currentPos = chunkEnd
320
- }
321
-
322
- // and NOT the parent markup.raw.block background
323
- expect(tsChunks.length).toBeGreaterThan(0)
324
-
325
- const hasKeywordStyle = tsChunks.some((chunk) => {
326
- const keywordStyle = syntaxStyle.getStyle("keyword")
327
- return (
328
- keywordStyle &&
329
- chunk.fg &&
330
- keywordStyle.fg &&
331
- chunk.fg.r === keywordStyle.fg.r &&
332
- chunk.fg.g === keywordStyle.fg.g &&
333
- chunk.fg.b === keywordStyle.fg.b
334
- )
335
- })
336
- expect(hasKeywordStyle).toBe(true)
337
- })
338
-
339
- test("should conceal backticks in inline code", async () => {
340
- const markdownCode = "Some text with `inline code` here."
341
-
342
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
343
- conceal: { enabled: true },
344
- })
345
- const chunks = styledText.chunks
346
-
347
- const reconstructed = chunks.map((c) => c.text).join("")
348
- expect(reconstructed).not.toContain("`")
349
- expect(reconstructed).toContain("inline code")
350
- expect(reconstructed).toContain("Some text with ")
351
- expect(reconstructed).toContain(" here.")
352
- })
353
-
354
- test("should conceal bold markers", async () => {
355
- const markdownCode = "Some **bold** text"
356
-
357
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
358
- conceal: { enabled: true },
359
- })
360
- const chunks = styledText.chunks
361
-
362
- const reconstructed = chunks.map((c) => c.text).join("")
363
- expect(reconstructed).not.toContain("**")
364
- expect(reconstructed).not.toContain("*")
365
- expect(reconstructed).toContain("bold")
366
- expect(reconstructed).toContain("Some ")
367
- expect(reconstructed).toContain(" text")
368
- })
369
-
370
- test("should conceal link syntax but keep text and URL", async () => {
371
- const markdownCode = "[Link text](https://example.com)"
372
-
373
- const result = await client.highlightOnce(markdownCode, "markdown")
374
- expect(result.highlights).toBeDefined()
375
-
376
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
377
- conceal: { enabled: true },
378
- })
379
- const chunks = styledText.chunks
380
-
381
- const reconstructed = chunks.map((c) => c.text).join("")
382
-
383
- expect(reconstructed).not.toContain("[")
384
- expect(reconstructed).not.toContain("]")
385
- expect(reconstructed).toContain("(")
386
- expect(reconstructed).toContain(")")
387
-
388
- expect(reconstructed).toContain("Link text")
389
- expect(reconstructed).toContain("https://example.com")
390
-
391
- expect(reconstructed).toBe("Link text (https://example.com)")
392
- })
393
-
394
- test("should conceal code block delimiters and language info", async () => {
395
- const markdownCode = `\`\`\`typescript
396
- const x: string = "hello";
397
- \`\`\``
398
-
399
- const result = await client.highlightOnce(markdownCode, "markdown")
400
- expect(result.highlights).toBeDefined()
401
-
402
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
403
- conceal: { enabled: true },
404
- })
405
- const chunks = styledText.chunks
406
-
407
- const reconstructed = chunks.map((c) => c.text).join("")
408
-
409
- expect(reconstructed).toContain("const x")
410
- expect(reconstructed).toContain("hello")
411
-
412
- expect(reconstructed).not.toContain("typescript")
413
-
414
- expect(reconstructed.startsWith("const")).toBe(true)
415
-
416
- expect(reconstructed.split("\n").filter((l) => l.trim() === "").length).toBeLessThanOrEqual(1)
417
- })
418
-
419
- test("should handle overlapping highlights with specificity resolution", async () => {
420
- const mockHighlights: SimpleHighlight[] = [
421
- [0, 10, "variable"],
422
- [0, 10, "variable.member"], // More specific, should win
423
- [0, 10, "type"],
424
- [11, 16, "keyword"],
425
- [11, 16, "keyword.coroutine"], // More specific, should win
426
- ]
427
-
428
- const content = "identifier const"
429
- // "identifier" = indices 0-9 (10 chars)
430
- // " " = index 10 (1 char)
431
- // "const" = indices 11-15 (5 chars)
432
- const chunks = treeSitterToTextChunks(content, mockHighlights, syntaxStyle)
433
-
434
- expect(chunks.length).toBe(3) // "identifier", " ", "const"
435
-
436
- const variableStyle = syntaxStyle.getStyle("variable")!
437
- expect(chunks[0].text).toBe("identifier")
438
- expect(chunks[0].fg).toEqual(variableStyle.fg)
439
-
440
- expect(chunks[1].text).toBe(" ")
441
-
442
- const keywordStyle = syntaxStyle.getStyle("keyword")!
443
- expect(chunks[2].text).toBe("const")
444
- expect(chunks[2].fg).toEqual(keywordStyle.fg)
445
- })
446
-
447
- test("should not conceal when conceal option is disabled", async () => {
448
- const markdownCode = "Some text with `inline code` here."
449
-
450
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
451
- conceal: { enabled: false },
452
- })
453
- const chunks = styledText.chunks
454
-
455
- const reconstructed = chunks.map((c) => c.text).join("")
456
- expect(reconstructed).toContain("`")
457
- expect(reconstructed).toBe(markdownCode)
458
- })
459
-
460
- test("should handle complex markdown with multiple features", async () => {
461
- const markdownCode = `# Heading
462
-
463
- Some **bold** text and \`code\`.
464
-
465
- \`\`\`typescript
466
- const hello: string = "world";
467
- \`\`\`
468
-
469
- [Link](https://example.com)`
470
-
471
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
472
- conceal: { enabled: true },
473
- })
474
- const chunks = styledText.chunks
475
-
476
- const reconstructed = chunks.map((c) => c.text).join("")
477
-
478
- expect(reconstructed).toContain("Heading")
479
- expect(reconstructed).toContain("bold")
480
- expect(reconstructed).toContain("code")
481
- expect(reconstructed).toContain("const hello")
482
- expect(reconstructed).toContain("Link")
483
-
484
- expect(reconstructed).not.toContain("**")
485
- })
486
-
487
- test("should correctly handle ranges after concealed text", async () => {
488
- const markdownCode = "Text with **bold** and *italic* markers."
489
-
490
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
491
- conceal: { enabled: true },
492
- })
493
- const chunks = styledText.chunks
494
-
495
- const reconstructed = chunks.map((c) => c.text).join("")
496
-
497
- expect(reconstructed).toContain("Text with ")
498
- expect(reconstructed).toContain("bold")
499
- expect(reconstructed).toContain(" and ")
500
- expect(reconstructed).toContain("italic")
501
- expect(reconstructed).toContain(" markers.")
502
-
503
- expect(reconstructed).not.toContain("**")
504
- expect(reconstructed).not.toContain("*")
505
-
506
- expect(reconstructed).toMatch(/Text with \w+ and \w+ markers\./)
507
- })
508
-
509
- test("should conceal heading markers and preserve heading styling", async () => {
510
- const markdownCode = "## Heading 2"
511
-
512
- const result = await client.highlightOnce(markdownCode, "markdown")
513
-
514
- const hasAnyConceals = result.highlights!.some(([, , , meta]) => meta?.conceal !== undefined)
515
- expect(hasAnyConceals).toBe(true) // Should have conceal on the ## marker
516
-
517
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
518
- conceal: { enabled: true },
519
- })
520
- const chunks = styledText.chunks
521
-
522
- const reconstructed = chunks.map((c) => c.text).join("")
523
-
524
- expect(reconstructed).toContain("Heading 2")
525
-
526
- expect(reconstructed).not.toContain("##")
527
- expect(reconstructed).not.toContain("#")
528
-
529
- expect(reconstructed).toBe("Heading 2")
530
-
531
- expect(reconstructed.startsWith(" ")).toBe(false)
532
- expect(reconstructed.startsWith("Heading")).toBe(true)
533
-
534
- // Note: Heading styling depends on having the parent markup.heading style
535
- // properly cascade to child text. In a real application with proper theme setup,
536
- // the heading text will be styled correctly as shown in other tests.
537
- })
538
-
539
- test("should not create empty lines when concealing code block delimiters", async () => {
540
- const markdownCode = `\`\`\`typescript
541
- const x = 1;
542
- const y = 2;
543
- \`\`\``
544
-
545
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
546
- conceal: { enabled: true },
547
- })
548
-
549
- const reconstructed = styledText.chunks.map((c) => c.text).join("")
550
-
551
- const originalLines = markdownCode.split("\n")
552
- expect(originalLines.length).toBe(4)
553
-
554
- // (The ```typescript line is completely removed including its newline)
555
- const reconstructedLines = reconstructed.split("\n")
556
- expect(reconstructedLines.length).toBe(3)
557
-
558
- expect(reconstructedLines[0]).toBe("const x = 1;")
559
-
560
- expect(reconstructed.startsWith("\n")).toBe(false)
561
- expect(reconstructed.startsWith("const")).toBe(true)
562
- })
563
-
564
- test("should conceal closing triple backticks in plain code block (no injection)", async () => {
565
- const markdownCode = `\`\`\`
566
- const msg = "hello";
567
- \`\`\``
568
-
569
- const result = await client.highlightOnce(markdownCode, "markdown")
570
- expect(result.highlights).toBeDefined()
571
-
572
- const closingBackticksHighlight = result.highlights!.find(([start, end, , meta]) => {
573
- const text = markdownCode.slice(start, end)
574
- return text === "```" && start > 10 && meta?.conceal !== undefined
575
- })
576
-
577
- expect(closingBackticksHighlight).toBeDefined()
578
-
579
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
580
- conceal: { enabled: true },
581
- })
582
- const chunks = styledText.chunks
583
-
584
- const reconstructed = chunks.map((c) => c.text).join("")
585
-
586
- expect(reconstructed).not.toContain("```")
587
- expect(reconstructed).toContain("const msg")
588
- })
589
-
590
- test("should conceal closing triple backticks when they are the last content (with TypeScript injection)", async () => {
591
- const markdownCode = `\`\`\`typescript
592
- const msg = "hello";
593
- \`\`\``
594
-
595
- const result = await client.highlightOnce(markdownCode, "markdown")
596
- expect(result.highlights).toBeDefined()
597
-
598
- const closingBackticksHighlights = result.highlights!.filter(([start, end]) => {
599
- const text = markdownCode.slice(start, end)
600
- return start > 30 && text.includes("`")
601
- })
602
-
603
- const hasClosingConceal = closingBackticksHighlights.some(([, , , meta]) => meta?.conceal !== undefined)
604
- expect(hasClosingConceal).toBe(true)
605
-
606
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
607
- conceal: { enabled: true },
608
- })
609
- const chunks = styledText.chunks
610
-
611
- const reconstructed = chunks.map((c) => c.text).join("")
612
-
613
- expect(reconstructed).not.toContain("```")
614
- expect(reconstructed).toContain("const msg")
615
- expect(reconstructed).toContain("hello")
616
-
617
- expect(reconstructed.endsWith("```")).toBe(false)
618
- expect(reconstructed.endsWith("`")).toBe(false)
619
- })
620
-
621
- describe("Markdown highlighting comprehensive coverage", () => {
622
- test("headings should have full styling applied", async () => {
623
- const markdownCode = `# Heading 1
624
- ## Heading 2
625
- ### Heading 3`
626
-
627
- const result = await client.highlightOnce(markdownCode, "markdown")
628
- expect(result.highlights).toBeDefined()
629
-
630
- const groups = result.highlights!.map(([, , group]) => group)
631
- expect(groups).toContain("markup.heading.1")
632
- expect(groups).toContain("markup.heading.2")
633
- expect(groups).toContain("markup.heading.3")
634
-
635
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
636
- conceal: { enabled: false }, // Disable concealing to test text preservation
637
- })
638
- const chunks = styledText.chunks
639
-
640
- const reconstructed = chunks.map((c) => c.text).join("")
641
- expect(reconstructed).toBe(markdownCode)
642
-
643
- const hashOrHeadingChunks = chunks.filter((chunk) => chunk.text.includes("#") || /heading/i.test(chunk.text))
644
- expect(hashOrHeadingChunks.length).toBeGreaterThan(0)
645
-
646
- const headingGroups = groups.filter((g) => g.includes("markup.heading"))
647
- expect(headingGroups.length).toBeGreaterThan(0)
648
- })
649
-
650
- test("inline raw blocks (code) should be styled", async () => {
651
- const markdownCode = "Some text with `inline code` here."
652
-
653
- const result = await client.highlightOnce(markdownCode, "markdown")
654
- expect(result.highlights).toBeDefined()
655
-
656
- const groups = result.highlights!.map(([, , group]) => group)
657
- const hasCodeGroup = groups.some((g) => g.includes("markup.raw") || g.includes("code"))
658
- expect(hasCodeGroup).toBe(true)
659
-
660
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
661
- conceal: { enabled: false },
662
- })
663
- const chunks = styledText.chunks
664
-
665
- const codeChunks = chunks.filter((c) => c.text.includes("inline") || c.text.includes("code"))
666
- expect(codeChunks.length).toBeGreaterThan(0)
667
-
668
- const defaultStyle = syntaxStyle.mergeStyles("default")
669
- const styledCodeChunks = codeChunks.filter((c) => c.fg !== defaultStyle.fg || c.attributes !== 0)
670
- expect(styledCodeChunks.length).toBeGreaterThan(0)
671
- })
672
-
673
- test("quotes should be styled correctly", async () => {
674
- const markdownCode = `> This is a quote
675
- > Another line`
676
-
677
- const result = await client.highlightOnce(markdownCode, "markdown")
678
- expect(result.highlights).toBeDefined()
679
-
680
- const groups = result.highlights!.map(([, , group]) => group)
681
- const hasQuoteGroup = groups.some((g) => g.includes("quote"))
682
- expect(hasQuoteGroup).toBe(true)
683
-
684
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client)
685
- const chunks = styledText.chunks
686
-
687
- const reconstructed = chunks.map((c) => c.text).join("")
688
- expect(reconstructed).toBe(markdownCode)
689
- })
690
-
691
- test("italic text should be styled in all places", async () => {
692
- const markdownCode = `*italic* text in paragraph
693
-
694
- # *italic in heading*
695
-
696
- - *italic in list*`
697
-
698
- const result = await client.highlightOnce(markdownCode, "markdown")
699
- expect(result.highlights).toBeDefined()
700
-
701
- const groups = result.highlights!.map(([, , group]) => group)
702
- const hasItalicGroup = groups.some((g) => g.includes("italic") || g.includes("emphasis"))
703
- expect(hasItalicGroup).toBe(true)
704
-
705
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
706
- conceal: { enabled: true },
707
- })
708
- const chunks = styledText.chunks
709
-
710
- const reconstructed = chunks.map((c) => c.text).join("")
711
- const asteriskCount = (reconstructed.match(/\*/g) || []).length
712
- const originalAsteriskCount = (markdownCode.match(/\*/g) || []).length
713
- expect(asteriskCount).toBeLessThan(originalAsteriskCount)
714
- })
715
-
716
- test("bold text should work in all contexts", async () => {
717
- const markdownCode = `**bold** text in paragraph
718
-
719
- # **bold in heading**
720
-
721
- - **bold in list**
722
-
723
- > **bold in quote**`
724
-
725
- const result = await client.highlightOnce(markdownCode, "markdown")
726
- expect(result.highlights).toBeDefined()
727
-
728
- const groups = result.highlights!.map(([, , group]) => group)
729
- const hasBoldGroup = groups.some((g) => g.includes("strong") || g.includes("bold"))
730
- expect(hasBoldGroup).toBe(true)
731
-
732
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
733
- conceal: { enabled: true },
734
- })
735
- const chunks = styledText.chunks
736
-
737
- const reconstructed = chunks.map((c) => c.text).join("")
738
- expect(reconstructed).not.toContain("**")
739
- expect(reconstructed).toContain("bold")
740
- })
741
-
742
- test("TypeScript code block should not contain parent markup.raw.block fragments between syntax ranges", async () => {
743
- const markdownCode = `\`\`\`typescript
744
- const greeting: string = "hello";
745
- function test() { return 42; }
746
- \`\`\``
747
-
748
- const result = await client.highlightOnce(markdownCode, "markdown")
749
- expect(result.highlights).toBeDefined()
750
-
751
- const hasInjection = result.highlights!.some(([, , , meta]) => meta?.injectionLang === "typescript")
752
- expect(hasInjection).toBe(true)
753
-
754
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
755
- conceal: { enabled: false }, // Disable concealing to test text preservation
756
- })
757
- const chunks = styledText.chunks
758
-
759
- const reconstructed = chunks.map((c) => c.text).join("")
760
- expect(reconstructed).toBe(markdownCode)
761
-
762
- const tsCodeStart = markdownCode.indexOf("\n") + 1 // After first ```typescript\n
763
- const tsCodeEnd = markdownCode.lastIndexOf("\n```") // Before last \n```
764
-
765
- let currentPos = 0
766
- const tsChunks: typeof chunks = []
767
- for (const chunk of chunks) {
768
- const chunkStart = currentPos
769
- const chunkEnd = currentPos + chunk.text.length
770
- if (chunkEnd > tsCodeStart && chunkStart < tsCodeEnd) {
771
- tsChunks.push(chunk)
772
- }
773
- currentPos = chunkEnd
774
- }
775
-
776
- expect(tsChunks.length).toBeGreaterThan(0)
777
-
778
- // (keyword, type, string, etc.) and NOT markup.raw.block background
779
- const keywordStyle = syntaxStyle.getStyle("keyword")
780
- const stringStyle = syntaxStyle.getStyle("string")
781
- const typeStyle = syntaxStyle.getStyle("type")
782
-
783
- const hasKeywordStyle = tsChunks.some((chunk) => {
784
- return (
785
- keywordStyle &&
786
- chunk.fg &&
787
- keywordStyle.fg &&
788
- chunk.fg.r === keywordStyle.fg.r &&
789
- chunk.fg.g === keywordStyle.fg.g &&
790
- chunk.fg.b === keywordStyle.fg.b
791
- )
792
- })
793
-
794
- const hasStringStyle = tsChunks.some((chunk) => {
795
- return (
796
- stringStyle &&
797
- chunk.fg &&
798
- stringStyle.fg &&
799
- chunk.fg.r === stringStyle.fg.r &&
800
- chunk.fg.g === stringStyle.fg.g &&
801
- chunk.fg.b === stringStyle.fg.b
802
- )
803
- })
804
-
805
- expect(hasKeywordStyle || hasStringStyle).toBe(true)
806
-
807
- const defaultStyle = syntaxStyle.mergeStyles("default")
808
-
809
- for (const chunk of tsChunks) {
810
- // 1. TypeScript-specific styling (keyword, string, type, etc.)
811
- // 2. Default styling (for whitespace, punctuation)
812
- // 3. NOT markup.raw.block background (which would be wrong)
813
-
814
- // we verify that chunks are either styled or default
815
- const isStyled = chunk.fg !== defaultStyle.fg || chunk.attributes !== 0
816
- const isDefault = chunk.fg === defaultStyle.fg
817
-
818
- expect(isStyled || isDefault).toBe(true)
819
- }
820
- })
821
-
822
- test("mixed formatting (bold + italic) should work", async () => {
823
- const markdownCode = "***bold and italic*** text"
824
-
825
- const result = await client.highlightOnce(markdownCode, "markdown")
826
- expect(result.highlights).toBeDefined()
827
-
828
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
829
- conceal: { enabled: true },
830
- })
831
- const chunks = styledText.chunks
832
-
833
- const reconstructed = chunks.map((c) => c.text).join("")
834
- expect(reconstructed).not.toContain("***")
835
- expect(reconstructed).toContain("bold and italic")
836
- })
837
-
838
- test("inline code in headings should be styled", async () => {
839
- const markdownCode = "# Heading with `code` inside"
840
-
841
- const result = await client.highlightOnce(markdownCode, "markdown")
842
- expect(result.highlights).toBeDefined()
843
-
844
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
845
- conceal: { enabled: false },
846
- })
847
- const chunks = styledText.chunks
848
-
849
- const reconstructed = chunks.map((c) => c.text).join("")
850
- expect(reconstructed).toBe(markdownCode)
851
-
852
- const groups = result.highlights!.map(([, , group]) => group)
853
- expect(groups.some((g) => g.includes("heading"))).toBe(true)
854
- expect(groups.some((g) => g.includes("markup.raw") || g.includes("code"))).toBe(true)
855
- })
856
-
857
- test("bold and italic in lists should work", async () => {
858
- const markdownCode = `- **bold item**
859
- - *italic item*
860
- - normal item`
861
-
862
- const result = await client.highlightOnce(markdownCode, "markdown")
863
- expect(result.highlights).toBeDefined()
864
-
865
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
866
- conceal: { enabled: true },
867
- })
868
- const chunks = styledText.chunks
869
-
870
- const reconstructed = chunks.map((c) => c.text).join("")
871
- expect(reconstructed).toContain("bold item")
872
- expect(reconstructed).toContain("italic item")
873
- expect(reconstructed).not.toContain("**")
874
- })
875
-
876
- test("code blocks with different languages should suppress parent styles", async () => {
877
- const markdownCode = `\`\`\`javascript
878
- const x = 42;
879
- \`\`\`
880
-
881
- \`\`\`typescript
882
- const y: number = 42;
883
- \`\`\``
884
-
885
- const result = await client.highlightOnce(markdownCode, "markdown")
886
- expect(result.highlights).toBeDefined()
887
-
888
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
889
- conceal: { enabled: false }, // Disable concealing to test text preservation
890
- })
891
- const chunks = styledText.chunks
892
-
893
- const reconstructed = chunks.map((c) => c.text).join("")
894
- expect(reconstructed).toBe(markdownCode)
895
-
896
- const jsInjection = result.highlights!.some(([, , , meta]) => meta?.injectionLang === "javascript")
897
- const tsInjection = result.highlights!.some(([, , , meta]) => meta?.injectionLang === "typescript")
898
-
899
- expect(jsInjection || tsInjection).toBe(true)
900
- })
901
-
902
- test("complex nested markdown structures", async () => {
903
- const markdownCode = `# Main Heading
904
-
905
- > This is a quote with **bold** and *italic* and \`code\`.
906
-
907
- ## Sub Heading
908
-
909
- - List item with **bold**
910
- - Another item with \`inline code\`
911
-
912
- \`\`\`typescript
913
- // Comment in code
914
- const value = "string";
915
- \`\`\`
916
-
917
- Normal paragraph with [link](https://example.com).`
918
-
919
- const result = await client.highlightOnce(markdownCode, "markdown")
920
- expect(result.highlights).toBeDefined()
921
- expect(result.highlights!.length).toBeGreaterThan(10)
922
-
923
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", syntaxStyle, client, {
924
- conceal: { enabled: true },
925
- })
926
- const chunks = styledText.chunks
927
-
928
- const reconstructed = chunks.map((c) => c.text).join("")
929
-
930
- expect(reconstructed).toContain("Main Heading")
931
- expect(reconstructed).toContain("Sub Heading")
932
- expect(reconstructed).toContain("quote")
933
- expect(reconstructed).toContain("bold")
934
- expect(reconstructed).toContain("italic")
935
- expect(reconstructed).toContain("code")
936
- expect(reconstructed).toContain("const value")
937
- expect(reconstructed).toContain("link")
938
-
939
- expect(reconstructed).not.toContain("**")
940
-
941
- const defaultStyle = syntaxStyle.mergeStyles("default")
942
- const styledChunks = chunks.filter((c) => c.fg !== defaultStyle.fg || c.attributes !== 0)
943
- expect(styledChunks.length).toBeGreaterThan(5)
944
- })
945
- })
946
-
947
- describe("Style Inheritance", () => {
948
- test("should merge styles from nested highlights with child overriding parent", () => {
949
- const mockHighlights: SimpleHighlight[] = [
950
- [0, 20, "markup.link"], // Parent: entire link with underline
951
- [1, 11, "markup.link.label"], // Child: label with different color
952
- [13, 19, "markup.link.url"], // Child: url with different color
953
- ]
954
-
955
- const testStyle = SyntaxStyle.fromStyles({
956
- default: { fg: RGBA.fromInts(255, 255, 255, 255) },
957
- "markup.link": { fg: RGBA.fromInts(100, 100, 255, 255), underline: true }, // Blue underlined
958
- "markup.link.label": { fg: RGBA.fromInts(165, 214, 255, 255) }, // Light blue (no underline specified)
959
- "markup.link.url": { fg: RGBA.fromInts(88, 166, 255, 255) }, // Different blue (no underline specified)
960
- })
961
-
962
- const content = "[Link text](url)"
963
-
964
- const labelStyle = testStyle.getStyle("markup.link.label")!
965
- const urlStyle = testStyle.getStyle("markup.link.url")!
966
-
967
- const chunks = treeSitterToTextChunks(content, mockHighlights, testStyle)
968
-
969
- testStyle.destroy()
970
-
971
- expect(chunks.length).toBeGreaterThan(0)
972
-
973
- let currentPos = 0
974
- const labelChunks: typeof chunks = []
975
- const urlChunks: typeof chunks = []
976
-
977
- for (const chunk of chunks) {
978
- const chunkStart = currentPos
979
- const chunkEnd = currentPos + chunk.text.length
980
-
981
- // Label is at [1, 11] - "Link text"
982
- if (chunkStart >= 1 && chunkStart < 11 && chunk.text.length > 0) {
983
- labelChunks.push(chunk)
984
- }
985
-
986
- // URL is at [13, 19] - "url"
987
- if (chunkStart >= 13 && chunkStart < 19 && chunk.text.length > 0) {
988
- urlChunks.push(chunk)
989
- }
990
-
991
- currentPos = chunkEnd
992
- }
993
-
994
- expect(labelChunks.length).toBeGreaterThan(0)
995
- expect(urlChunks.length).toBeGreaterThan(0)
996
-
997
- const underlineAttr = createTextAttributes({ underline: true })
998
- for (const chunk of [...labelChunks, ...urlChunks]) {
999
- expect(chunk.attributes).toBe(underlineAttr)
1000
- }
1001
-
1002
- for (const chunk of labelChunks) {
1003
- expect(chunk.fg?.r).toBeCloseTo(labelStyle.fg!.r, 2)
1004
- expect(chunk.fg?.g).toBeCloseTo(labelStyle.fg!.g, 2)
1005
- expect(chunk.fg?.b).toBeCloseTo(labelStyle.fg!.b, 2)
1006
- }
1007
-
1008
- for (const chunk of urlChunks) {
1009
- expect(chunk.fg?.r).toBeCloseTo(urlStyle.fg!.r, 2)
1010
- expect(chunk.fg?.g).toBeCloseTo(urlStyle.fg!.g, 2)
1011
- expect(chunk.fg?.b).toBeCloseTo(urlStyle.fg!.b, 2)
1012
- }
1013
- })
1014
-
1015
- test("should merge multiple overlapping styles with correct priority", () => {
1016
- const mockHighlights: SimpleHighlight[] = [
1017
- [0, 10, "text"], // Base style
1018
- [0, 10, "text.special"], // More specific: adds bold
1019
- [0, 10, "text.special.highlighted"], // Most specific: adds underline
1020
- ]
1021
-
1022
- const testStyle = SyntaxStyle.fromStyles({
1023
- default: { fg: RGBA.fromInts(255, 255, 255, 255) },
1024
- text: { fg: RGBA.fromInts(200, 200, 200, 255) }, // Gray
1025
- "text.special": { bold: true }, // Add bold, no color change
1026
- "text.special.highlighted": { underline: true, fg: RGBA.fromInts(255, 255, 100, 255) }, // Add underline and yellow
1027
- })
1028
-
1029
- const content = "test text "
1030
- const chunks = treeSitterToTextChunks(content, mockHighlights, testStyle)
1031
-
1032
- testStyle.destroy()
1033
-
1034
- expect(chunks.length).toBeGreaterThan(0)
1035
-
1036
- const chunk = chunks[0]
1037
-
1038
- expect(chunk.fg?.r).toBeCloseTo(1.0, 2)
1039
- expect(chunk.fg?.g).toBeCloseTo(1.0, 2)
1040
- expect(chunk.fg?.b).toBeCloseTo(100 / 255, 2)
1041
-
1042
- const expectedAttributes = createTextAttributes({ bold: true, underline: true })
1043
- expect(chunk.attributes).toBe(expectedAttributes)
1044
- })
1045
-
1046
- test("should handle style inheritance when parent only sets attributes", () => {
1047
- const mockHighlights: SimpleHighlight[] = [
1048
- [0, 15, "container"], // Parent: only underline
1049
- [0, 5, "container.part1"], // Child: only color
1050
- [5, 10, "container.part2"], // Child: different color
1051
- [10, 15, "container.part3"], // Child: yet another color
1052
- ]
1053
-
1054
- const testStyle = SyntaxStyle.fromStyles({
1055
- default: { fg: RGBA.fromInts(255, 255, 255, 255) },
1056
- container: { underline: true }, // Only underline, no color
1057
- "container.part1": { fg: RGBA.fromInts(255, 100, 100, 255) }, // Red
1058
- "container.part2": { fg: RGBA.fromInts(100, 255, 100, 255) }, // Green
1059
- "container.part3": { fg: RGBA.fromInts(100, 100, 255, 255) }, // Blue
1060
- })
1061
-
1062
- const content = "part1part2part3"
1063
- const chunks = treeSitterToTextChunks(content, mockHighlights, testStyle)
1064
-
1065
- testStyle.destroy()
1066
-
1067
- expect(chunks.length).toBe(3)
1068
-
1069
- const underlineAttr = createTextAttributes({ underline: true })
1070
- for (const chunk of chunks) {
1071
- expect(chunk.attributes).toBe(underlineAttr)
1072
- }
1073
-
1074
- expect(chunks[0].fg?.r).toBeCloseTo(1.0, 2) // 255 / 255
1075
- expect(chunks[0].fg?.g).toBeCloseTo(100 / 255, 2)
1076
- expect(chunks[0].fg?.b).toBeCloseTo(100 / 255, 2)
1077
-
1078
- expect(chunks[1].fg?.r).toBeCloseTo(100 / 255, 2)
1079
- expect(chunks[1].fg?.g).toBeCloseTo(1.0, 2) // 255 / 255
1080
- expect(chunks[1].fg?.b).toBeCloseTo(100 / 255, 2)
1081
-
1082
- expect(chunks[2].fg?.r).toBeCloseTo(100 / 255, 2)
1083
- expect(chunks[2].fg?.g).toBeCloseTo(100 / 255, 2)
1084
- expect(chunks[2].fg?.b).toBeCloseTo(1.0, 2) // 255 / 255
1085
- })
1086
-
1087
- test("should handle markdown link with realistic tree-sitter output", async () => {
1088
- const markdownCode = "[Label](url)"
1089
-
1090
- const result = await client.highlightOnce(markdownCode, "markdown")
1091
- expect(result.highlights).toBeDefined()
1092
-
1093
- // IMPORTANT: Tree-sitter markdown parser emits:
1094
- // - markup.link ONLY for brackets/parens: "[", "]", "(", ")"
1095
- // - markup.link.label ONLY for the label text: "Label" (not nested under markup.link!)
1096
- // - markup.link.url for the URL text: "url" (ALONG WITH markup.link as sibling)
1097
- //
1098
- // This means label does NOT inherit from markup.link because it's not a child range!
1099
- // Therefore, if you want label underlined, you must specify it explicitly.
1100
-
1101
- const labelHighlights = result.highlights!.filter(
1102
- ([start, end, group]) => group === "markup.link.label" && markdownCode.slice(start, end) === "Label",
1103
- )
1104
- expect(labelHighlights.length).toBe(1)
1105
-
1106
- const labelStart = labelHighlights[0][0]
1107
- const labelEnd = labelHighlights[0][1]
1108
- const labelHasParentLink = result.highlights!.some(
1109
- ([start, end, group]) => group === "markup.link" && start === labelStart && end === labelEnd,
1110
- )
1111
- expect(labelHasParentLink).toBe(false) // Confirms label is NOT nested
1112
-
1113
- const linkStyle = SyntaxStyle.fromStyles({
1114
- default: { fg: RGBA.fromInts(255, 255, 255, 255) },
1115
- "markup.link": { underline: true }, // Brackets and parens
1116
- "markup.link.label": { fg: RGBA.fromInts(165, 214, 255, 255), underline: true }, // Must set underline!
1117
- "markup.link.url": { fg: RGBA.fromInts(88, 166, 255, 255), underline: true }, // Must set underline!
1118
- })
1119
-
1120
- const styledText = await treeSitterToStyledText(markdownCode, "markdown", linkStyle, client, {
1121
- conceal: { enabled: false },
1122
- })
1123
- const chunks = styledText.chunks
1124
-
1125
- linkStyle.destroy()
1126
-
1127
- const reconstructed = chunks.map((c) => c.text).join("")
1128
- expect(reconstructed).toBe(markdownCode)
1129
-
1130
- const labelChunk = chunks.find((c) => c.text === "Label")
1131
- const urlChunk = chunks.find((c) => c.text === "url")
1132
-
1133
- expect(labelChunk).toBeDefined()
1134
- expect(urlChunk).toBeDefined()
1135
-
1136
- const underlineAttr = createTextAttributes({ underline: true })
1137
- expect(labelChunk!.attributes).toBe(underlineAttr)
1138
- expect(urlChunk!.attributes).toBe(underlineAttr)
1139
-
1140
- expect(labelChunk!.fg?.r).toBeCloseTo(165 / 255, 2)
1141
- expect(urlChunk!.fg?.r).toBeCloseTo(88 / 255, 2)
1142
- })
1143
-
1144
- test("should preserve original behavior for non-overlapping highlights", () => {
1145
- const mockHighlights: SimpleHighlight[] = [
1146
- [0, 5, "keyword"], // "const"
1147
- [6, 11, "string"], // "'str'"
1148
- [12, 15, "number"], // "123"
1149
- ]
1150
-
1151
- const testStyle = SyntaxStyle.fromStyles({
1152
- default: { fg: RGBA.fromInts(255, 255, 255, 255) },
1153
- keyword: { fg: RGBA.fromInts(255, 100, 100, 255), bold: true },
1154
- string: { fg: RGBA.fromInts(100, 255, 100, 255) },
1155
- number: { fg: RGBA.fromInts(100, 100, 255, 255) },
1156
- })
1157
-
1158
- const content = "const 'str' 123"
1159
- const chunks = treeSitterToTextChunks(content, mockHighlights, testStyle)
1160
-
1161
- testStyle.destroy()
1162
-
1163
- expect(chunks.length).toBe(5)
1164
-
1165
- expect(chunks[0].text).toBe("const")
1166
- expect(chunks[0].fg?.r).toBeCloseTo(1.0, 2) // 255 / 255
1167
- expect(chunks[0].attributes).toBe(createTextAttributes({ bold: true }))
1168
-
1169
- expect(chunks[1].text).toBe(" ")
1170
-
1171
- expect(chunks[2].text).toBe("'str'")
1172
- expect(chunks[2].fg?.g).toBeCloseTo(1.0, 2) // 255 / 255
1173
-
1174
- expect(chunks[3].text).toBe(" ")
1175
-
1176
- expect(chunks[4].text).toBe("123")
1177
- expect(chunks[4].fg?.b).toBeCloseTo(1.0, 2) // 255 / 255
1178
- })
1179
-
1180
- test("should demonstrate when inheritance works vs when it does not", () => {
1181
- const nestedHighlights: SimpleHighlight[] = [
1182
- [0, 10, "parent"], // Parent covers entire range
1183
- [2, 8, "parent.child"], // Child is INSIDE parent
1184
- ]
1185
-
1186
- const nestedStyle = SyntaxStyle.fromStyles({
1187
- default: { fg: RGBA.fromInts(255, 255, 255, 255) },
1188
- parent: { underline: true },
1189
- "parent.child": { fg: RGBA.fromInts(200, 100, 100, 255) }, // No underline specified
1190
- })
1191
-
1192
- const nestedContent = "0123456789"
1193
- const nestedChunks = treeSitterToTextChunks(nestedContent, nestedHighlights, nestedStyle)
1194
-
1195
- nestedStyle.destroy()
1196
-
1197
- const childChunk = nestedChunks.find((c) => c.text.includes("234567"))
1198
- expect(childChunk).toBeDefined()
1199
- expect(childChunk!.attributes).toBe(createTextAttributes({ underline: true }))
1200
- expect(childChunk!.fg?.r).toBeCloseTo(200 / 255, 2)
1201
-
1202
- const siblingHighlights: SimpleHighlight[] = [
1203
- [0, 5, "typeA"], // First range
1204
- [5, 10, "typeB"], // Second range (NOT nested)
1205
- ]
1206
-
1207
- const siblingStyle = SyntaxStyle.fromStyles({
1208
- default: { fg: RGBA.fromInts(255, 255, 255, 255) },
1209
- typeA: { underline: true, fg: RGBA.fromInts(100, 100, 255, 255) },
1210
- typeB: { fg: RGBA.fromInts(255, 100, 100, 255) }, // No underline
1211
- })
1212
-
1213
- const siblingContent = "0123456789"
1214
- const siblingChunks = treeSitterToTextChunks(siblingContent, siblingHighlights, siblingStyle)
1215
-
1216
- siblingStyle.destroy()
1217
-
1218
- expect(siblingChunks.length).toBe(2)
1219
-
1220
- expect(siblingChunks[0].attributes).toBe(createTextAttributes({ underline: true }))
1221
-
1222
- expect(siblingChunks[1].attributes).toBe(0) // No attributes
1223
- expect(siblingChunks[1].fg?.r).toBeCloseTo(255 / 255, 2)
1224
- })
1225
-
1226
- test("should handle child style completely overriding parent attributes", () => {
1227
- const mockHighlights: SimpleHighlight[] = [
1228
- [0, 10, "parent"],
1229
- [0, 10, "parent.child"],
1230
- ]
1231
-
1232
- const testStyle = SyntaxStyle.fromStyles({
1233
- default: { fg: RGBA.fromInts(255, 255, 255, 255) },
1234
- parent: { bold: true, italic: true, underline: true },
1235
- "parent.child": { bold: false, fg: RGBA.fromInts(200, 200, 200, 255) }, // Override bold, set color
1236
- })
1237
-
1238
- const content = "test text "
1239
- const chunks = treeSitterToTextChunks(content, mockHighlights, testStyle)
1240
-
1241
- testStyle.destroy()
1242
-
1243
- expect(chunks.length).toBeGreaterThan(0)
1244
-
1245
- const chunk = chunks[0]
1246
-
1247
- expect(chunk.fg?.r).toBeCloseTo(200 / 255, 2)
1248
-
1249
- const expectedAttributes = createTextAttributes({ bold: false, italic: true, underline: true })
1250
- expect(chunk.attributes).toBe(expectedAttributes)
1251
- })
1252
- })
1253
- })