@fairyhunter13/opentui-core 0.1.91 → 0.1.94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (570) hide show
  1. package/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 +34042 -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 +107 -0
  24. package/console.d.ts +143 -0
  25. package/edit-buffer.d.ts +98 -0
  26. package/editor-view.d.ts +73 -0
  27. package/index-e6ec7apq.js +18415 -0
  28. package/index-e6ec7apq.js.map +64 -0
  29. package/index-h066zmrb.js +12619 -0
  30. package/index-h066zmrb.js.map +43 -0
  31. package/index-ynzawt3n.js +113 -0
  32. package/index-ynzawt3n.js.map +10 -0
  33. package/index.d.ts +21 -0
  34. package/index.js +430 -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 +49 -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 +76 -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 +38 -0
  74. package/lib/tree-sitter/resolve-ft.d.ts +2 -0
  75. package/lib/tree-sitter/types.d.ts +81 -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 +51 -63
  80. package/parser.worker.js +869 -0
  81. package/parser.worker.js.map +12 -0
  82. package/plugins/core-slot.d.ts +72 -0
  83. package/plugins/registry.d.ts +38 -0
  84. package/plugins/types.d.ts +34 -0
  85. package/post/filters.d.ts +105 -0
  86. package/renderables/ASCIIFont.d.ts +52 -0
  87. package/renderables/Box.d.ts +72 -0
  88. package/renderables/Code.d.ts +78 -0
  89. package/renderables/Diff.d.ts +142 -0
  90. package/renderables/EditBufferRenderable.d.ts +162 -0
  91. package/renderables/FrameBuffer.d.ts +16 -0
  92. package/renderables/Input.d.ts +67 -0
  93. package/renderables/LineNumberRenderable.d.ts +74 -0
  94. package/renderables/Markdown.d.ts +173 -0
  95. package/renderables/ScrollBar.d.ts +77 -0
  96. package/renderables/ScrollBox.d.ts +124 -0
  97. package/renderables/Select.d.ts +115 -0
  98. package/renderables/Slider.d.ts +44 -0
  99. package/renderables/TabSelect.d.ts +96 -0
  100. package/renderables/Text.d.ts +36 -0
  101. package/renderables/TextBufferRenderable.d.ts +105 -0
  102. package/renderables/TextNode.d.ts +91 -0
  103. package/renderables/TextTable.d.ts +140 -0
  104. package/renderables/Textarea.d.ts +114 -0
  105. package/renderables/TimeToFirstDraw.d.ts +24 -0
  106. package/renderables/__tests__/renderable-test-utils.d.ts +12 -0
  107. package/renderables/composition/VRenderable.d.ts +16 -0
  108. package/renderables/composition/constructs.d.ts +35 -0
  109. package/renderables/composition/vnode.d.ts +46 -0
  110. package/renderables/index.d.ts +22 -0
  111. package/renderables/markdown-parser.d.ts +10 -0
  112. package/renderer.d.ts +388 -0
  113. package/runtime-plugin-support.d.ts +3 -0
  114. package/runtime-plugin-support.js +29 -0
  115. package/runtime-plugin-support.js.map +10 -0
  116. package/runtime-plugin.d.ts +11 -0
  117. package/runtime-plugin.js +16 -0
  118. package/runtime-plugin.js.map +9 -0
  119. package/syntax-style.d.ts +54 -0
  120. package/testing/manual-clock.d.ts +16 -0
  121. package/testing/mock-keys.d.ts +81 -0
  122. package/testing/mock-mouse.d.ts +38 -0
  123. package/testing/mock-tree-sitter-client.d.ts +23 -0
  124. package/testing/spy.d.ts +7 -0
  125. package/testing/test-recorder.d.ts +61 -0
  126. package/testing/test-renderer.d.ts +23 -0
  127. package/testing.d.ts +6 -0
  128. package/testing.js +675 -0
  129. package/testing.js.map +15 -0
  130. package/text-buffer-view.d.ts +42 -0
  131. package/text-buffer.d.ts +67 -0
  132. package/types.d.ts +131 -0
  133. package/utils.d.ts +14 -0
  134. package/zig-structs.d.ts +155 -0
  135. package/zig.d.ts +351 -0
  136. package/dev/keypress-debug-renderer.ts +0 -148
  137. package/dev/keypress-debug.ts +0 -43
  138. package/dev/print-env-vars.ts +0 -32
  139. package/dev/test-tmux-graphics-334.sh +0 -68
  140. package/dev/thai-debug-test.ts +0 -68
  141. package/docs/development.md +0 -141
  142. package/docs/env-vars.md +0 -140
  143. package/docs/getting-started.md +0 -353
  144. package/docs/renderables-vs-constructs.md +0 -159
  145. package/docs/tree-sitter.md +0 -311
  146. package/scripts/build.ts +0 -400
  147. package/scripts/publish.ts +0 -60
  148. package/src/3d/SpriteResourceManager.ts +0 -286
  149. package/src/3d/SpriteUtils.ts +0 -71
  150. package/src/3d/TextureUtils.ts +0 -196
  151. package/src/3d/ThreeRenderable.ts +0 -197
  152. package/src/3d/WGPURenderer.ts +0 -294
  153. package/src/3d/animation/ExplodingSpriteEffect.ts +0 -513
  154. package/src/3d/animation/PhysicsExplodingSpriteEffect.ts +0 -429
  155. package/src/3d/animation/SpriteAnimator.ts +0 -633
  156. package/src/3d/animation/SpriteParticleGenerator.ts +0 -435
  157. package/src/3d/canvas.ts +0 -464
  158. package/src/3d/index.ts +0 -12
  159. package/src/3d/physics/PlanckPhysicsAdapter.ts +0 -72
  160. package/src/3d/physics/RapierPhysicsAdapter.ts +0 -66
  161. package/src/3d/physics/physics-interface.ts +0 -31
  162. package/src/3d/shaders/supersampling.wgsl +0 -201
  163. package/src/3d.ts +0 -3
  164. package/src/NativeSpanFeed.ts +0 -300
  165. package/src/Renderable.ts +0 -1698
  166. package/src/__snapshots__/buffer.test.ts.snap +0 -28
  167. package/src/animation/Timeline.test.ts +0 -2709
  168. package/src/animation/Timeline.ts +0 -598
  169. package/src/ansi.ts +0 -18
  170. package/src/benchmark/latest-all-bench-run.json +0 -707
  171. package/src/benchmark/latest-async-bench-run.json +0 -336
  172. package/src/benchmark/latest-default-bench-run.json +0 -657
  173. package/src/benchmark/latest-large-bench-run.json +0 -707
  174. package/src/benchmark/latest-quick-bench-run.json +0 -207
  175. package/src/benchmark/markdown-benchmark.ts +0 -1804
  176. package/src/benchmark/native-span-feed-async-benchmark.ts +0 -355
  177. package/src/benchmark/native-span-feed-benchmark.md +0 -56
  178. package/src/benchmark/native-span-feed-benchmark.ts +0 -596
  179. package/src/benchmark/native-span-feed-compare.ts +0 -280
  180. package/src/benchmark/renderer-benchmark.ts +0 -754
  181. package/src/benchmark/text-table-benchmark.ts +0 -947
  182. package/src/buffer.test.ts +0 -291
  183. package/src/buffer.ts +0 -519
  184. package/src/console.test.ts +0 -612
  185. package/src/console.ts +0 -1255
  186. package/src/edit-buffer.test.ts +0 -1769
  187. package/src/edit-buffer.ts +0 -411
  188. package/src/editor-view.test.ts +0 -1032
  189. package/src/editor-view.ts +0 -284
  190. package/src/examples/ascii-font-selection-demo.ts +0 -245
  191. package/src/examples/assets/Water_2_M_Normal.jpg +0 -0
  192. package/src/examples/assets/concrete.png +0 -0
  193. package/src/examples/assets/crate.png +0 -0
  194. package/src/examples/assets/crate_emissive.png +0 -0
  195. package/src/examples/assets/forrest_background.png +0 -0
  196. package/src/examples/assets/hast-example.json +0 -1018
  197. package/src/examples/assets/heart.png +0 -0
  198. package/src/examples/assets/main_char_heavy_attack.png +0 -0
  199. package/src/examples/assets/main_char_idle.png +0 -0
  200. package/src/examples/assets/main_char_jump_end.png +0 -0
  201. package/src/examples/assets/main_char_jump_landing.png +0 -0
  202. package/src/examples/assets/main_char_jump_start.png +0 -0
  203. package/src/examples/assets/main_char_run_loop.png +0 -0
  204. package/src/examples/assets/roughness_map.jpg +0 -0
  205. package/src/examples/build.ts +0 -115
  206. package/src/examples/code-demo.ts +0 -584
  207. package/src/examples/console-demo.ts +0 -358
  208. package/src/examples/core-plugin-slots-demo.ts +0 -759
  209. package/src/examples/diff-demo.ts +0 -699
  210. package/src/examples/draggable-three-demo.ts +0 -259
  211. package/src/examples/editor-demo.ts +0 -322
  212. package/src/examples/extmarks-demo.ts +0 -204
  213. package/src/examples/focus-restore-demo.ts +0 -310
  214. package/src/examples/fonts.ts +0 -245
  215. package/src/examples/fractal-shader-demo.ts +0 -268
  216. package/src/examples/framebuffer-demo.ts +0 -674
  217. package/src/examples/full-unicode-demo.ts +0 -181
  218. package/src/examples/golden-star-demo.ts +0 -933
  219. package/src/examples/grayscale-buffer-demo.ts +0 -249
  220. package/src/examples/hast-syntax-highlighting-demo.ts +0 -129
  221. package/src/examples/index.ts +0 -925
  222. package/src/examples/input-demo.ts +0 -377
  223. package/src/examples/input-select-layout-demo.ts +0 -425
  224. package/src/examples/install.sh +0 -143
  225. package/src/examples/keypress-debug-demo.ts +0 -452
  226. package/src/examples/lib/HexList.ts +0 -122
  227. package/src/examples/lib/PaletteGrid.ts +0 -125
  228. package/src/examples/lib/standalone-keys.ts +0 -25
  229. package/src/examples/lib/tab-controller.ts +0 -243
  230. package/src/examples/lights-phong-demo.ts +0 -290
  231. package/src/examples/link-demo.ts +0 -220
  232. package/src/examples/live-state-demo.ts +0 -480
  233. package/src/examples/markdown-demo.ts +0 -620
  234. package/src/examples/mouse-interaction-demo.ts +0 -428
  235. package/src/examples/nested-zindex-demo.ts +0 -357
  236. package/src/examples/opacity-example.ts +0 -235
  237. package/src/examples/opentui-demo.ts +0 -1057
  238. package/src/examples/physx-planck-2d-demo.ts +0 -507
  239. package/src/examples/physx-rapier-2d-demo.ts +0 -526
  240. package/src/examples/relative-positioning-demo.ts +0 -323
  241. package/src/examples/scroll-example.ts +0 -214
  242. package/src/examples/scrollbox-mouse-test.ts +0 -112
  243. package/src/examples/scrollbox-overlay-hit-test.ts +0 -206
  244. package/src/examples/select-demo.ts +0 -237
  245. package/src/examples/shader-cube-demo.ts +0 -772
  246. package/src/examples/simple-layout-example.ts +0 -591
  247. package/src/examples/slider-demo.ts +0 -617
  248. package/src/examples/split-mode-demo.ts +0 -445
  249. package/src/examples/sprite-animation-demo.ts +0 -443
  250. package/src/examples/sprite-particle-generator-demo.ts +0 -486
  251. package/src/examples/static-sprite-demo.ts +0 -193
  252. package/src/examples/sticky-scroll-example.ts +0 -308
  253. package/src/examples/styled-text-demo.ts +0 -282
  254. package/src/examples/tab-select-demo.ts +0 -219
  255. package/src/examples/terminal-title.ts +0 -29
  256. package/src/examples/terminal.ts +0 -305
  257. package/src/examples/text-node-demo.ts +0 -416
  258. package/src/examples/text-selection-demo.ts +0 -377
  259. package/src/examples/text-table-demo.ts +0 -503
  260. package/src/examples/text-truncation-demo.ts +0 -481
  261. package/src/examples/text-wrap.ts +0 -757
  262. package/src/examples/texture-loading-demo.ts +0 -259
  263. package/src/examples/timeline-example.ts +0 -670
  264. package/src/examples/transparency-demo.ts +0 -241
  265. package/src/examples/vnode-composition-demo.ts +0 -404
  266. package/src/index.ts +0 -22
  267. package/src/lib/KeyHandler.integration.test.ts +0 -292
  268. package/src/lib/KeyHandler.stopPropagation.test.ts +0 -289
  269. package/src/lib/KeyHandler.test.ts +0 -662
  270. package/src/lib/KeyHandler.ts +0 -222
  271. package/src/lib/RGBA.test.ts +0 -984
  272. package/src/lib/RGBA.ts +0 -204
  273. package/src/lib/ascii.font.ts +0 -330
  274. package/src/lib/border.test.ts +0 -83
  275. package/src/lib/border.ts +0 -168
  276. package/src/lib/bunfs.test.ts +0 -27
  277. package/src/lib/bunfs.ts +0 -18
  278. package/src/lib/clipboard.test.ts +0 -41
  279. package/src/lib/clipboard.ts +0 -47
  280. package/src/lib/clock.ts +0 -31
  281. package/src/lib/data-paths.test.ts +0 -133
  282. package/src/lib/data-paths.ts +0 -109
  283. package/src/lib/debounce.ts +0 -106
  284. package/src/lib/detect-links.test.ts +0 -98
  285. package/src/lib/detect-links.ts +0 -56
  286. package/src/lib/env.test.ts +0 -228
  287. package/src/lib/env.ts +0 -209
  288. package/src/lib/extmarks-history.ts +0 -51
  289. package/src/lib/extmarks-multiwidth.test.ts +0 -322
  290. package/src/lib/extmarks.test.ts +0 -3457
  291. package/src/lib/extmarks.ts +0 -843
  292. package/src/lib/fonts/block.json +0 -405
  293. package/src/lib/fonts/grid.json +0 -265
  294. package/src/lib/fonts/huge.json +0 -741
  295. package/src/lib/fonts/pallet.json +0 -314
  296. package/src/lib/fonts/shade.json +0 -591
  297. package/src/lib/fonts/slick.json +0 -321
  298. package/src/lib/fonts/tiny.json +0 -69
  299. package/src/lib/hast-styled-text.ts +0 -59
  300. package/src/lib/index.ts +0 -21
  301. package/src/lib/keymapping.test.ts +0 -280
  302. package/src/lib/keymapping.ts +0 -87
  303. package/src/lib/objects-in-viewport.test.ts +0 -787
  304. package/src/lib/objects-in-viewport.ts +0 -153
  305. package/src/lib/output.capture.ts +0 -58
  306. package/src/lib/parse.keypress-kitty.protocol.test.ts +0 -340
  307. package/src/lib/parse.keypress-kitty.test.ts +0 -663
  308. package/src/lib/parse.keypress-kitty.ts +0 -439
  309. package/src/lib/parse.keypress.test.ts +0 -1849
  310. package/src/lib/parse.keypress.ts +0 -397
  311. package/src/lib/parse.mouse.test.ts +0 -552
  312. package/src/lib/parse.mouse.ts +0 -232
  313. package/src/lib/paste.ts +0 -16
  314. package/src/lib/queue.ts +0 -65
  315. package/src/lib/renderable.validations.test.ts +0 -87
  316. package/src/lib/renderable.validations.ts +0 -83
  317. package/src/lib/scroll-acceleration.ts +0 -98
  318. package/src/lib/selection.ts +0 -240
  319. package/src/lib/singleton.ts +0 -28
  320. package/src/lib/stdin-parser.test.ts +0 -1676
  321. package/src/lib/stdin-parser.ts +0 -1248
  322. package/src/lib/styled-text.ts +0 -178
  323. package/src/lib/terminal-capability-detection.test.ts +0 -202
  324. package/src/lib/terminal-capability-detection.ts +0 -79
  325. package/src/lib/terminal-palette.test.ts +0 -878
  326. package/src/lib/terminal-palette.ts +0 -383
  327. package/src/lib/tree-sitter/assets/README.md +0 -118
  328. package/src/lib/tree-sitter/assets/update.ts +0 -331
  329. package/src/lib/tree-sitter/assets.d.ts +0 -9
  330. package/src/lib/tree-sitter/cache.test.ts +0 -270
  331. package/src/lib/tree-sitter/client.test.ts +0 -1061
  332. package/src/lib/tree-sitter/client.ts +0 -615
  333. package/src/lib/tree-sitter/default-parsers.ts +0 -80
  334. package/src/lib/tree-sitter/download-utils.ts +0 -148
  335. package/src/lib/tree-sitter/index.ts +0 -28
  336. package/src/lib/tree-sitter/parser.worker.ts +0 -1001
  337. package/src/lib/tree-sitter/parsers-config.ts +0 -75
  338. package/src/lib/tree-sitter/resolve-ft.ts +0 -62
  339. package/src/lib/tree-sitter/types.ts +0 -81
  340. package/src/lib/tree-sitter-styled-text.test.ts +0 -1253
  341. package/src/lib/tree-sitter-styled-text.ts +0 -306
  342. package/src/lib/validate-dir-name.ts +0 -55
  343. package/src/lib/yoga.options.test.ts +0 -628
  344. package/src/lib/yoga.options.ts +0 -346
  345. package/src/plugins/core-slot.ts +0 -579
  346. package/src/plugins/registry.ts +0 -377
  347. package/src/plugins/types.ts +0 -46
  348. package/src/post/filters.ts +0 -888
  349. package/src/renderables/ASCIIFont.ts +0 -219
  350. package/src/renderables/Box.test.ts +0 -160
  351. package/src/renderables/Box.ts +0 -295
  352. package/src/renderables/Code.test.ts +0 -2062
  353. package/src/renderables/Code.ts +0 -357
  354. package/src/renderables/Diff.regression.test.ts +0 -226
  355. package/src/renderables/Diff.test.ts +0 -3027
  356. package/src/renderables/Diff.ts +0 -1209
  357. package/src/renderables/EditBufferRenderable.ts +0 -764
  358. package/src/renderables/FrameBuffer.ts +0 -47
  359. package/src/renderables/Input.test.ts +0 -1228
  360. package/src/renderables/Input.ts +0 -245
  361. package/src/renderables/LineNumberRenderable.ts +0 -675
  362. package/src/renderables/Markdown.ts +0 -1106
  363. package/src/renderables/ScrollBar.ts +0 -422
  364. package/src/renderables/ScrollBox.ts +0 -883
  365. package/src/renderables/Select.test.ts +0 -1010
  366. package/src/renderables/Select.ts +0 -523
  367. package/src/renderables/Slider.test.ts +0 -456
  368. package/src/renderables/Slider.ts +0 -347
  369. package/src/renderables/TabSelect.test.ts +0 -197
  370. package/src/renderables/TabSelect.ts +0 -455
  371. package/src/renderables/Text.selection-buffer.test.ts +0 -123
  372. package/src/renderables/Text.test.ts +0 -2660
  373. package/src/renderables/Text.ts +0 -147
  374. package/src/renderables/TextBufferRenderable.ts +0 -518
  375. package/src/renderables/TextNode.test.ts +0 -1058
  376. package/src/renderables/TextNode.ts +0 -325
  377. package/src/renderables/TextTable.test.ts +0 -1421
  378. package/src/renderables/TextTable.ts +0 -1344
  379. package/src/renderables/Textarea.ts +0 -732
  380. package/src/renderables/TimeToFirstDraw.ts +0 -89
  381. package/src/renderables/__snapshots__/Code.test.ts.snap +0 -13
  382. package/src/renderables/__snapshots__/Diff.test.ts.snap +0 -785
  383. package/src/renderables/__snapshots__/Text.test.ts.snap +0 -421
  384. package/src/renderables/__snapshots__/TextTable.test.ts.snap +0 -215
  385. package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +0 -144
  386. package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +0 -816
  387. package/src/renderables/__tests__/LineNumberRenderable.test.ts +0 -1787
  388. package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +0 -85
  389. package/src/renderables/__tests__/Markdown.test.ts +0 -2287
  390. package/src/renderables/__tests__/MultiRenderable.selection.test.ts +0 -87
  391. package/src/renderables/__tests__/Textarea.buffer.test.ts +0 -682
  392. package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +0 -675
  393. package/src/renderables/__tests__/Textarea.editing.test.ts +0 -2041
  394. package/src/renderables/__tests__/Textarea.error-handling.test.ts +0 -35
  395. package/src/renderables/__tests__/Textarea.events.test.ts +0 -738
  396. package/src/renderables/__tests__/Textarea.highlights.test.ts +0 -590
  397. package/src/renderables/__tests__/Textarea.keybinding.test.ts +0 -3149
  398. package/src/renderables/__tests__/Textarea.paste.test.ts +0 -357
  399. package/src/renderables/__tests__/Textarea.rendering.test.ts +0 -1864
  400. package/src/renderables/__tests__/Textarea.scroll.test.ts +0 -733
  401. package/src/renderables/__tests__/Textarea.selection.test.ts +0 -1590
  402. package/src/renderables/__tests__/Textarea.stress.test.ts +0 -670
  403. package/src/renderables/__tests__/Textarea.undo-redo.test.ts +0 -383
  404. package/src/renderables/__tests__/Textarea.visual-lines.test.ts +0 -310
  405. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +0 -221
  406. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +0 -89
  407. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +0 -457
  408. package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +0 -158
  409. package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +0 -387
  410. package/src/renderables/__tests__/markdown-parser.test.ts +0 -217
  411. package/src/renderables/__tests__/renderable-test-utils.ts +0 -60
  412. package/src/renderables/composition/README.md +0 -8
  413. package/src/renderables/composition/VRenderable.ts +0 -32
  414. package/src/renderables/composition/constructs.ts +0 -127
  415. package/src/renderables/composition/vnode.ts +0 -289
  416. package/src/renderables/index.ts +0 -22
  417. package/src/renderables/markdown-parser.ts +0 -66
  418. package/src/renderer.ts +0 -2363
  419. package/src/runtime-plugin-support.ts +0 -39
  420. package/src/runtime-plugin.ts +0 -144
  421. package/src/syntax-style.test.ts +0 -841
  422. package/src/syntax-style.ts +0 -264
  423. package/src/testing/README.md +0 -210
  424. package/src/testing/capture-spans.test.ts +0 -194
  425. package/src/testing/integration.test.ts +0 -276
  426. package/src/testing/manual-clock.ts +0 -106
  427. package/src/testing/mock-keys.test.ts +0 -1356
  428. package/src/testing/mock-keys.ts +0 -449
  429. package/src/testing/mock-mouse.test.ts +0 -218
  430. package/src/testing/mock-mouse.ts +0 -247
  431. package/src/testing/mock-tree-sitter-client.ts +0 -73
  432. package/src/testing/spy.ts +0 -13
  433. package/src/testing/test-recorder.test.ts +0 -415
  434. package/src/testing/test-recorder.ts +0 -145
  435. package/src/testing/test-renderer.ts +0 -116
  436. package/src/testing.ts +0 -7
  437. package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +0 -481
  438. package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +0 -19
  439. package/src/tests/__snapshots__/scrollbox.test.ts.snap +0 -29
  440. package/src/tests/absolute-positioning.snapshot.test.ts +0 -638
  441. package/src/tests/allocator-stats.test.ts +0 -38
  442. package/src/tests/destroy-during-render.test.ts +0 -200
  443. package/src/tests/hover-cursor.test.ts +0 -98
  444. package/src/tests/native-span-feed-async.test.ts +0 -173
  445. package/src/tests/native-span-feed-close.test.ts +0 -120
  446. package/src/tests/native-span-feed-coverage.test.ts +0 -227
  447. package/src/tests/native-span-feed-edge-cases.test.ts +0 -352
  448. package/src/tests/native-span-feed-use-after-free.test.ts +0 -45
  449. package/src/tests/opacity.test.ts +0 -123
  450. package/src/tests/renderable.snapshot.test.ts +0 -524
  451. package/src/tests/renderable.test.ts +0 -1281
  452. package/src/tests/renderer.console-startup.test.ts +0 -65
  453. package/src/tests/renderer.control.test.ts +0 -364
  454. package/src/tests/renderer.core-slot-binding.test.ts +0 -952
  455. package/src/tests/renderer.cursor.test.ts +0 -26
  456. package/src/tests/renderer.destroy-during-render.test.ts +0 -110
  457. package/src/tests/renderer.focus-restore.test.ts +0 -228
  458. package/src/tests/renderer.focus.test.ts +0 -251
  459. package/src/tests/renderer.idle.test.ts +0 -219
  460. package/src/tests/renderer.input.test.ts +0 -2145
  461. package/src/tests/renderer.kitty-flags.test.ts +0 -195
  462. package/src/tests/renderer.mouse.test.ts +0 -1269
  463. package/src/tests/renderer.palette.test.ts +0 -629
  464. package/src/tests/renderer.selection.test.ts +0 -49
  465. package/src/tests/renderer.slot-registry.test.ts +0 -649
  466. package/src/tests/renderer.useMouse.test.ts +0 -50
  467. package/src/tests/runtime-plugin-support.fixture.ts +0 -11
  468. package/src/tests/runtime-plugin-support.test.ts +0 -28
  469. package/src/tests/runtime-plugin.fixture.ts +0 -40
  470. package/src/tests/runtime-plugin.test.ts +0 -190
  471. package/src/tests/scrollbox-culling-bug.test.ts +0 -114
  472. package/src/tests/scrollbox-hitgrid-resize.test.ts +0 -136
  473. package/src/tests/scrollbox-hitgrid.test.ts +0 -909
  474. package/src/tests/scrollbox.test.ts +0 -1530
  475. package/src/tests/wrap-resize-perf.test.ts +0 -229
  476. package/src/tests/yoga-setters.test.ts +0 -921
  477. package/src/text-buffer-view.test.ts +0 -705
  478. package/src/text-buffer-view.ts +0 -189
  479. package/src/text-buffer.test.ts +0 -347
  480. package/src/text-buffer.ts +0 -250
  481. package/src/types.ts +0 -152
  482. package/src/utils.ts +0 -88
  483. package/src/zig/ansi.zig +0 -268
  484. package/src/zig/bench/README.md +0 -50
  485. package/src/zig/bench/buffer-draw-text-buffer_bench.zig +0 -887
  486. package/src/zig/bench/edit-buffer_bench.zig +0 -476
  487. package/src/zig/bench/native-span-feed_bench.zig +0 -100
  488. package/src/zig/bench/rope-markers_bench.zig +0 -713
  489. package/src/zig/bench/rope_bench.zig +0 -514
  490. package/src/zig/bench/styled-text_bench.zig +0 -470
  491. package/src/zig/bench/text-buffer-coords_bench.zig +0 -362
  492. package/src/zig/bench/text-buffer-view_bench.zig +0 -459
  493. package/src/zig/bench/text-chunk-graphemes_bench.zig +0 -273
  494. package/src/zig/bench/utf8_bench.zig +0 -799
  495. package/src/zig/bench-utils.zig +0 -431
  496. package/src/zig/bench.zig +0 -217
  497. package/src/zig/buffer.zig +0 -2223
  498. package/src/zig/build.zig +0 -289
  499. package/src/zig/build.zig.zon +0 -16
  500. package/src/zig/edit-buffer.zig +0 -825
  501. package/src/zig/editor-view.zig +0 -802
  502. package/src/zig/event-bus.zig +0 -13
  503. package/src/zig/event-emitter.zig +0 -65
  504. package/src/zig/file-logger.zig +0 -92
  505. package/src/zig/grapheme.zig +0 -599
  506. package/src/zig/lib.zig +0 -1834
  507. package/src/zig/link.zig +0 -333
  508. package/src/zig/logger.zig +0 -43
  509. package/src/zig/mem-registry.zig +0 -125
  510. package/src/zig/native-span-feed-bench-lib.zig +0 -7
  511. package/src/zig/native-span-feed.zig +0 -708
  512. package/src/zig/renderer.zig +0 -1386
  513. package/src/zig/rope.zig +0 -1220
  514. package/src/zig/syntax-style.zig +0 -161
  515. package/src/zig/terminal.zig +0 -975
  516. package/src/zig/test.zig +0 -70
  517. package/src/zig/tests/README.md +0 -18
  518. package/src/zig/tests/buffer_test.zig +0 -2526
  519. package/src/zig/tests/edit-buffer-history_test.zig +0 -271
  520. package/src/zig/tests/edit-buffer_test.zig +0 -1689
  521. package/src/zig/tests/editor-view_test.zig +0 -3299
  522. package/src/zig/tests/event-emitter_test.zig +0 -249
  523. package/src/zig/tests/grapheme_test.zig +0 -1304
  524. package/src/zig/tests/link_test.zig +0 -190
  525. package/src/zig/tests/mem-registry_test.zig +0 -473
  526. package/src/zig/tests/memory_leak_regression_test.zig +0 -159
  527. package/src/zig/tests/native-span-feed_test.zig +0 -1264
  528. package/src/zig/tests/renderer_test.zig +0 -1010
  529. package/src/zig/tests/rope-nested_test.zig +0 -712
  530. package/src/zig/tests/rope_fuzz_test.zig +0 -238
  531. package/src/zig/tests/rope_test.zig +0 -2362
  532. package/src/zig/tests/segment-merge.test.zig +0 -148
  533. package/src/zig/tests/syntax-style_test.zig +0 -557
  534. package/src/zig/tests/terminal_test.zig +0 -719
  535. package/src/zig/tests/text-buffer-drawing_test.zig +0 -3237
  536. package/src/zig/tests/text-buffer-highlights_test.zig +0 -666
  537. package/src/zig/tests/text-buffer-iterators_test.zig +0 -776
  538. package/src/zig/tests/text-buffer-segment_test.zig +0 -320
  539. package/src/zig/tests/text-buffer-selection_test.zig +0 -1035
  540. package/src/zig/tests/text-buffer-selection_viewport_test.zig +0 -358
  541. package/src/zig/tests/text-buffer-view_test.zig +0 -3649
  542. package/src/zig/tests/text-buffer_test.zig +0 -2191
  543. package/src/zig/tests/unicode-width-map.zon +0 -3909
  544. package/src/zig/tests/utf8_no_zwj_test.zig +0 -260
  545. package/src/zig/tests/utf8_test.zig +0 -4057
  546. package/src/zig/tests/utf8_wcwidth_cursor_test.zig +0 -267
  547. package/src/zig/tests/utf8_wcwidth_test.zig +0 -357
  548. package/src/zig/tests/word-wrap-editing_test.zig +0 -498
  549. package/src/zig/tests/wrap-cache-perf_test.zig +0 -113
  550. package/src/zig/text-buffer-iterators.zig +0 -499
  551. package/src/zig/text-buffer-segment.zig +0 -404
  552. package/src/zig/text-buffer-view.zig +0 -1371
  553. package/src/zig/text-buffer.zig +0 -1180
  554. package/src/zig/utf8.zig +0 -1948
  555. package/src/zig/utils.zig +0 -9
  556. package/src/zig-structs.ts +0 -261
  557. package/src/zig.ts +0 -3843
  558. package/tsconfig.build.json +0 -22
  559. package/tsconfig.json +0 -28
  560. /package/{src/lib/tree-sitter/assets → assets}/javascript/highlights.scm +0 -0
  561. /package/{src/lib/tree-sitter/assets → assets}/javascript/tree-sitter-javascript.wasm +0 -0
  562. /package/{src/lib/tree-sitter/assets → assets}/markdown/highlights.scm +0 -0
  563. /package/{src/lib/tree-sitter/assets → assets}/markdown/injections.scm +0 -0
  564. /package/{src/lib/tree-sitter/assets → assets}/markdown/tree-sitter-markdown.wasm +0 -0
  565. /package/{src/lib/tree-sitter/assets → assets}/markdown_inline/highlights.scm +0 -0
  566. /package/{src/lib/tree-sitter/assets → assets}/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  567. /package/{src/lib/tree-sitter/assets → assets}/typescript/highlights.scm +0 -0
  568. /package/{src/lib/tree-sitter/assets → assets}/typescript/tree-sitter-typescript.wasm +0 -0
  569. /package/{src/lib/tree-sitter/assets → assets}/zig/highlights.scm +0 -0
  570. /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
- })