@pierre/diffs 1.3.0-beta.5 → 1.3.0-beta.7

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 (643) hide show
  1. package/README.md +9 -9
  2. package/dist/components/CodeView.d.ts +13 -11
  3. package/dist/components/CodeView.d.ts.map +1 -1
  4. package/dist/components/CodeView.js +53 -14
  5. package/dist/components/CodeView.js.map +1 -1
  6. package/dist/components/File.d.ts +4 -5
  7. package/dist/components/File.d.ts.map +1 -1
  8. package/dist/components/File.js +37 -19
  9. package/dist/components/File.js.map +1 -1
  10. package/dist/components/FileDiff.d.ts +49 -36
  11. package/dist/components/FileDiff.d.ts.map +1 -1
  12. package/dist/components/FileDiff.js +173 -75
  13. package/dist/components/FileDiff.js.map +1 -1
  14. package/dist/components/FileStream.d.ts +0 -1
  15. package/dist/components/FileStream.d.ts.map +1 -1
  16. package/dist/components/FileStream.js +4 -4
  17. package/dist/components/FileStream.js.map +1 -1
  18. package/dist/components/UnresolvedFile.d.ts +3 -3
  19. package/dist/components/UnresolvedFile.d.ts.map +1 -1
  20. package/dist/components/UnresolvedFile.js +7 -5
  21. package/dist/components/UnresolvedFile.js.map +1 -1
  22. package/dist/components/VirtualizedFile.d.ts +0 -1
  23. package/dist/components/VirtualizedFile.d.ts.map +1 -1
  24. package/dist/components/VirtualizedFile.js +22 -25
  25. package/dist/components/VirtualizedFile.js.map +1 -1
  26. package/dist/components/VirtualizedFileDiff.d.ts +12 -7
  27. package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
  28. package/dist/components/VirtualizedFileDiff.js +192 -64
  29. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  30. package/dist/components/Virtualizer.d.ts +1 -1
  31. package/dist/components/Virtualizer.d.ts.map +1 -1
  32. package/dist/components/Virtualizer.js +23 -24
  33. package/dist/components/Virtualizer.js.map +1 -1
  34. package/dist/components/VirtulizerDevelopment.d.ts.map +1 -1
  35. package/dist/components/web-components.d.ts.map +1 -1
  36. package/dist/components/web-components.js +2 -3
  37. package/dist/components/web-components.js.map +1 -1
  38. package/dist/constants.d.ts +3 -2
  39. package/dist/constants.d.ts.map +1 -1
  40. package/dist/constants.js +3 -2
  41. package/dist/constants.js.map +1 -1
  42. package/dist/editor/command.d.ts +2 -1
  43. package/dist/editor/command.d.ts.map +1 -1
  44. package/dist/editor/command.js +7 -3
  45. package/dist/editor/command.js.map +1 -1
  46. package/dist/editor/editStack.d.ts +7 -1
  47. package/dist/editor/editStack.d.ts.map +1 -1
  48. package/dist/editor/editStack.js +3 -3
  49. package/dist/editor/editStack.js.map +1 -1
  50. package/dist/editor/editor.d.ts +28 -4
  51. package/dist/editor/editor.d.ts.map +1 -1
  52. package/dist/editor/editor.js +669 -313
  53. package/dist/editor/editor.js.map +1 -1
  54. package/dist/editor/editor2.js +3 -3
  55. package/dist/editor/editor2.js.map +1 -1
  56. package/dist/editor/index.js +1 -2
  57. package/dist/editor/lineAnnotations.d.ts.map +1 -1
  58. package/dist/editor/lineAnnotations.js +2 -3
  59. package/dist/editor/lineAnnotations.js.map +1 -1
  60. package/dist/editor/marker.d.ts +2 -1
  61. package/dist/editor/marker.d.ts.map +1 -1
  62. package/dist/editor/marker.js +28 -11
  63. package/dist/editor/marker.js.map +1 -1
  64. package/dist/editor/pieceTable.d.ts +4 -2
  65. package/dist/editor/pieceTable.d.ts.map +1 -1
  66. package/dist/editor/pieceTable.js +138 -128
  67. package/dist/editor/pieceTable.js.map +1 -1
  68. package/dist/editor/platform.d.ts +8 -1
  69. package/dist/editor/platform.d.ts.map +1 -1
  70. package/dist/editor/platform.js +16 -5
  71. package/dist/editor/platform.js.map +1 -1
  72. package/dist/editor/searchPanel.d.ts +1 -0
  73. package/dist/editor/searchPanel.d.ts.map +1 -1
  74. package/dist/editor/searchPanel.js +75 -62
  75. package/dist/editor/searchPanel.js.map +1 -1
  76. package/dist/editor/selection.d.ts +42 -5
  77. package/dist/editor/selection.d.ts.map +1 -1
  78. package/dist/editor/selection.js +504 -114
  79. package/dist/editor/selection.js.map +1 -1
  80. package/dist/editor/selectionAction.d.ts +4 -5
  81. package/dist/editor/selectionAction.d.ts.map +1 -1
  82. package/dist/editor/selectionAction.js +14 -64
  83. package/dist/editor/selectionAction.js.map +1 -1
  84. package/dist/editor/sprite.d.ts +2 -2
  85. package/dist/editor/sprite.d.ts.map +1 -1
  86. package/dist/editor/sprite.js +7 -14
  87. package/dist/editor/sprite.js.map +1 -1
  88. package/dist/editor/textDocument.d.ts +5 -4
  89. package/dist/editor/textDocument.d.ts.map +1 -1
  90. package/dist/editor/textDocument.js +26 -15
  91. package/dist/editor/textDocument.js.map +1 -1
  92. package/dist/editor/textMeasure.d.ts +36 -3
  93. package/dist/editor/textMeasure.d.ts.map +1 -1
  94. package/dist/editor/textMeasure.js +104 -17
  95. package/dist/editor/textMeasure.js.map +1 -1
  96. package/dist/editor/tokenzier.d.ts +3 -0
  97. package/dist/editor/tokenzier.d.ts.map +1 -1
  98. package/dist/editor/tokenzier.js +27 -16
  99. package/dist/editor/tokenzier.js.map +1 -1
  100. package/dist/editor/utils.d.ts +4 -1
  101. package/dist/editor/utils.d.ts.map +1 -1
  102. package/dist/editor/utils.js +19 -3
  103. package/dist/editor/utils.js.map +1 -1
  104. package/dist/highlighter/languages/areLanguagesAttached.d.ts.map +1 -1
  105. package/dist/highlighter/languages/areLanguagesAttached.js +1 -2
  106. package/dist/highlighter/languages/areLanguagesAttached.js.map +1 -1
  107. package/dist/highlighter/languages/attachResolvedLanguages.d.ts +0 -2
  108. package/dist/highlighter/languages/attachResolvedLanguages.d.ts.map +1 -1
  109. package/dist/highlighter/languages/attachResolvedLanguages.js +1 -2
  110. package/dist/highlighter/languages/attachResolvedLanguages.js.map +1 -1
  111. package/dist/highlighter/languages/cleanUpResolvedLanguages.d.ts.map +1 -1
  112. package/dist/highlighter/languages/cleanUpResolvedLanguages.js +1 -2
  113. package/dist/highlighter/languages/cleanUpResolvedLanguages.js.map +1 -1
  114. package/dist/highlighter/languages/constants.d.ts +0 -1
  115. package/dist/highlighter/languages/constants.d.ts.map +1 -1
  116. package/dist/highlighter/languages/constants.js +1 -1
  117. package/dist/highlighter/languages/constants.js.map +1 -1
  118. package/dist/highlighter/languages/getResolvedLanguages.d.ts +0 -2
  119. package/dist/highlighter/languages/getResolvedLanguages.d.ts.map +1 -1
  120. package/dist/highlighter/languages/getResolvedLanguages.js +1 -2
  121. package/dist/highlighter/languages/getResolvedLanguages.js.map +1 -1
  122. package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts +0 -2
  123. package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts.map +1 -1
  124. package/dist/highlighter/languages/getResolvedOrResolveLanguage.js +1 -2
  125. package/dist/highlighter/languages/getResolvedOrResolveLanguage.js.map +1 -1
  126. package/dist/highlighter/languages/hasResolvedLanguages.d.ts.map +1 -1
  127. package/dist/highlighter/languages/hasResolvedLanguages.js +1 -2
  128. package/dist/highlighter/languages/hasResolvedLanguages.js.map +1 -1
  129. package/dist/highlighter/languages/registerCustomLanguage.d.ts +0 -1
  130. package/dist/highlighter/languages/registerCustomLanguage.d.ts.map +1 -1
  131. package/dist/highlighter/languages/registerCustomLanguage.js +1 -2
  132. package/dist/highlighter/languages/registerCustomLanguage.js.map +1 -1
  133. package/dist/highlighter/languages/resolveLanguage.d.ts +0 -2
  134. package/dist/highlighter/languages/resolveLanguage.d.ts.map +1 -1
  135. package/dist/highlighter/languages/resolveLanguage.js +4 -5
  136. package/dist/highlighter/languages/resolveLanguage.js.map +1 -1
  137. package/dist/highlighter/languages/resolveLanguages.d.ts +0 -2
  138. package/dist/highlighter/languages/resolveLanguages.d.ts.map +1 -1
  139. package/dist/highlighter/languages/resolveLanguages.js +1 -2
  140. package/dist/highlighter/languages/resolveLanguages.js.map +1 -1
  141. package/dist/highlighter/shared_highlighter.d.ts.map +1 -1
  142. package/dist/highlighter/shared_highlighter.js +3 -4
  143. package/dist/highlighter/shared_highlighter.js.map +1 -1
  144. package/dist/highlighter/themes/areThemesAttached.d.ts.map +1 -1
  145. package/dist/highlighter/themes/areThemesAttached.js +1 -2
  146. package/dist/highlighter/themes/areThemesAttached.js.map +1 -1
  147. package/dist/highlighter/themes/attachResolvedThemes.d.ts.map +1 -1
  148. package/dist/highlighter/themes/attachResolvedThemes.js +1 -2
  149. package/dist/highlighter/themes/attachResolvedThemes.js.map +1 -1
  150. package/dist/highlighter/themes/cleanUpResolvedThemes.d.ts.map +1 -1
  151. package/dist/highlighter/themes/cleanUpResolvedThemes.js +1 -2
  152. package/dist/highlighter/themes/cleanUpResolvedThemes.js.map +1 -1
  153. package/dist/highlighter/themes/constants.d.ts.map +1 -1
  154. package/dist/highlighter/themes/constants.js +1 -1
  155. package/dist/highlighter/themes/constants.js.map +1 -1
  156. package/dist/highlighter/themes/getResolvedOrResolveTheme.d.ts.map +1 -1
  157. package/dist/highlighter/themes/getResolvedOrResolveTheme.js +1 -2
  158. package/dist/highlighter/themes/getResolvedOrResolveTheme.js.map +1 -1
  159. package/dist/highlighter/themes/getResolvedThemes.d.ts.map +1 -1
  160. package/dist/highlighter/themes/getResolvedThemes.js +1 -2
  161. package/dist/highlighter/themes/getResolvedThemes.js.map +1 -1
  162. package/dist/highlighter/themes/hasResolvedThemes.d.ts.map +1 -1
  163. package/dist/highlighter/themes/hasResolvedThemes.js +1 -2
  164. package/dist/highlighter/themes/hasResolvedThemes.js.map +1 -1
  165. package/dist/highlighter/themes/registerCustomCSSVariableTheme.d.ts.map +1 -1
  166. package/dist/highlighter/themes/registerCustomCSSVariableTheme.js +1 -2
  167. package/dist/highlighter/themes/registerCustomCSSVariableTheme.js.map +1 -1
  168. package/dist/highlighter/themes/registerCustomTheme.d.ts.map +1 -1
  169. package/dist/highlighter/themes/registerCustomTheme.js +1 -2
  170. package/dist/highlighter/themes/registerCustomTheme.js.map +1 -1
  171. package/dist/highlighter/themes/resolveTheme.d.ts.map +1 -1
  172. package/dist/highlighter/themes/resolveTheme.js +1 -2
  173. package/dist/highlighter/themes/resolveTheme.js.map +1 -1
  174. package/dist/highlighter/themes/resolveThemes.d.ts.map +1 -1
  175. package/dist/highlighter/themes/resolveThemes.js +1 -2
  176. package/dist/highlighter/themes/resolveThemes.js.map +1 -1
  177. package/dist/highlighter/themes/themeResolution.d.ts.map +1 -1
  178. package/dist/highlighter/themes/themeResolution.js +1 -2
  179. package/dist/highlighter/themes/themeResolution.js.map +1 -1
  180. package/dist/highlighter/themes/themeResolver.d.ts +2 -2
  181. package/dist/highlighter/themes/themeResolver.d.ts.map +1 -1
  182. package/dist/highlighter/themes/themeResolver.js +1 -2
  183. package/dist/highlighter/themes/themeResolver.js.map +1 -1
  184. package/dist/index.d.ts +12 -10
  185. package/dist/index.js +4 -3
  186. package/dist/managers/InteractionManager.d.ts +7 -0
  187. package/dist/managers/InteractionManager.d.ts.map +1 -1
  188. package/dist/managers/InteractionManager.js +25 -4
  189. package/dist/managers/InteractionManager.js.map +1 -1
  190. package/dist/managers/ResizeManager.d.ts.map +1 -1
  191. package/dist/managers/ResizeManager.js +1 -1
  192. package/dist/managers/ResizeManager.js.map +1 -1
  193. package/dist/managers/ScrollSyncManager.d.ts.map +1 -1
  194. package/dist/managers/ScrollSyncManager.js +1 -1
  195. package/dist/managers/ScrollSyncManager.js.map +1 -1
  196. package/dist/managers/UniversalRenderingManager.d.ts.map +1 -1
  197. package/dist/managers/UniversalRenderingManager.js +2 -2
  198. package/dist/managers/UniversalRenderingManager.js.map +1 -1
  199. package/dist/node_modules/.pnpm/@types_hast@3.0.4/node_modules/@types/hast/index.d.ts +228 -0
  200. package/dist/node_modules/.pnpm/@types_hast@3.0.4/node_modules/@types/hast/index.d.ts.map +1 -0
  201. package/dist/node_modules/.pnpm/@types_unist@3.0.3/node_modules/@types/unist/index.d.ts +84 -0
  202. package/dist/node_modules/.pnpm/@types_unist@3.0.3/node_modules/@types/unist/index.d.ts.map +1 -0
  203. package/dist/react/CodeView.d.ts +1 -1
  204. package/dist/react/CodeView.d.ts.map +1 -1
  205. package/dist/react/CodeView.js +17 -16
  206. package/dist/react/CodeView.js.map +1 -1
  207. package/dist/react/EditorContext.d.ts +0 -1
  208. package/dist/react/EditorContext.d.ts.map +1 -1
  209. package/dist/react/EditorContext.js +2 -5
  210. package/dist/react/EditorContext.js.map +1 -1
  211. package/dist/react/File.d.ts +1 -0
  212. package/dist/react/File.d.ts.map +1 -1
  213. package/dist/react/File.js +4 -6
  214. package/dist/react/File.js.map +1 -1
  215. package/dist/react/FileDiff.d.ts +1 -0
  216. package/dist/react/FileDiff.d.ts.map +1 -1
  217. package/dist/react/FileDiff.js +4 -6
  218. package/dist/react/FileDiff.js.map +1 -1
  219. package/dist/react/MultiFileDiff.d.ts +4 -4
  220. package/dist/react/MultiFileDiff.d.ts.map +1 -1
  221. package/dist/react/MultiFileDiff.js +4 -6
  222. package/dist/react/MultiFileDiff.js.map +1 -1
  223. package/dist/react/PatchDiff.d.ts +1 -0
  224. package/dist/react/PatchDiff.d.ts.map +1 -1
  225. package/dist/react/PatchDiff.js +4 -6
  226. package/dist/react/PatchDiff.js.map +1 -1
  227. package/dist/react/UnresolvedFile.d.ts +2 -1
  228. package/dist/react/UnresolvedFile.d.ts.map +1 -1
  229. package/dist/react/UnresolvedFile.js +4 -6
  230. package/dist/react/UnresolvedFile.js.map +1 -1
  231. package/dist/react/Virtualizer.d.ts.map +1 -1
  232. package/dist/react/Virtualizer.js +2 -5
  233. package/dist/react/Virtualizer.js.map +1 -1
  234. package/dist/react/WorkerPoolContext.d.ts +0 -1
  235. package/dist/react/WorkerPoolContext.d.ts.map +1 -1
  236. package/dist/react/WorkerPoolContext.js +2 -5
  237. package/dist/react/WorkerPoolContext.js.map +1 -1
  238. package/dist/react/constants.d.ts.map +1 -1
  239. package/dist/react/constants.js +1 -1
  240. package/dist/react/constants.js.map +1 -1
  241. package/dist/react/index.d.ts +2 -2
  242. package/dist/react/index.js +1 -2
  243. package/dist/react/jsx.d.ts +0 -2
  244. package/dist/react/jsx.d.ts.map +1 -1
  245. package/dist/react/types.d.ts +2 -0
  246. package/dist/react/types.d.ts.map +1 -1
  247. package/dist/react/utils/renderDiffChildren.d.ts +2 -0
  248. package/dist/react/utils/renderDiffChildren.d.ts.map +1 -1
  249. package/dist/react/utils/renderDiffChildren.js +18 -11
  250. package/dist/react/utils/renderDiffChildren.js.map +1 -1
  251. package/dist/react/utils/renderFileChildren.d.ts +2 -0
  252. package/dist/react/utils/renderFileChildren.d.ts.map +1 -1
  253. package/dist/react/utils/renderFileChildren.js +18 -11
  254. package/dist/react/utils/renderFileChildren.js.map +1 -1
  255. package/dist/react/utils/templateRender.d.ts.map +1 -1
  256. package/dist/react/utils/templateRender.js +1 -2
  257. package/dist/react/utils/templateRender.js.map +1 -1
  258. package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
  259. package/dist/react/utils/useFileDiffInstance.js +15 -18
  260. package/dist/react/utils/useFileDiffInstance.js.map +1 -1
  261. package/dist/react/utils/useFileInstance.d.ts.map +1 -1
  262. package/dist/react/utils/useFileInstance.js +1 -2
  263. package/dist/react/utils/useFileInstance.js.map +1 -1
  264. package/dist/react/utils/useStableCallback.d.ts.map +1 -1
  265. package/dist/react/utils/useStableCallback.js +1 -2
  266. package/dist/react/utils/useStableCallback.js.map +1 -1
  267. package/dist/react/utils/useUnresolvedFileInstance.d.ts.map +1 -1
  268. package/dist/react/utils/useUnresolvedFileInstance.js +10 -11
  269. package/dist/react/utils/useUnresolvedFileInstance.js.map +1 -1
  270. package/dist/renderers/DiffHunksRenderer.d.ts +2 -3
  271. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  272. package/dist/renderers/DiffHunksRenderer.js +52 -33
  273. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  274. package/dist/renderers/FileRenderer.d.ts +1 -3
  275. package/dist/renderers/FileRenderer.d.ts.map +1 -1
  276. package/dist/renderers/FileRenderer.js +14 -11
  277. package/dist/renderers/FileRenderer.js.map +1 -1
  278. package/dist/renderers/UnresolvedFileHunksRenderer.d.ts +1 -2
  279. package/dist/renderers/UnresolvedFileHunksRenderer.d.ts.map +1 -1
  280. package/dist/renderers/UnresolvedFileHunksRenderer.js +1 -2
  281. package/dist/renderers/UnresolvedFileHunksRenderer.js.map +1 -1
  282. package/dist/shiki-stream/index.js +1 -2
  283. package/dist/shiki-stream/stream.d.ts +0 -1
  284. package/dist/shiki-stream/stream.d.ts.map +1 -1
  285. package/dist/shiki-stream/stream.js +1 -2
  286. package/dist/shiki-stream/stream.js.map +1 -1
  287. package/dist/shiki-stream/tokenizer.d.ts.map +1 -1
  288. package/dist/shiki-stream/tokenizer.js +1 -1
  289. package/dist/shiki-stream/tokenizer.js.map +1 -1
  290. package/dist/shiki-stream/types.d.ts +0 -1
  291. package/dist/shiki-stream/types.d.ts.map +1 -1
  292. package/dist/sprite.d.ts.map +1 -1
  293. package/dist/sprite.js +1 -1
  294. package/dist/ssr/FileDiffReact.d.ts.map +1 -1
  295. package/dist/ssr/FileDiffReact.js +5 -8
  296. package/dist/ssr/FileDiffReact.js.map +1 -1
  297. package/dist/ssr/index.d.ts +2 -2
  298. package/dist/ssr/index.js +1 -2
  299. package/dist/ssr/preloadDiffs.d.ts +12 -11
  300. package/dist/ssr/preloadDiffs.d.ts.map +1 -1
  301. package/dist/ssr/preloadDiffs.js +15 -8
  302. package/dist/ssr/preloadDiffs.js.map +1 -1
  303. package/dist/ssr/preloadFile.d.ts.map +1 -1
  304. package/dist/ssr/preloadFile.js +1 -2
  305. package/dist/ssr/preloadFile.js.map +1 -1
  306. package/dist/ssr/preloadPatchFile.d.ts.map +1 -1
  307. package/dist/ssr/preloadPatchFile.js +2 -3
  308. package/dist/ssr/preloadPatchFile.js.map +1 -1
  309. package/dist/ssr/renderHTML.d.ts +1 -1
  310. package/dist/ssr/renderHTML.d.ts.map +1 -1
  311. package/dist/ssr/renderHTML.js +1 -2
  312. package/dist/ssr/renderHTML.js.map +1 -1
  313. package/dist/string-import.d.ts +4 -0
  314. package/dist/string-import.d.ts.map +1 -1
  315. package/dist/style.js +3 -3
  316. package/dist/style.js.map +1 -1
  317. package/dist/types.d.ts +67 -7
  318. package/dist/types.d.ts.map +1 -1
  319. package/dist/utils/areDiffLineAnnotationsEqual.d.ts.map +1 -1
  320. package/dist/utils/areDiffLineAnnotationsEqual.js +1 -1
  321. package/dist/utils/areDiffLineAnnotationsEqual.js.map +1 -1
  322. package/dist/utils/areDiffRenderOptionsEqual.d.ts.map +1 -1
  323. package/dist/utils/areDiffRenderOptionsEqual.js +1 -2
  324. package/dist/utils/areDiffRenderOptionsEqual.js.map +1 -1
  325. package/dist/utils/areDiffTargetsEqual.d.ts.map +1 -1
  326. package/dist/utils/areDiffTargetsEqual.js +1 -1
  327. package/dist/utils/areDiffTargetsEqual.js.map +1 -1
  328. package/dist/utils/areFileRenderOptionsEqual.d.ts.map +1 -1
  329. package/dist/utils/areFileRenderOptionsEqual.js +1 -2
  330. package/dist/utils/areFileRenderOptionsEqual.js.map +1 -1
  331. package/dist/utils/areFilesEqual.d.ts.map +1 -1
  332. package/dist/utils/areFilesEqual.js +1 -1
  333. package/dist/utils/areFilesEqual.js.map +1 -1
  334. package/dist/utils/areHunkDataEqual.d.ts.map +1 -1
  335. package/dist/utils/areHunkDataEqual.js +2 -2
  336. package/dist/utils/areHunkDataEqual.js.map +1 -1
  337. package/dist/utils/areLineAnnotationsEqual.d.ts.map +1 -1
  338. package/dist/utils/areLineAnnotationsEqual.js +1 -1
  339. package/dist/utils/areLineAnnotationsEqual.js.map +1 -1
  340. package/dist/utils/areManagedSnapshotsEqual.d.ts.map +1 -1
  341. package/dist/utils/areManagedSnapshotsEqual.js +1 -1
  342. package/dist/utils/areManagedSnapshotsEqual.js.map +1 -1
  343. package/dist/utils/areMergeConflictActionsEqual.d.ts.map +1 -1
  344. package/dist/utils/areMergeConflictActionsEqual.js +1 -1
  345. package/dist/utils/areMergeConflictActionsEqual.js.map +1 -1
  346. package/dist/utils/areObjectsEqual.d.ts.map +1 -1
  347. package/dist/utils/areObjectsEqual.js +1 -1
  348. package/dist/utils/areObjectsEqual.js.map +1 -1
  349. package/dist/utils/areOptionsEqual.d.ts +0 -2
  350. package/dist/utils/areOptionsEqual.d.ts.map +1 -1
  351. package/dist/utils/areOptionsEqual.js +1 -2
  352. package/dist/utils/areOptionsEqual.js.map +1 -1
  353. package/dist/utils/arePrePropertiesEqual.d.ts.map +1 -1
  354. package/dist/utils/arePrePropertiesEqual.js +1 -1
  355. package/dist/utils/arePrePropertiesEqual.js.map +1 -1
  356. package/dist/utils/areRenderRangesEqual.d.ts.map +1 -1
  357. package/dist/utils/areRenderRangesEqual.js +1 -1
  358. package/dist/utils/areRenderRangesEqual.js.map +1 -1
  359. package/dist/utils/areSelectionPointsEqual.d.ts.map +1 -1
  360. package/dist/utils/areSelectionPointsEqual.js +1 -1
  361. package/dist/utils/areSelectionPointsEqual.js.map +1 -1
  362. package/dist/utils/areSelectionsEqual.d.ts.map +1 -1
  363. package/dist/utils/areSelectionsEqual.js +1 -1
  364. package/dist/utils/areSelectionsEqual.js.map +1 -1
  365. package/dist/utils/areThemesEqual.d.ts.map +1 -1
  366. package/dist/utils/areThemesEqual.js +1 -1
  367. package/dist/utils/areThemesEqual.js.map +1 -1
  368. package/dist/utils/areVirtualWindowSpecsEqual.d.ts.map +1 -1
  369. package/dist/utils/areVirtualWindowSpecsEqual.js +1 -1
  370. package/dist/utils/areVirtualWindowSpecsEqual.js.map +1 -1
  371. package/dist/utils/areWorkerStatsEqual.d.ts +0 -2
  372. package/dist/utils/areWorkerStatsEqual.d.ts.map +1 -1
  373. package/dist/utils/areWorkerStatsEqual.js +1 -1
  374. package/dist/utils/areWorkerStatsEqual.js.map +1 -1
  375. package/dist/utils/awaitWithTimeout.d.ts +5 -0
  376. package/dist/utils/awaitWithTimeout.d.ts.map +1 -0
  377. package/dist/utils/awaitWithTimeout.js +15 -0
  378. package/dist/utils/awaitWithTimeout.js.map +1 -0
  379. package/dist/utils/cleanLastNewline.d.ts.map +1 -1
  380. package/dist/utils/cleanLastNewline.js +1 -1
  381. package/dist/utils/cleanLastNewline.js.map +1 -1
  382. package/dist/utils/cloneFileDiffMetadata.d.ts +7 -0
  383. package/dist/utils/cloneFileDiffMetadata.d.ts.map +1 -0
  384. package/dist/utils/cloneFileDiffMetadata.js +16 -0
  385. package/dist/utils/cloneFileDiffMetadata.js.map +1 -0
  386. package/dist/utils/computeEstimatedDiffHeights.d.ts +3 -1
  387. package/dist/utils/computeEstimatedDiffHeights.d.ts.map +1 -1
  388. package/dist/utils/computeEstimatedDiffHeights.js +9 -3
  389. package/dist/utils/computeEstimatedDiffHeights.js.map +1 -1
  390. package/dist/utils/computeFileOffsets.d.ts +9 -1
  391. package/dist/utils/computeFileOffsets.d.ts.map +1 -1
  392. package/dist/utils/computeFileOffsets.js +20 -2
  393. package/dist/utils/computeFileOffsets.js.map +1 -1
  394. package/dist/utils/computeVirtualFileMetrics.d.ts.map +1 -1
  395. package/dist/utils/computeVirtualFileMetrics.js +1 -2
  396. package/dist/utils/computeVirtualFileMetrics.js.map +1 -1
  397. package/dist/utils/createAnnotationElement.d.ts +1 -1
  398. package/dist/utils/createAnnotationElement.d.ts.map +1 -1
  399. package/dist/utils/createAnnotationElement.js +1 -2
  400. package/dist/utils/createAnnotationElement.js.map +1 -1
  401. package/dist/utils/createAnnotationWrapperNode.d.ts.map +1 -1
  402. package/dist/utils/createAnnotationWrapperNode.js +1 -1
  403. package/dist/utils/createAnnotationWrapperNode.js.map +1 -1
  404. package/dist/utils/createContentColumn.d.ts +1 -1
  405. package/dist/utils/createContentColumn.d.ts.map +1 -1
  406. package/dist/utils/createContentColumn.js +1 -2
  407. package/dist/utils/createContentColumn.js.map +1 -1
  408. package/dist/utils/createEmptyRowBuffer.d.ts +1 -1
  409. package/dist/utils/createEmptyRowBuffer.d.ts.map +1 -1
  410. package/dist/utils/createEmptyRowBuffer.js +1 -2
  411. package/dist/utils/createEmptyRowBuffer.js.map +1 -1
  412. package/dist/utils/createFileHeaderElement.d.ts +1 -1
  413. package/dist/utils/createFileHeaderElement.d.ts.map +1 -1
  414. package/dist/utils/createFileHeaderElement.js +6 -3
  415. package/dist/utils/createFileHeaderElement.js.map +1 -1
  416. package/dist/utils/createGutterUtilityContentNode.d.ts.map +1 -1
  417. package/dist/utils/createGutterUtilityContentNode.js +1 -1
  418. package/dist/utils/createGutterUtilityContentNode.js.map +1 -1
  419. package/dist/utils/createGutterUtilityElement.d.ts +1 -1
  420. package/dist/utils/createGutterUtilityElement.d.ts.map +1 -1
  421. package/dist/utils/createGutterUtilityElement.js +1 -2
  422. package/dist/utils/createGutterUtilityElement.js.map +1 -1
  423. package/dist/utils/createNoNewlineElement.d.ts +1 -1
  424. package/dist/utils/createNoNewlineElement.d.ts.map +1 -1
  425. package/dist/utils/createNoNewlineElement.js +1 -2
  426. package/dist/utils/createNoNewlineElement.js.map +1 -1
  427. package/dist/utils/createPreElement.d.ts +1 -1
  428. package/dist/utils/createPreElement.d.ts.map +1 -1
  429. package/dist/utils/createPreElement.js +1 -3
  430. package/dist/utils/createPreElement.js.map +1 -1
  431. package/dist/utils/createRowNodes.d.ts.map +1 -1
  432. package/dist/utils/createRowNodes.js +1 -1
  433. package/dist/utils/createRowNodes.js.map +1 -1
  434. package/dist/utils/createSeparator.d.ts +1 -1
  435. package/dist/utils/createSeparator.d.ts.map +1 -1
  436. package/dist/utils/createSeparator.js +1 -2
  437. package/dist/utils/createSeparator.js.map +1 -1
  438. package/dist/utils/createSpanNodeFromToken.d.ts.map +1 -1
  439. package/dist/utils/createSpanNodeFromToken.js +1 -2
  440. package/dist/utils/createSpanNodeFromToken.js.map +1 -1
  441. package/dist/utils/createStyleElement.d.ts +1 -1
  442. package/dist/utils/createStyleElement.d.ts.map +1 -1
  443. package/dist/utils/createStyleElement.js +1 -2
  444. package/dist/utils/createStyleElement.js.map +1 -1
  445. package/dist/utils/createTransformerWithState.d.ts.map +1 -1
  446. package/dist/utils/createTransformerWithState.js +1 -2
  447. package/dist/utils/createTransformerWithState.js.map +1 -1
  448. package/dist/utils/createUnsafeCSSStyleNode.d.ts.map +1 -1
  449. package/dist/utils/createUnsafeCSSStyleNode.js +1 -2
  450. package/dist/utils/createUnsafeCSSStyleNode.js.map +1 -1
  451. package/dist/utils/createWindowFromScrollPosition.d.ts.map +1 -1
  452. package/dist/utils/createWindowFromScrollPosition.js +5 -5
  453. package/dist/utils/createWindowFromScrollPosition.js.map +1 -1
  454. package/dist/utils/cssWrappers.d.ts.map +1 -1
  455. package/dist/utils/cssWrappers.js +2 -3
  456. package/dist/utils/cssWrappers.js.map +1 -1
  457. package/dist/utils/detachString.d.ts.map +1 -1
  458. package/dist/utils/detachString.js +1 -1
  459. package/dist/utils/detachString.js.map +1 -1
  460. package/dist/utils/diffAcceptRejectHunk.d.ts.map +1 -1
  461. package/dist/utils/diffAcceptRejectHunk.js +1 -2
  462. package/dist/utils/diffAcceptRejectHunk.js.map +1 -1
  463. package/dist/utils/formatCSSVariablePrefix.d.ts.map +1 -1
  464. package/dist/utils/formatCSSVariablePrefix.js +1 -1
  465. package/dist/utils/formatCSSVariablePrefix.js.map +1 -1
  466. package/dist/utils/getDiffFileInput.d.ts +14 -0
  467. package/dist/utils/getDiffFileInput.d.ts.map +1 -0
  468. package/dist/utils/getDiffFileInput.js +24 -0
  469. package/dist/utils/getDiffFileInput.js.map +1 -0
  470. package/dist/utils/getDiffHunksRendererOptions.d.ts.map +1 -1
  471. package/dist/utils/getDiffHunksRendererOptions.js +2 -1
  472. package/dist/utils/getDiffHunksRendererOptions.js.map +1 -1
  473. package/dist/utils/getFileRendererOptions.d.ts.map +1 -1
  474. package/dist/utils/getFileRendererOptions.js +1 -1
  475. package/dist/utils/getFileRendererOptions.js.map +1 -1
  476. package/dist/utils/getFiletypeFromFileName.d.ts.map +1 -1
  477. package/dist/utils/getFiletypeFromFileName.js +3 -1
  478. package/dist/utils/getFiletypeFromFileName.js.map +1 -1
  479. package/dist/utils/getHighlighterOptions.d.ts.map +1 -1
  480. package/dist/utils/getHighlighterOptions.js +1 -2
  481. package/dist/utils/getHighlighterOptions.js.map +1 -1
  482. package/dist/utils/getHighlighterThemeStyles.d.ts.map +1 -1
  483. package/dist/utils/getHighlighterThemeStyles.js +1 -2
  484. package/dist/utils/getHighlighterThemeStyles.js.map +1 -1
  485. package/dist/utils/getHunkSeparatorSlotName.d.ts.map +1 -1
  486. package/dist/utils/getHunkSeparatorSlotName.js +1 -1
  487. package/dist/utils/getHunkSeparatorSlotName.js.map +1 -1
  488. package/dist/utils/getIconForType.d.ts.map +1 -1
  489. package/dist/utils/getIconForType.js +1 -1
  490. package/dist/utils/getIconForType.js.map +1 -1
  491. package/dist/utils/getLineAnnotationName.d.ts.map +1 -1
  492. package/dist/utils/getLineAnnotationName.js +1 -1
  493. package/dist/utils/getLineAnnotationName.js.map +1 -1
  494. package/dist/utils/getLineEndingType.d.ts.map +1 -1
  495. package/dist/utils/getLineEndingType.js +1 -1
  496. package/dist/utils/getLineEndingType.js.map +1 -1
  497. package/dist/utils/getLineNodes.d.ts +1 -1
  498. package/dist/utils/getLineNodes.d.ts.map +1 -1
  499. package/dist/utils/getLineNodes.js +1 -1
  500. package/dist/utils/getLineNodes.js.map +1 -1
  501. package/dist/utils/getMergeConflictActionSlotName.d.ts.map +1 -1
  502. package/dist/utils/getMergeConflictActionSlotName.js +1 -1
  503. package/dist/utils/getMergeConflictActionSlotName.js.map +1 -1
  504. package/dist/utils/getMergeConflictLineTypes.d.ts.map +1 -1
  505. package/dist/utils/getMergeConflictLineTypes.js +1 -2
  506. package/dist/utils/getMergeConflictLineTypes.js.map +1 -1
  507. package/dist/utils/getOrCreateCodeNode.d.ts.map +1 -1
  508. package/dist/utils/getOrCreateCodeNode.js +1 -1
  509. package/dist/utils/getOrCreateCodeNode.js.map +1 -1
  510. package/dist/utils/getSingularPatch.d.ts.map +1 -1
  511. package/dist/utils/getSingularPatch.js +1 -2
  512. package/dist/utils/getSingularPatch.js.map +1 -1
  513. package/dist/utils/getThemes.d.ts.map +1 -1
  514. package/dist/utils/getThemes.js +1 -2
  515. package/dist/utils/getThemes.js.map +1 -1
  516. package/dist/utils/getTotalLineCountFromHunks.d.ts.map +1 -1
  517. package/dist/utils/getTotalLineCountFromHunks.js +1 -1
  518. package/dist/utils/getTotalLineCountFromHunks.js.map +1 -1
  519. package/dist/utils/hast_utils.d.ts +1 -1
  520. package/dist/utils/hast_utils.d.ts.map +1 -1
  521. package/dist/utils/hast_utils.js +1 -1
  522. package/dist/utils/hast_utils.js.map +1 -1
  523. package/dist/utils/hostTheme.d.ts.map +1 -1
  524. package/dist/utils/hostTheme.js +1 -2
  525. package/dist/utils/hostTheme.js.map +1 -1
  526. package/dist/utils/hydratePartialDiff.d.ts +10 -0
  527. package/dist/utils/hydratePartialDiff.d.ts.map +1 -0
  528. package/dist/utils/hydratePartialDiff.js +140 -0
  529. package/dist/utils/hydratePartialDiff.js.map +1 -0
  530. package/dist/utils/includesFileAnnotations.d.ts.map +1 -1
  531. package/dist/utils/includesFileAnnotations.js +5 -5
  532. package/dist/utils/includesFileAnnotations.js.map +1 -1
  533. package/dist/utils/isDefaultRenderRange.d.ts.map +1 -1
  534. package/dist/utils/isDefaultRenderRange.js +1 -1
  535. package/dist/utils/isDefaultRenderRange.js.map +1 -1
  536. package/dist/utils/isDiffPlainText.d.ts.map +1 -1
  537. package/dist/utils/isDiffPlainText.js +1 -2
  538. package/dist/utils/isDiffPlainText.js.map +1 -1
  539. package/dist/utils/isFilePlainText.d.ts.map +1 -1
  540. package/dist/utils/isFilePlainText.js +1 -2
  541. package/dist/utils/isFilePlainText.js.map +1 -1
  542. package/dist/utils/isStyleNode.d.ts.map +1 -1
  543. package/dist/utils/isStyleNode.js +1 -1
  544. package/dist/utils/isStyleNode.js.map +1 -1
  545. package/dist/utils/isWorkerContext.d.ts.map +1 -1
  546. package/dist/utils/isWorkerContext.js +1 -1
  547. package/dist/utils/isWorkerContext.js.map +1 -1
  548. package/dist/utils/iterateOverDiff.d.ts.map +1 -1
  549. package/dist/utils/iterateOverDiff.js +47 -48
  550. package/dist/utils/iterateOverDiff.js.map +1 -1
  551. package/dist/utils/normalizeDiffResolution.d.ts.map +1 -1
  552. package/dist/utils/normalizeDiffResolution.js +1 -1
  553. package/dist/utils/normalizeDiffResolution.js.map +1 -1
  554. package/dist/utils/parseDiffDecorations.d.ts.map +1 -1
  555. package/dist/utils/parseDiffDecorations.js +1 -2
  556. package/dist/utils/parseDiffDecorations.js.map +1 -1
  557. package/dist/utils/parseDiffFromFile.d.ts +1 -2
  558. package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
  559. package/dist/utils/parseDiffFromFile.js +27 -7
  560. package/dist/utils/parseDiffFromFile.js.map +1 -1
  561. package/dist/utils/parseLineType.d.ts.map +1 -1
  562. package/dist/utils/parseLineType.js +1 -1
  563. package/dist/utils/parseLineType.js.map +1 -1
  564. package/dist/utils/parseMergeConflictDiffFromFile.d.ts.map +1 -1
  565. package/dist/utils/parseMergeConflictDiffFromFile.js +5 -5
  566. package/dist/utils/parseMergeConflictDiffFromFile.js.map +1 -1
  567. package/dist/utils/parsePatchFiles.d.ts.map +1 -1
  568. package/dist/utils/parsePatchFiles.js +6 -7
  569. package/dist/utils/parsePatchFiles.js.map +1 -1
  570. package/dist/utils/prefersReducedMotion.d.ts.map +1 -1
  571. package/dist/utils/prefersReducedMotion.js +1 -1
  572. package/dist/utils/prefersReducedMotion.js.map +1 -1
  573. package/dist/utils/prerenderHTMLIfNecessary.d.ts.map +1 -1
  574. package/dist/utils/prerenderHTMLIfNecessary.js +1 -1
  575. package/dist/utils/prerenderHTMLIfNecessary.js.map +1 -1
  576. package/dist/utils/processLine.d.ts +1 -1
  577. package/dist/utils/processLine.d.ts.map +1 -1
  578. package/dist/utils/processLine.js +1 -2
  579. package/dist/utils/processLine.js.map +1 -1
  580. package/dist/utils/renderDiffWithHighlighter.d.ts.map +1 -1
  581. package/dist/utils/renderDiffWithHighlighter.js +4 -5
  582. package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
  583. package/dist/utils/renderFileWithHighlighter.d.ts.map +1 -1
  584. package/dist/utils/renderFileWithHighlighter.js +1 -2
  585. package/dist/utils/renderFileWithHighlighter.js.map +1 -1
  586. package/dist/utils/resolveConflict.d.ts.map +1 -1
  587. package/dist/utils/resolveConflict.js +1 -2
  588. package/dist/utils/resolveConflict.js.map +1 -1
  589. package/dist/utils/resolveRegion.d.ts.map +1 -1
  590. package/dist/utils/resolveRegion.js +1 -1
  591. package/dist/utils/resolveRegion.js.map +1 -1
  592. package/dist/utils/roundToDevicePixel.d.ts.map +1 -1
  593. package/dist/utils/roundToDevicePixel.js +1 -1
  594. package/dist/utils/roundToDevicePixel.js.map +1 -1
  595. package/dist/utils/scrollbarGutter.d.ts.map +1 -1
  596. package/dist/utils/scrollbarGutter.js +1 -2
  597. package/dist/utils/scrollbarGutter.js.map +1 -1
  598. package/dist/utils/setLanguageOverride.d.ts.map +1 -1
  599. package/dist/utils/setLanguageOverride.js +1 -1
  600. package/dist/utils/setLanguageOverride.js.map +1 -1
  601. package/dist/utils/setWrapperNodeProps.d.ts.map +1 -1
  602. package/dist/utils/setWrapperNodeProps.js +1 -2
  603. package/dist/utils/setWrapperNodeProps.js.map +1 -1
  604. package/dist/utils/shouldUseTokenTransformer.d.ts.map +1 -1
  605. package/dist/utils/shouldUseTokenTransformer.js +1 -1
  606. package/dist/utils/shouldUseTokenTransformer.js.map +1 -1
  607. package/dist/utils/splitFileContents.d.ts.map +1 -1
  608. package/dist/utils/splitFileContents.js +1 -2
  609. package/dist/utils/splitFileContents.js.map +1 -1
  610. package/dist/utils/trimPatchContext.d.ts.map +1 -1
  611. package/dist/utils/trimPatchContext.js +1 -2
  612. package/dist/utils/trimPatchContext.js.map +1 -1
  613. package/dist/utils/updateDiffHunks.d.ts +6 -1
  614. package/dist/utils/updateDiffHunks.d.ts.map +1 -1
  615. package/dist/utils/updateDiffHunks.js +44 -3
  616. package/dist/utils/updateDiffHunks.js.map +1 -1
  617. package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
  618. package/dist/utils/virtualDiffLayout.js +1 -2
  619. package/dist/utils/virtualDiffLayout.js.map +1 -1
  620. package/dist/utils/wrapTokenFragments.d.ts +1 -1
  621. package/dist/utils/wrapTokenFragments.d.ts.map +1 -1
  622. package/dist/utils/wrapTokenFragments.js +1 -2
  623. package/dist/utils/wrapTokenFragments.js.map +1 -1
  624. package/dist/worker/WorkerPoolManager.d.ts +7 -2
  625. package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
  626. package/dist/worker/WorkerPoolManager.js +83 -20
  627. package/dist/worker/WorkerPoolManager.js.map +1 -1
  628. package/dist/worker/getOrCreateWorkerPoolSingleton.d.ts.map +1 -1
  629. package/dist/worker/getOrCreateWorkerPoolSingleton.js +1 -2
  630. package/dist/worker/getOrCreateWorkerPoolSingleton.js.map +1 -1
  631. package/dist/worker/index.d.ts +2 -2
  632. package/dist/worker/index.js +1 -2
  633. package/dist/worker/types.d.ts +7 -1
  634. package/dist/worker/types.d.ts.map +1 -1
  635. package/dist/worker/wasm-B9ZqxnKj.js +8 -0
  636. package/dist/worker/wasm-B9ZqxnKj.js.map +1 -0
  637. package/dist/worker/worker-portable.js +2784 -6406
  638. package/dist/worker/worker-portable.js.map +1 -1
  639. package/dist/worker/worker.js +94 -126
  640. package/dist/worker/worker.js.map +1 -1
  641. package/package.json +13 -14
  642. package/dist/worker/wasm-qE0LgnY3.js +0 -10
  643. package/dist/worker/wasm-qE0LgnY3.js.map +0 -1
@@ -1,16 +1,18 @@
1
- import { h, round } from "./utils.js";
2
-
1
+ import { getGraphemeSegmenter, h, round } from "./utils.js";
3
2
  //#region src/editor/textMeasure.ts
3
+ const TEXT_WIDTH_CACHE_LIMIT = 4096;
4
4
  var Metrics = class {
5
5
  #root;
6
6
  #canvasCtx;
7
7
  #font;
8
+ #textWidthCache = /* @__PURE__ */ new Map();
8
9
  /** Width of the '0' character. */
9
10
  ch = -1;
10
11
  /** Size of a tab(\t) character. */
11
12
  tabSize = 2;
12
13
  /** Height of the code line. */
13
14
  lineHeight = 20;
15
+ /** Padding top of the root element. */
14
16
  paddingTop = 0;
15
17
  /** initialize the metrics */
16
18
  init(root) {
@@ -31,12 +33,34 @@ var Metrics = class {
31
33
  this.#font = font;
32
34
  this.#canvasCtx.font = font;
33
35
  this.ch = this.canvasMeasureTextWidth("0");
36
+ this.clearTextWidthCache();
34
37
  }
35
- this.tabSize = parseInt(tabSize, 10);
38
+ const nextTabSize = parseInt(tabSize, 10);
39
+ if (!Number.isNaN(nextTabSize)) this.tabSize = nextTabSize;
40
+ }
41
+ /**
42
+ * Re-measure the '0' character width against the font that is loaded right
43
+ * now, returning true when it changed.
44
+ *
45
+ * A custom web font can finish loading after the editor first renders.
46
+ * Until then canvas measureText reports the fallback font's width, and
47
+ * getComputedStyle returns the same font-family string before and after the
48
+ * file arrives, so init()'s font guard never re-measures on its own. Call
49
+ * this once fonts have settled (e.g. on document.fonts.ready) to replace a
50
+ * width measured against the fallback font with the real glyph width. The
51
+ * boolean return lets the caller skip re-rendering when nothing changed.
52
+ */
53
+ remeasureCharacterWidth() {
54
+ if (this.#canvasCtx === void 0 || this.#font === void 0) return false;
55
+ this.#canvasCtx.font = this.#font;
56
+ const ch = this.canvasMeasureTextWidth("0");
57
+ if (ch === this.ch) return false;
58
+ this.ch = ch;
59
+ return true;
36
60
  }
37
61
  /** measure the width of the text */
38
62
  measureTextWidth(text) {
39
- const textWithExpandedTabs = text.replaceAll(" ", " ".repeat(this.tabSize));
63
+ const textWithExpandedTabs = expandTabsToSpaces(text, this.tabSize);
40
64
  if (needsDomTextMeasurement(textWithExpandedTabs)) return this.domMeasureTextWidth(textWithExpandedTabs);
41
65
  return this.canvasMeasureTextWidth(textWithExpandedTabs);
42
66
  }
@@ -47,10 +71,14 @@ var Metrics = class {
47
71
  }
48
72
  /**
49
73
  * measure the width of the text using the DOM
50
- * this is slow because it cause a reflow, use it for non-ascii text
74
+ * this is slow because it cause a reflow, use it for non-ascii text;
75
+ * results are memoized per text so repeated measurements skip the reflow
51
76
  */
52
77
  domMeasureTextWidth(text) {
53
78
  if (this.#root === void 0) throw new Error("Metrics not initialized");
79
+ const cacheKey = text + "|" + this.#font;
80
+ const cached = this.#textWidthCache.get(cacheKey);
81
+ if (cached !== void 0) return cached;
54
82
  const measureEl = h("span", {
55
83
  style: {
56
84
  position: "absolute",
@@ -63,11 +91,26 @@ var Metrics = class {
63
91
  },
64
92
  textContent: text
65
93
  }, this.#root);
94
+ let width;
66
95
  try {
67
- return measureEl.getBoundingClientRect().width;
96
+ width = round(measureEl.getBoundingClientRect().width);
68
97
  } finally {
69
98
  measureEl.remove();
70
99
  }
100
+ if (this.#textWidthCache.size >= TEXT_WIDTH_CACHE_LIMIT) {
101
+ const oldestKey = this.#textWidthCache.keys().next().value;
102
+ if (oldestKey !== void 0) this.#textWidthCache.delete(oldestKey);
103
+ }
104
+ this.#textWidthCache.set(cacheKey, width);
105
+ return width;
106
+ }
107
+ /**
108
+ * discard memoized DOM text widths
109
+ * call this when the inherited font may have changed without re-running
110
+ * init(), e.g. on a layout reflow, so stale widths are not reused
111
+ */
112
+ clearTextWidthCache() {
113
+ this.#textWidthCache.clear();
71
114
  }
72
115
  };
73
116
  /** Check if the text needs DOM text measurement. */
@@ -82,12 +125,22 @@ function needsDomTextMeasurement(text) {
82
125
  function snapTextOffsetToUnicodeBoundary(text, offset) {
83
126
  const boundedOffset = Math.max(0, Math.min(offset, text.length));
84
127
  if (boundedOffset === 0 || boundedOffset === text.length || !needsDomTextMeasurement(text)) return boundedOffset;
85
- const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
86
- for (const segment of segmenter.segment(text)) {
87
- const segmentStart = segment.index;
88
- const segmentEnd = segmentStart + segment.segment.length;
128
+ const segmenter = getGraphemeSegmenter();
129
+ if (segmenter !== void 0) {
130
+ for (const segment of segmenter.segment(text)) {
131
+ const segmentStart = segment.index;
132
+ const segmentEnd = segmentStart + segment.segment.length;
133
+ if (boundedOffset > segmentStart && boundedOffset < segmentEnd) return segmentEnd;
134
+ if (boundedOffset <= segmentStart) break;
135
+ }
136
+ return boundedOffset;
137
+ }
138
+ let segmentStart = 0;
139
+ for (const codePoint of text) {
140
+ const segmentEnd = segmentStart + codePoint.length;
89
141
  if (boundedOffset > segmentStart && boundedOffset < segmentEnd) return segmentEnd;
90
142
  if (boundedOffset <= segmentStart) break;
143
+ segmentStart = segmentEnd;
91
144
  }
92
145
  return boundedOffset;
93
146
  }
@@ -95,20 +148,54 @@ function snapTextOffsetToUnicodeBoundary(text, offset) {
95
148
  function getUnicodeMeasurementOffsets(text) {
96
149
  if (!needsDomTextMeasurement(text)) return;
97
150
  const offsets = [0];
98
- const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
99
- for (const segment of segmenter.segment(text)) offsets.push(segment.index + segment.segment.length);
151
+ const segmenter = getGraphemeSegmenter();
152
+ if (segmenter !== void 0) {
153
+ for (const segment of segmenter.segment(text)) offsets.push(segment.index + segment.segment.length);
154
+ return offsets;
155
+ }
156
+ let offset = 0;
157
+ for (const codePoint of text) {
158
+ offset += codePoint.length;
159
+ offsets.push(offset);
160
+ }
100
161
  return offsets;
101
162
  }
102
- /** get the number of columns of the ASCII text */
163
+ /**
164
+ * Expand tab characters to spaces using fixed tab stops: each tab advances to
165
+ * the next multiple of tabSize from its running column, matching how the
166
+ * rendered text expands tabs via CSS `tab-size`. Expanding every tab to a flat
167
+ * tabSize would mis-measure tabs that follow other characters on the same line
168
+ * (e.g. an alignment tab in `foo\tbar`).
169
+ */
170
+ function expandTabsToSpaces(text, tabSize) {
171
+ if (!text.includes(" ")) return text;
172
+ let result = "";
173
+ let column = 0;
174
+ for (let i = 0; i < text.length; i++) if (text.charCodeAt(i) === 9) {
175
+ const advance = tabSize - column % tabSize;
176
+ result += " ".repeat(advance);
177
+ column += advance;
178
+ } else {
179
+ result += text[i];
180
+ column += 1;
181
+ }
182
+ return result;
183
+ }
184
+ /**
185
+ * Count the rendered columns of ASCII text, advancing each tab to the next
186
+ * fixed tab stop (a multiple of tabSize) to match CSS `tab-size`. Returns -1
187
+ * for non-ASCII text, which must be measured glyph-by-glyph instead.
188
+ */
103
189
  function getExpandedAsciiTextColumns(text, tabSize) {
104
190
  let columns = 0;
105
191
  for (let i = 0; i < text.length; i++) {
106
- if (text.charCodeAt(i) > 127) return -1;
107
- columns += text.charCodeAt(i) === 9 ? tabSize : 1;
192
+ const code = text.charCodeAt(i);
193
+ if (code > 127) return -1;
194
+ columns += code === 9 ? tabSize - columns % tabSize : 1;
108
195
  }
109
196
  return columns;
110
197
  }
111
-
112
198
  //#endregion
113
- export { Metrics, getExpandedAsciiTextColumns, getUnicodeMeasurementOffsets, needsDomTextMeasurement, snapTextOffsetToUnicodeBoundary };
199
+ export { Metrics, expandTabsToSpaces, getExpandedAsciiTextColumns, getUnicodeMeasurementOffsets, needsDomTextMeasurement, snapTextOffsetToUnicodeBoundary };
200
+
114
201
  //# sourceMappingURL=textMeasure.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"textMeasure.js","names":["#root","#canvasCtx","#font"],"sources":["../../src/editor/textMeasure.ts"],"sourcesContent":["import { h, round } from './utils';\n\nexport class Metrics {\n #root?: HTMLElement;\n #canvasCtx?: CanvasRenderingContext2D;\n #font?: string;\n\n /** Width of the '0' character. */\n ch: number = -1;\n /** Size of a tab(\\t) character. */\n tabSize: number = 2;\n /** Height of the code line. */\n lineHeight: number = 20;\n\n paddingTop: number = 0;\n\n /** initialize the metrics */\n init(root: HTMLElement): void {\n if (\n this.#root === root &&\n this.#canvasCtx !== undefined &&\n this.ch !== -1\n ) {\n // already initialized\n return;\n }\n\n this.#root = root;\n this.#canvasCtx ??=\n document.createElement('canvas').getContext('2d') ?? undefined;\n if (this.#canvasCtx === undefined) {\n throw new Error('Could not get canvas context');\n }\n\n const parent = root.parentElement;\n if (parent !== null) {\n const { paddingTop } = getComputedStyle(parent);\n if (paddingTop.endsWith('px')) {\n this.paddingTop = parseFloat(paddingTop.slice(0, -2));\n }\n }\n\n const { fontSize, fontFamily, tabSize, lineHeight } =\n getComputedStyle(root);\n if (lineHeight.endsWith('px')) {\n this.lineHeight = parseFloat(lineHeight.slice(0, -2));\n } else if (fontSize.endsWith('px')) {\n this.lineHeight = round(\n parseFloat(fontSize.slice(0, -2)) * parseFloat(lineHeight)\n );\n }\n const font = fontSize + ' ' + fontFamily;\n if (this.#font !== font || this.ch === -1) {\n this.#font = font;\n this.#canvasCtx.font = font;\n this.ch = this.canvasMeasureTextWidth('0');\n }\n this.tabSize = parseInt(tabSize, 10);\n }\n\n /** measure the width of the text */\n measureTextWidth(text: string): number {\n const textWithExpandedTabs = text.replaceAll(\n '\\t',\n ' '.repeat(this.tabSize)\n );\n if (needsDomTextMeasurement(textWithExpandedTabs)) {\n return this.domMeasureTextWidth(textWithExpandedTabs);\n }\n return this.canvasMeasureTextWidth(textWithExpandedTabs);\n }\n\n /** measure the width of the text using the canvas measureText API */\n canvasMeasureTextWidth(text: string): number {\n if (this.#canvasCtx === undefined) {\n throw new Error('Metrics not initialized');\n }\n return round(this.#canvasCtx.measureText(text).width);\n }\n\n /**\n * measure the width of the text using the DOM\n * this is slow because it cause a reflow, use it for non-ascii text\n */\n domMeasureTextWidth(text: string): number {\n if (this.#root === undefined) {\n throw new Error('Metrics not initialized');\n }\n const measureEl = h(\n 'span',\n {\n style: {\n position: 'absolute',\n top: '0',\n left: '0',\n visibility: 'hidden',\n pointerEvents: 'none',\n whiteSpace: 'pre',\n font: 'inherit',\n },\n textContent: text,\n },\n this.#root\n );\n try {\n return measureEl.getBoundingClientRect().width;\n } finally {\n measureEl.remove();\n }\n }\n}\n\n/** Check if the text needs DOM text measurement. */\nexport function needsDomTextMeasurement(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n if (\n (code >= 0xd800 && code <= 0xdfff) ||\n code === 0x200d ||\n code === 0xfe0e ||\n code === 0xfe0f\n ) {\n return true;\n }\n }\n return false;\n}\n\n/** snap the text offset to the Unicode boundary */\nexport function snapTextOffsetToUnicodeBoundary(\n text: string,\n offset: number\n): number {\n const boundedOffset = Math.max(0, Math.min(offset, text.length));\n if (\n boundedOffset === 0 ||\n boundedOffset === text.length ||\n !needsDomTextMeasurement(text)\n ) {\n return boundedOffset;\n }\n // Avoid measuring a caret position inside one visual emoji/grapheme.\n // Browser caret movement can report offsets around UTF-16 surrogate\n // pairs and emoji joiners; measuring a partial sequence gives a\n // replacement-glyph width.\n const segmenter = new Intl.Segmenter(undefined, {\n granularity: 'grapheme',\n });\n for (const segment of segmenter.segment(text)) {\n const segmentStart = segment.index;\n const segmentEnd = segmentStart + segment.segment.length;\n if (boundedOffset > segmentStart && boundedOffset < segmentEnd) {\n return segmentEnd;\n }\n if (boundedOffset <= segmentStart) {\n break;\n }\n }\n return boundedOffset;\n}\n\n/** get the offsets of the Unicode grapheme clusters in the text */\nexport function getUnicodeMeasurementOffsets(\n text: string\n): number[] | undefined {\n if (!needsDomTextMeasurement(text)) {\n return undefined;\n }\n const offsets = [0];\n const segmenter = new Intl.Segmenter(undefined, {\n granularity: 'grapheme',\n });\n for (const segment of segmenter.segment(text)) {\n offsets.push(segment.index + segment.segment.length);\n }\n return offsets;\n}\n\n/** get the number of columns of the ASCII text */\nexport function getExpandedAsciiTextColumns(\n text: string,\n tabSize: number\n): number {\n let columns = 0;\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) > 127) {\n return -1;\n }\n columns += text.charCodeAt(i) === /* '\\t' */ 9 ? tabSize : 1;\n }\n return columns;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"textMeasure.js","names":["#root","#canvasCtx","#font","#textWidthCache"],"sources":["../../src/editor/textMeasure.ts"],"sourcesContent":["import { getGraphemeSegmenter, h, round } from './utils';\n\n// Upper bound on cached DOM text-width measurements. The cache only holds\n// non-ASCII runs (emoji, ZWJ sequences, variation selectors), so it stays\n// small for ordinary code, but capping it prevents unbounded growth on\n// emoji-heavy documents. Past the cap the oldest entry is evicted.\nconst TEXT_WIDTH_CACHE_LIMIT = 4096;\n\nexport class Metrics {\n #root?: HTMLElement;\n #canvasCtx?: CanvasRenderingContext2D;\n #font?: string;\n\n // Memoizes domMeasureTextWidth() results\n #textWidthCache = new Map<string, number>();\n\n /** Width of the '0' character. */\n ch: number = -1;\n /** Size of a tab(\\t) character. */\n tabSize: number = 2;\n /** Height of the code line. */\n lineHeight: number = 20;\n /** Padding top of the root element. */\n paddingTop: number = 0;\n\n /** initialize the metrics */\n init(root: HTMLElement): void {\n if (\n this.#root === root &&\n this.#canvasCtx !== undefined &&\n this.ch !== -1\n ) {\n // already initialized\n return;\n }\n\n this.#root = root;\n this.#canvasCtx ??=\n document.createElement('canvas').getContext('2d') ?? undefined;\n if (this.#canvasCtx === undefined) {\n throw new Error('Could not get canvas context');\n }\n\n const parent = root.parentElement;\n if (parent !== null) {\n const { paddingTop } = getComputedStyle(parent);\n if (paddingTop.endsWith('px')) {\n this.paddingTop = parseFloat(paddingTop.slice(0, -2));\n }\n }\n\n const { fontSize, fontFamily, tabSize, lineHeight } =\n getComputedStyle(root);\n if (lineHeight.endsWith('px')) {\n this.lineHeight = parseFloat(lineHeight.slice(0, -2));\n } else if (fontSize.endsWith('px')) {\n this.lineHeight = round(\n parseFloat(fontSize.slice(0, -2)) * parseFloat(lineHeight)\n );\n }\n const font = fontSize + ' ' + fontFamily;\n if (this.#font !== font || this.ch === -1) {\n this.#font = font;\n this.#canvasCtx.font = font;\n this.ch = this.canvasMeasureTextWidth('0');\n // Cached DOM widths were measured against the previous font.\n this.clearTextWidthCache();\n }\n const nextTabSize = parseInt(tabSize, 10);\n if (!Number.isNaN(nextTabSize)) {\n this.tabSize = nextTabSize;\n }\n }\n\n /**\n * Re-measure the '0' character width against the font that is loaded right\n * now, returning true when it changed.\n *\n * A custom web font can finish loading after the editor first renders.\n * Until then canvas measureText reports the fallback font's width, and\n * getComputedStyle returns the same font-family string before and after the\n * file arrives, so init()'s font guard never re-measures on its own. Call\n * this once fonts have settled (e.g. on document.fonts.ready) to replace a\n * width measured against the fallback font with the real glyph width. The\n * boolean return lets the caller skip re-rendering when nothing changed.\n */\n remeasureCharacterWidth(): boolean {\n if (this.#canvasCtx === undefined || this.#font === undefined) {\n return false;\n }\n this.#canvasCtx.font = this.#font;\n const ch = this.canvasMeasureTextWidth('0');\n if (ch === this.ch) {\n return false;\n }\n this.ch = ch;\n return true;\n }\n\n /** measure the width of the text */\n measureTextWidth(text: string): number {\n const textWithExpandedTabs = expandTabsToSpaces(text, this.tabSize);\n if (needsDomTextMeasurement(textWithExpandedTabs)) {\n return this.domMeasureTextWidth(textWithExpandedTabs);\n }\n return this.canvasMeasureTextWidth(textWithExpandedTabs);\n }\n\n /** measure the width of the text using the canvas measureText API */\n canvasMeasureTextWidth(text: string): number {\n if (this.#canvasCtx === undefined) {\n throw new Error('Metrics not initialized');\n }\n return round(this.#canvasCtx.measureText(text).width);\n }\n\n /**\n * measure the width of the text using the DOM\n * this is slow because it cause a reflow, use it for non-ascii text;\n * results are memoized per text so repeated measurements skip the reflow\n */\n domMeasureTextWidth(text: string): number {\n if (this.#root === undefined) {\n throw new Error('Metrics not initialized');\n }\n const cacheKey = text + '|' + this.#font;\n const cached = this.#textWidthCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n const measureEl = h(\n 'span',\n {\n style: {\n position: 'absolute',\n top: '0',\n left: '0',\n visibility: 'hidden',\n pointerEvents: 'none',\n whiteSpace: 'pre',\n font: 'inherit',\n },\n textContent: text,\n },\n this.#root\n );\n let width: number;\n try {\n // round() to match canvasMeasureTextWidth and ch; otherwise the DOM path\n // returns raw sub-pixel widths and caret/selection offsets drift between\n // ASCII and non-ASCII runs on the same line.\n width = round(measureEl.getBoundingClientRect().width);\n } finally {\n measureEl.remove();\n }\n if (this.#textWidthCache.size >= TEXT_WIDTH_CACHE_LIMIT) {\n const oldestKey = this.#textWidthCache.keys().next().value;\n if (oldestKey !== undefined) {\n this.#textWidthCache.delete(oldestKey);\n }\n }\n this.#textWidthCache.set(cacheKey, width);\n return width;\n }\n\n /**\n * discard memoized DOM text widths\n * call this when the inherited font may have changed without re-running\n * init(), e.g. on a layout reflow, so stale widths are not reused\n */\n clearTextWidthCache(): void {\n this.#textWidthCache.clear();\n }\n}\n\n/** Check if the text needs DOM text measurement. */\nexport function needsDomTextMeasurement(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n if (\n (code >= 0xd800 && code <= 0xdfff) ||\n code === 0x200d ||\n code === 0xfe0e ||\n code === 0xfe0f\n ) {\n return true;\n }\n }\n return false;\n}\n\n/** snap the text offset to the Unicode boundary */\nexport function snapTextOffsetToUnicodeBoundary(\n text: string,\n offset: number\n): number {\n const boundedOffset = Math.max(0, Math.min(offset, text.length));\n if (\n boundedOffset === 0 ||\n boundedOffset === text.length ||\n !needsDomTextMeasurement(text)\n ) {\n return boundedOffset;\n }\n // Avoid measuring a caret position inside one visual emoji/grapheme.\n // Browser caret movement can report offsets around UTF-16 surrogate\n // pairs and emoji joiners; measuring a partial sequence gives a\n // replacement-glyph width.\n const segmenter = getGraphemeSegmenter();\n if (segmenter !== undefined) {\n for (const segment of segmenter.segment(text)) {\n const segmentStart = segment.index;\n const segmentEnd = segmentStart + segment.segment.length;\n if (boundedOffset > segmentStart && boundedOffset < segmentEnd) {\n return segmentEnd;\n }\n if (boundedOffset <= segmentStart) {\n break;\n }\n }\n return boundedOffset;\n }\n // Degraded path for engines lacking Intl.Segmenter: snap out of a\n // surrogate pair by stepping over code points.\n let segmentStart = 0;\n for (const codePoint of text) {\n const segmentEnd = segmentStart + codePoint.length;\n if (boundedOffset > segmentStart && boundedOffset < segmentEnd) {\n return segmentEnd;\n }\n if (boundedOffset <= segmentStart) {\n break;\n }\n segmentStart = segmentEnd;\n }\n return boundedOffset;\n}\n\n/** get the offsets of the Unicode grapheme clusters in the text */\nexport function getUnicodeMeasurementOffsets(\n text: string\n): number[] | undefined {\n if (!needsDomTextMeasurement(text)) {\n return undefined;\n }\n const offsets = [0];\n const segmenter = getGraphemeSegmenter();\n if (segmenter !== undefined) {\n for (const segment of segmenter.segment(text)) {\n offsets.push(segment.index + segment.segment.length);\n }\n return offsets;\n }\n // Degraded path for engines lacking Intl.Segmenter: step by code point.\n let offset = 0;\n for (const codePoint of text) {\n offset += codePoint.length;\n offsets.push(offset);\n }\n return offsets;\n}\n\n/**\n * Expand tab characters to spaces using fixed tab stops: each tab advances to\n * the next multiple of tabSize from its running column, matching how the\n * rendered text expands tabs via CSS `tab-size`. Expanding every tab to a flat\n * tabSize would mis-measure tabs that follow other characters on the same line\n * (e.g. an alignment tab in `foo\\tbar`).\n */\nexport function expandTabsToSpaces(text: string, tabSize: number): string {\n if (!text.includes('\\t')) {\n return text;\n }\n let result = '';\n let column = 0;\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) === /* '\\t' */ 9) {\n const advance = tabSize - (column % tabSize);\n result += ' '.repeat(advance);\n column += advance;\n } else {\n result += text[i];\n column += 1;\n }\n }\n return result;\n}\n\n/**\n * Count the rendered columns of ASCII text, advancing each tab to the next\n * fixed tab stop (a multiple of tabSize) to match CSS `tab-size`. Returns -1\n * for non-ASCII text, which must be measured glyph-by-glyph instead.\n */\nexport function getExpandedAsciiTextColumns(\n text: string,\n tabSize: number\n): number {\n let columns = 0;\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n if (code > 127) {\n return -1;\n }\n columns += code === /* '\\t' */ 9 ? tabSize - (columns % tabSize) : 1;\n }\n return columns;\n}\n"],"mappings":";;AAMA,MAAM,yBAAyB;AAE/B,IAAa,UAAb,MAAqB;CACnB;CACA;CACA;CAGA,kCAAkB,IAAI,IAAoB;;CAG1C,KAAa;;CAEb,UAAkB;;CAElB,aAAqB;;CAErB,aAAqB;;CAGrB,KAAK,MAAyB;EAC5B,IACE,KAAKA,UAAU,QACf,KAAKC,eAAe,KAAA,KACpB,KAAK,OAAO,IAGZ;EAGF,KAAKD,QAAQ;EACb,KAAKC,eACH,SAAS,cAAc,QAAQ,CAAC,CAAC,WAAW,IAAI,KAAK,KAAA;EACvD,IAAI,KAAKA,eAAe,KAAA,GACtB,MAAM,IAAI,MAAM,8BAA8B;EAGhD,MAAM,SAAS,KAAK;EACpB,IAAI,WAAW,MAAM;GACnB,MAAM,EAAE,eAAe,iBAAiB,MAAM;GAC9C,IAAI,WAAW,SAAS,IAAI,GAC1B,KAAK,aAAa,WAAW,WAAW,MAAM,GAAG,EAAE,CAAC;EAExD;EAEA,MAAM,EAAE,UAAU,YAAY,SAAS,eACrC,iBAAiB,IAAI;EACvB,IAAI,WAAW,SAAS,IAAI,GAC1B,KAAK,aAAa,WAAW,WAAW,MAAM,GAAG,EAAE,CAAC;OAC/C,IAAI,SAAS,SAAS,IAAI,GAC/B,KAAK,aAAa,MAChB,WAAW,SAAS,MAAM,GAAG,EAAE,CAAC,IAAI,WAAW,UAAU,CAC3D;EAEF,MAAM,OAAO,WAAW,MAAM;EAC9B,IAAI,KAAKC,UAAU,QAAQ,KAAK,OAAO,IAAI;GACzC,KAAKA,QAAQ;GACb,KAAKD,WAAW,OAAO;GACvB,KAAK,KAAK,KAAK,uBAAuB,GAAG;GAEzC,KAAK,oBAAoB;EAC3B;EACA,MAAM,cAAc,SAAS,SAAS,EAAE;EACxC,IAAI,CAAC,OAAO,MAAM,WAAW,GAC3B,KAAK,UAAU;CAEnB;;;;;;;;;;;;;CAcA,0BAAmC;EACjC,IAAI,KAAKA,eAAe,KAAA,KAAa,KAAKC,UAAU,KAAA,GAClD,OAAO;EAET,KAAKD,WAAW,OAAO,KAAKC;EAC5B,MAAM,KAAK,KAAK,uBAAuB,GAAG;EAC1C,IAAI,OAAO,KAAK,IACd,OAAO;EAET,KAAK,KAAK;EACV,OAAO;CACT;;CAGA,iBAAiB,MAAsB;EACrC,MAAM,uBAAuB,mBAAmB,MAAM,KAAK,OAAO;EAClE,IAAI,wBAAwB,oBAAoB,GAC9C,OAAO,KAAK,oBAAoB,oBAAoB;EAEtD,OAAO,KAAK,uBAAuB,oBAAoB;CACzD;;CAGA,uBAAuB,MAAsB;EAC3C,IAAI,KAAKD,eAAe,KAAA,GACtB,MAAM,IAAI,MAAM,yBAAyB;EAE3C,OAAO,MAAM,KAAKA,WAAW,YAAY,IAAI,CAAC,CAAC,KAAK;CACtD;;;;;;CAOA,oBAAoB,MAAsB;EACxC,IAAI,KAAKD,UAAU,KAAA,GACjB,MAAM,IAAI,MAAM,yBAAyB;EAE3C,MAAM,WAAW,OAAO,MAAM,KAAKE;EACnC,MAAM,SAAS,KAAKC,gBAAgB,IAAI,QAAQ;EAChD,IAAI,WAAW,KAAA,GACb,OAAO;EAET,MAAM,YAAY,EAChB,QACA;GACE,OAAO;IACL,UAAU;IACV,KAAK;IACL,MAAM;IACN,YAAY;IACZ,eAAe;IACf,YAAY;IACZ,MAAM;GACR;GACA,aAAa;EACf,GACA,KAAKH,KACP;EACA,IAAI;EACJ,IAAI;GAIF,QAAQ,MAAM,UAAU,sBAAsB,CAAC,CAAC,KAAK;EACvD,UAAU;GACR,UAAU,OAAO;EACnB;EACA,IAAI,KAAKG,gBAAgB,QAAQ,wBAAwB;GACvD,MAAM,YAAY,KAAKA,gBAAgB,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;GACrD,IAAI,cAAc,KAAA,GAChB,KAAKA,gBAAgB,OAAO,SAAS;EAEzC;EACA,KAAKA,gBAAgB,IAAI,UAAU,KAAK;EACxC,OAAO;CACT;;;;;;CAOA,sBAA4B;EAC1B,KAAKA,gBAAgB,MAAM;CAC7B;AACF;;AAGA,SAAgB,wBAAwB,MAAuB;CAC7D,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,OAAO,KAAK,WAAW,CAAC;EAC9B,IACG,QAAQ,SAAU,QAAQ,SAC3B,SAAS,QACT,SAAS,SACT,SAAS,OAET,OAAO;CAEX;CACA,OAAO;AACT;;AAGA,SAAgB,gCACd,MACA,QACQ;CACR,MAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,KAAK,MAAM,CAAC;CAC/D,IACE,kBAAkB,KAClB,kBAAkB,KAAK,UACvB,CAAC,wBAAwB,IAAI,GAE7B,OAAO;CAMT,MAAM,YAAY,qBAAqB;CACvC,IAAI,cAAc,KAAA,GAAW;EAC3B,KAAK,MAAM,WAAW,UAAU,QAAQ,IAAI,GAAG;GAC7C,MAAM,eAAe,QAAQ;GAC7B,MAAM,aAAa,eAAe,QAAQ,QAAQ;GAClD,IAAI,gBAAgB,gBAAgB,gBAAgB,YAClD,OAAO;GAET,IAAI,iBAAiB,cACnB;EAEJ;EACA,OAAO;CACT;CAGA,IAAI,eAAe;CACnB,KAAK,MAAM,aAAa,MAAM;EAC5B,MAAM,aAAa,eAAe,UAAU;EAC5C,IAAI,gBAAgB,gBAAgB,gBAAgB,YAClD,OAAO;EAET,IAAI,iBAAiB,cACnB;EAEF,eAAe;CACjB;CACA,OAAO;AACT;;AAGA,SAAgB,6BACd,MACsB;CACtB,IAAI,CAAC,wBAAwB,IAAI,GAC/B;CAEF,MAAM,UAAU,CAAC,CAAC;CAClB,MAAM,YAAY,qBAAqB;CACvC,IAAI,cAAc,KAAA,GAAW;EAC3B,KAAK,MAAM,WAAW,UAAU,QAAQ,IAAI,GAC1C,QAAQ,KAAK,QAAQ,QAAQ,QAAQ,QAAQ,MAAM;EAErD,OAAO;CACT;CAEA,IAAI,SAAS;CACb,KAAK,MAAM,aAAa,MAAM;EAC5B,UAAU,UAAU;EACpB,QAAQ,KAAK,MAAM;CACrB;CACA,OAAO;AACT;;;;;;;;AASA,SAAgB,mBAAmB,MAAc,SAAyB;CACxE,IAAI,CAAC,KAAK,SAAS,GAAI,GACrB,OAAO;CAET,IAAI,SAAS;CACb,IAAI,SAAS;CACb,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAC/B,IAAI,KAAK,WAAW,CAAC,MAAiB,GAAG;EACvC,MAAM,UAAU,UAAW,SAAS;EACpC,UAAU,IAAI,OAAO,OAAO;EAC5B,UAAU;CACZ,OAAO;EACL,UAAU,KAAK;EACf,UAAU;CACZ;CAEF,OAAO;AACT;;;;;;AAOA,SAAgB,4BACd,MACA,SACQ;CACR,IAAI,UAAU;CACd,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,OAAO,KAAK,WAAW,CAAC;EAC9B,IAAI,OAAO,KACT,OAAO;EAET,WAAW,SAAoB,IAAI,UAAW,UAAU,UAAW;CACrE;CACA,OAAO;AACT"}
@@ -9,6 +9,7 @@ interface EditorTokenizerProps {
9
9
  codeOptions: BaseCodeOptions;
10
10
  setStyle: (style: string) => void;
11
11
  onDeferTokenize: (lines: Map<number, Array<HighlightedToken>>, themeType: 'dark' | 'light') => void;
12
+ onThemeChange?: () => void;
12
13
  __debug?: boolean;
13
14
  }
14
15
  /** Stoppable code tokenizer for the editor */
@@ -22,8 +23,10 @@ declare class EditorTokenizer {
22
23
  textDocument,
23
24
  setStyle,
24
25
  onDeferTokenize,
26
+ onThemeChange,
25
27
  __debug
26
28
  }: EditorTokenizerProps);
29
+ syncTheme(codeOptions: BaseCodeOptions): void;
27
30
  cleanUp(): void;
28
31
  tokenize(change: TextDocumentChange, renderRange?: RenderRange): Map<number, Array<HighlightedToken>>;
29
32
  prebuildStateStack(renderRange?: RenderRange): void;
@@ -1 +1 @@
1
- {"version":3,"file":"tokenzier.d.ts","names":["IGrammar","StateStack","BaseCodeOptions","DiffsHighlighter","HighlightedToken","RenderRange","TextDocument","TextDocumentChange","EditorTokenizerProps","Array","Map","EditorTokenizer","codeOptions","highlighter","textDocument","setStyle","onDeferTokenize","__debug","tokenizeLine","renderLineTokens","HTMLElement"],"sources":["../../src/editor/tokenzier.d.ts"],"sourcesContent":["import { type IGrammar, type StateStack } from 'shiki/textmate';\nimport type { BaseCodeOptions, DiffsHighlighter, HighlightedToken, RenderRange } from '../types';\nimport type { TextDocument, TextDocumentChange } from './textDocument';\nexport interface EditorTokenizerProps {\n highlighter: DiffsHighlighter;\n textDocument: TextDocument<unknown>;\n codeOptions: BaseCodeOptions;\n setStyle: (style: string) => void;\n onDeferTokenize: (lines: Map<number, Array<HighlightedToken>>, themeType: 'dark' | 'light') => void;\n __debug?: boolean;\n}\n/** Stoppable code tokenizer for the editor */\nexport declare class EditorTokenizer {\n #private;\n static TOKENIZE_TIME_LIMIT: number;\n get themeType(): 'light' | 'dark';\n constructor({ codeOptions, highlighter, textDocument, setStyle, onDeferTokenize, __debug }: EditorTokenizerProps);\n cleanUp(): void;\n tokenize(change: TextDocumentChange, renderRange?: RenderRange): Map<number, Array<HighlightedToken>>;\n prebuildStateStack(renderRange?: RenderRange): void;\n stopBackgroundTokenize(): void;\n pauseBackgroundTokenize(): void;\n resumeBackgroundTokenize(): void;\n}\nexport declare function tokenizeLine(grammar: IGrammar, colorMap: string[], lineText: string, stateStack: StateStack, timeLimit?: number): {\n ruleStack: StateStack;\n resolvedTokens: Array<HighlightedToken>;\n};\nexport declare function renderLineTokens(tokens: Array<HighlightedToken>, themeType: 'light' | 'dark'): (HTMLElement | string)[];\n//# sourceMappingURL=tokenzier.d.ts.map"],"mappings":";;;;;UAGiBQ,oBAAAA;eACAL;EADAK,YAAAA,EAECF,YAFmB,CAAA,OAAA,CAAA;EACpBH,WAAAA,EAEAD,eAFAC;EACCG,QAAAA,EAAAA,CAAAA,KAAAA,EAAAA,MAAAA,EAAAA,GAAAA,IAAAA;EACDJ,eAAAA,EAAAA,CAAAA,KAAAA,EAEYQ,GAFZR,CAAAA,MAAAA,EAEwBO,KAFxBP,CAE8BE,gBAF9BF,CAAAA,CAAAA,EAAAA,SAAAA,EAAAA,MAAAA,GAAAA,OAAAA,EAAAA,GAAAA,IAAAA;EAE8BE,OAAAA,CAAAA,EAAAA,OAAAA;;;AAAf,cAIXO,eAAAA,CAJW;EAIXA,CAAAA,OAAAA;EAIHC,OAAAA,mBAAAA,EAAAA,MAAAA;EAAaC,IAAAA,SAAAA,CAAAA,CAAAA,EAAAA,OAAAA,GAAAA,MAAAA;EAAaC,WAAAA,CAAAA;IAAAA,WAAAA;IAAAA,WAAAA;IAAAA,YAAAA;IAAAA,QAAAA;IAAAA,eAAAA;IAAAA;EAAAA,CAAAA,EAAoDN,oBAApDM;EAAcC,OAAAA,CAAAA,CAAAA,EAAAA,IAAAA;EAAUC,QAAAA,CAAAA,MAAAA,EAE/CT,kBAF+CS,EAAAA,WAAAA,CAAAA,EAEbX,WAFaW,CAAAA,EAECN,GAFDM,CAAAA,MAAAA,EAEaP,KAFbO,CAEmBZ,gBAFnBY,CAAAA,CAAAA;EAAiBC,kBAAAA,CAAAA,WAAAA,CAAAA,EAGhDZ,WAHgDY,CAAAA,EAAAA,IAAAA;EAAWT,sBAAAA,CAAAA,CAAAA,EAAAA,IAAAA;EAE3ED,uBAAAA,CAAAA,CAAAA,EAAAA,IAAAA;EAAkCF,wBAAAA,CAAAA,CAAAA,EAAAA,IAAAA;;AAA0BI,iBAMzDS,YAAAA,CANyDT,OAAAA,EAMnCT,QANmCS,EAAAA,QAAAA,EAAAA,MAAAA,EAAAA,EAAAA,QAAAA,EAAAA,MAAAA,EAAAA,UAAAA,EAMyBR,UANzBQ,EAAAA,SAAAA,CAAAA,EAAAA,MAAAA,CAAAA,EAAAA;EAAZC,SAAAA,EAOtDT,UAPsDS;EAChCL,cAAAA,EAOjBI,KAPiBJ,CAOXD,gBAPWC,CAAAA;CAAW;AAKxBa,iBAIAC,gBAAAA,CAJY,MAAA,EAIaV,KAJb,CAImBL,gBAJnB,CAAA,EAAA,SAAA,EAAA,OAAA,GAAA,MAAA,CAAA,EAAA,CAIqEgB,WAJrE,GAAA,MAAA,CAAA,EAAA"}
1
+ {"version":3,"file":"tokenzier.d.ts","names":[],"sources":["../../src/editor/tokenzier.ts"],"mappings":";;;;;UAiBiB,oBAAA;EACf,WAAA,EAAa,gBAAA;EACb,YAAA,EAAc,YAAA;EACd,WAAA,EAAa,eAAA;EACb,QAAA,GAAW,KAAA;EACX,eAAA,GACE,KAAA,EAAO,GAAA,SAAY,KAAA,CAAM,gBAAA,IACzB,SAAA;EAKF,aAAA;EACA,OAAA;AAAA;;cAIW,eAAA;EAAA;SACJ,mBAAA;EAAA,IAgEH,SAAA;EAIJ,WAAA;IACE,WAAA;IACA,WAAA;IACA,YAAA;IACA,QAAA;IACA,eAAA;IACA,aAAA;IACA;EAAA,GACC,oBAAA;EAgFH,SAAA,CAAU,WAAA,EAAa,eAAA;EA8CvB,OAAA;EASA,QAAA,CACE,MAAA,EAAQ,kBAAA,EACR,WAAA,GAAc,WAAA,GACb,GAAA,SAAY,KAAA,CAAM,gBAAA;EA0LrB,kBAAA,CAAmB,WAAA,GAAc,WAAA;EAmBjC,sBAAA;EAYA,uBAAA;EAYA,wBAAA;AAAA;AAAA,iBA4Nc,YAAA,CACd,OAAA,EAAS,QAAA,EACT,QAAA,YACA,QAAA,UACA,UAAA,EAAY,UAAA,EACZ,SAAA;EAEA,SAAA,EAAW,UAAA;EACX,cAAA,EAAgB,KAAA,CAAM,gBAAA;AAAA;AAAA,iBA+BR,gBAAA,CACd,MAAA,EAAQ,KAAA,CAAM,gBAAA,GACd,SAAA,sBACE,WAAA"}
@@ -1,7 +1,6 @@
1
1
  import { DEFAULT_THEMES } from "../constants.js";
2
2
  import { addEventListener, debounce, h } from "./utils.js";
3
3
  import { EncodedTokenMetadata, INITIAL } from "shiki/textmate";
4
-
5
4
  //#region src/editor/tokenzier.ts
6
5
  /** Stoppable code tokenizer for the editor */
7
6
  var EditorTokenizer = class EditorTokenizer {
@@ -10,11 +9,13 @@ var EditorTokenizer = class EditorTokenizer {
10
9
  #grammar;
11
10
  #mediaQueryList;
12
11
  #themeType;
12
+ #themeName = "";
13
13
  #colorMap;
14
14
  #textDocument;
15
15
  #tokenizeMaxLineLength;
16
16
  #setStyle;
17
17
  #onDeferTokenize;
18
+ #onThemeChange;
18
19
  #debug;
19
20
  #disposes;
20
21
  #stateStack = [INITIAL];
@@ -42,24 +43,24 @@ var EditorTokenizer = class EditorTokenizer {
42
43
  get themeType() {
43
44
  return this.#themeType;
44
45
  }
45
- constructor({ codeOptions, highlighter, textDocument, setStyle, onDeferTokenize, __debug }) {
46
+ constructor({ codeOptions, highlighter, textDocument, setStyle, onDeferTokenize, onThemeChange, __debug }) {
46
47
  const { themeType = "system", theme = DEFAULT_THEMES, tokenizeMaxLineLength = 1e3 } = codeOptions;
47
48
  this.#mediaQueryList = window.matchMedia("(prefers-color-scheme: dark)");
48
49
  if (themeType === "system") this.#themeType = this.#mediaQueryList.matches ? "dark" : "light";
49
50
  else this.#themeType = themeType;
50
- if (typeof theme !== "string") {
51
+ if (typeof theme !== "string" && themeType === "system") {
51
52
  const observer = new MutationObserver((mutations) => {
52
53
  for (const { type, attributeName } of mutations) if (type === "attributes" && attributeName !== null && (attributeName === "class" || attributeName.startsWith("data-"))) {
53
- const themeType$1 = getComputedStyle(document.body).colorScheme === "dark" ? "dark" : "light";
54
- this.#emitThemeChange(theme[themeType$1], themeType$1);
54
+ const themeType = getComputedStyle(document.body).colorScheme === "dark" ? "dark" : "light";
55
+ this.#emitThemeChange(theme[themeType], themeType);
55
56
  break;
56
57
  }
57
58
  });
58
59
  observer.observe(document.documentElement, { attributes: true });
59
60
  observer.observe(document.body, { attributes: true });
60
61
  this.#disposes = [addEventListener(this.#mediaQueryList, "change", (e) => {
61
- const themeType$1 = e.matches ? "dark" : "light";
62
- this.#emitThemeChange(theme[themeType$1], themeType$1);
62
+ const themeType = e.matches ? "dark" : "light";
63
+ this.#emitThemeChange(theme[themeType], themeType);
63
64
  }), () => observer.disconnect()];
64
65
  }
65
66
  this.#highlighter = highlighter;
@@ -67,8 +68,9 @@ var EditorTokenizer = class EditorTokenizer {
67
68
  this.#tokenizeMaxLineLength = tokenizeMaxLineLength;
68
69
  this.#setStyle = setStyle;
69
70
  this.#onDeferTokenize = onDeferTokenize;
71
+ this.#onThemeChange = onThemeChange;
70
72
  this.#debug = __debug ?? false;
71
- if (!isGrammarlessLanguage(textDocument.languageId) && highlighter.getLoadedLanguages().includes(textDocument.languageId)) this.#grammar = highlighter.getLanguage(textDocument.languageId);
73
+ this.#ensureGrammar();
72
74
  this.#colorMap = [];
73
75
  this.#setTheme(typeof theme === "string" ? theme : theme[this.#themeType]);
74
76
  }
@@ -78,14 +80,21 @@ var EditorTokenizer = class EditorTokenizer {
78
80
  this.stopBackgroundTokenize();
79
81
  this.#stateStack = [INITIAL];
80
82
  if (this.#grammar !== void 0 && this.#textDocument.lineCount > 0) this.#scheduleBackgroundTokenize(0);
83
+ this.#onThemeChange?.();
84
+ }
85
+ syncTheme(codeOptions) {
86
+ const { themeType = "system", theme = DEFAULT_THEMES } = codeOptions;
87
+ const nextThemeType = themeType === "system" ? this.#mediaQueryList.matches ? "dark" : "light" : themeType;
88
+ const nextThemeName = typeof theme === "string" ? theme : theme[nextThemeType];
89
+ if (nextThemeType === this.#themeType && nextThemeName === this.#themeName) return;
90
+ this.#emitThemeChange(nextThemeName, nextThemeType);
81
91
  }
82
92
  #setTheme(themeName) {
93
+ this.#themeName = themeName;
83
94
  this.#colorMap = this.#highlighter.setTheme(themeName).colorMap;
84
95
  const { colors = {} } = this.#highlighter.getTheme(themeName);
85
96
  const selectionBackground = colors["editor.selectionBackground"];
86
97
  const lineHighlightBackground = colors["editor.lineHighlightBackground"];
87
- const gutterForeground = colors["editorLineNumber.foreground"];
88
- const gutterActiveForeground = colors["editorLineNumber.activeForeground"];
89
98
  const cursorForeground = colors["editorCursor.foreground"];
90
99
  const findMatchBackground = colors["editor.findMatchBackground"];
91
100
  const findMatchHighlightBackground = colors["editor.findMatchHighlightBackground"];
@@ -96,9 +105,6 @@ var EditorTokenizer = class EditorTokenizer {
96
105
  this.#setStyle(`:host {
97
106
  --diffs-editor-selection-bg: ${selectionBackground ?? "var(--diffs-line-bg)"};
98
107
  --diffs-editor-line-highlight-bg: ${lineHighlightBackground ?? "var(--diffs-line-bg)"};
99
- --diffs-editor-line-number-fg: ${gutterForeground ?? "var(--diffs-fg-number)"};
100
- --diffs-editor-line-number-active-bg: ${lineHighlightBackground ?? "var(--diffs-line-bg, var(--diffs-bg))"};
101
- --diffs-editor-line-number-active-fg: ${gutterActiveForeground ?? "var(--diffs-selection-number-fg)"};
102
108
  --diffs-editor-match-bg: ${findMatchBackground ?? "unset"};
103
109
  --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? "unset"};
104
110
  --diffs-editor-cursor-fg: ${cursorForeground ?? "unset"};
@@ -115,7 +121,8 @@ var EditorTokenizer = class EditorTokenizer {
115
121
  this.#disposes = void 0;
116
122
  }
117
123
  tokenize(change, renderRange) {
118
- if (this.#grammar === void 0 && !isGrammarlessLanguage(this.#textDocument.languageId)) throw new Error("Grammar not loaded");
124
+ this.#ensureGrammar();
125
+ if (this.#grammar === void 0 && !isGrammarlessLanguage(this.#textDocument.languageId)) throw new Error(`Grammar for language "${this.#textDocument.languageId}" not loaded`);
119
126
  const { lineCount } = this.#textDocument;
120
127
  const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};
121
128
  const renderRangeEndLine = totalLines === Infinity ? lineCount : Math.min(startingLine + totalLines, lineCount);
@@ -140,7 +147,6 @@ var EditorTokenizer = class EditorTokenizer {
140
147
  let backgroundStartLine;
141
148
  let backgroundChangedRangeIndex = 0;
142
149
  let line = canReuseCachedStates ? changedLineRanges[changedRangeIndex][0] : viewStart;
143
- let state = this.#stateStack[line] ?? INITIAL;
144
150
  let settled = false;
145
151
  const dirtyLines = /* @__PURE__ */ new Map();
146
152
  const offscreenDirtyLines = shouldFlushOffscreenLines ? /* @__PURE__ */ new Map() : void 0;
@@ -158,6 +164,7 @@ var EditorTokenizer = class EditorTokenizer {
158
164
  if (canCacheTokenizedStates) this.#stateStack[offscreenEnd] = offscreenState;
159
165
  }
160
166
  }
167
+ let state = this.#stateStack[line] ?? INITIAL;
161
168
  for (; line < renderRangeEndLine;) {
162
169
  const previousNextState = canReuseCachedStates ? this.#stateStack[line + 1] : void 0;
163
170
  if (canCacheTokenizedStates) this.#stateStack[line] = state;
@@ -200,8 +207,12 @@ var EditorTokenizer = class EditorTokenizer {
200
207
  return dirtyLines;
201
208
  }
202
209
  prebuildStateStack(renderRange) {
210
+ this.#ensureGrammar();
203
211
  this.#prebuildStateStack(renderRange);
204
212
  }
213
+ #ensureGrammar() {
214
+ if (this.#grammar === void 0 && !isGrammarlessLanguage(this.#textDocument.languageId) && this.#highlighter.getLoadedLanguages().includes(this.#textDocument.languageId)) this.#grammar = this.#highlighter.getLanguage(this.#textDocument.languageId);
215
+ }
205
216
  stopBackgroundTokenize() {
206
217
  if (this.#isStopped) return;
207
218
  this.#isStopped = true;
@@ -395,7 +406,7 @@ function renderLineTokens(tokens, themeType) {
395
406
  function isGrammarlessLanguage(languageId) {
396
407
  return languageId === "text" || languageId === "ansi";
397
408
  }
398
-
399
409
  //#endregion
400
410
  export { EditorTokenizer, renderLineTokens, tokenizeLine };
411
+
401
412
  //# sourceMappingURL=tokenzier.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokenzier.js","names":["#textDocument","#grammar","#highlighter","#buildStateStack","#backgroundJobId","#backgroundTokenize","#themeType","#mediaQueryList","themeType","#emitThemeChange","#disposes","#tokenizeMaxLineLength","#setStyle","#onDeferTokenize","#debug","#colorMap","#setTheme","#stateStack","#scheduleBackgroundTokenize","#detachMessageListener","changedLineRanges: readonly [number, number][]","backgroundStartLine: number | undefined","dirtyLines: Map<number, Array<HighlightedToken>>","offscreenDirtyLines:\n | Map<number, Array<HighlightedToken>>\n | undefined","#tokenizeLineAt","#prebuildStateStack","#isStopped","#isPaused","#lastLine","#backgroundChangedLineRanges","#backgroundChangedRangeIndex","#postTokenizeMessage","#isMessageListenerAttached","#onMessage","#attachMessageListener","resolvedTokens: Array<HighlightedToken>"],"sources":["../../src/editor/tokenzier.ts"],"sourcesContent":["import {\n EncodedTokenMetadata,\n type IGrammar,\n INITIAL,\n type StateStack,\n} from 'shiki/textmate';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport type {\n BaseCodeOptions,\n DiffsHighlighter,\n HighlightedToken,\n RenderRange,\n} from '../types';\nimport type { TextDocument, TextDocumentChange } from './textDocument';\nimport { addEventListener, debounce, h } from './utils';\n\nexport interface EditorTokenizerProps {\n highlighter: DiffsHighlighter;\n textDocument: TextDocument<unknown>;\n codeOptions: BaseCodeOptions;\n setStyle: (style: string) => void;\n onDeferTokenize: (\n lines: Map<number, Array<HighlightedToken>>,\n themeType: 'dark' | 'light'\n ) => void;\n __debug?: boolean;\n}\n\n/** Stoppable code tokenizer for the editor */\nexport class EditorTokenizer {\n static TOKENIZE_TIME_LIMIT = 500;\n\n #highlighter: DiffsHighlighter;\n #grammar: IGrammar | undefined;\n #mediaQueryList: MediaQueryList;\n #themeType: 'light' | 'dark';\n #colorMap: string[];\n #textDocument: TextDocument<unknown>;\n #tokenizeMaxLineLength: number;\n #setStyle: EditorTokenizerProps['setStyle'];\n #onDeferTokenize: EditorTokenizerProps['onDeferTokenize'];\n #debug: boolean;\n #disposes?: (() => void)[];\n\n // state\n #stateStack: StateStack[] = [INITIAL]; // cached state stack by line index\n #lastLine: number = -1;\n #isStopped: boolean = true;\n #isPaused: boolean = false;\n #backgroundJobId: number = 0;\n #backgroundChangedLineRanges: readonly [number, number][] | undefined;\n #backgroundChangedRangeIndex: number = 0;\n #isMessageListenerAttached: boolean = false;\n\n #prebuildStateStack = debounce(async (renderRange?: RenderRange) => {\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const endLine = Math.min(\n totalLines === Infinity ? Infinity : startingLine + totalLines,\n this.#textDocument.lineCount\n );\n if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId)\n ) {\n await this.#highlighter.loadLanguage(this.#textDocument.languageId);\n this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n this.#buildStateStack(endLine);\n }, 500);\n\n #onMessage = ({ data }: MessageEvent<unknown>) => {\n if (typeof data !== 'object' || data === null) {\n return;\n }\n const { type, jobId } = data as {\n type?: unknown;\n jobId?: unknown;\n };\n if (\n type === 'tokenize' &&\n typeof jobId === 'number' &&\n jobId === this.#backgroundJobId\n ) {\n this.#backgroundTokenize(jobId);\n }\n };\n\n get themeType(): 'light' | 'dark' {\n return this.#themeType;\n }\n\n constructor({\n codeOptions,\n highlighter,\n textDocument,\n setStyle,\n onDeferTokenize,\n __debug,\n }: EditorTokenizerProps) {\n const {\n themeType = 'system',\n theme = DEFAULT_THEMES,\n tokenizeMaxLineLength = 1000,\n } = codeOptions;\n this.#mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');\n if (themeType === 'system') {\n this.#themeType = this.#mediaQueryList.matches ? 'dark' : 'light';\n } else {\n this.#themeType = themeType;\n }\n if (typeof theme !== 'string') {\n const observer = new MutationObserver((mutations) => {\n for (const { type, attributeName } of mutations) {\n if (\n type === 'attributes' &&\n attributeName !== null &&\n (attributeName === 'class' || attributeName.startsWith('data-'))\n ) {\n const themeType =\n getComputedStyle(document.body).colorScheme === 'dark'\n ? 'dark'\n : 'light';\n this.#emitThemeChange(theme[themeType], themeType);\n break;\n }\n }\n });\n observer.observe(document.documentElement, { attributes: true });\n observer.observe(document.body, { attributes: true });\n this.#disposes = [\n addEventListener(this.#mediaQueryList, 'change', (e) => {\n const themeType = e.matches ? 'dark' : 'light';\n this.#emitThemeChange(theme[themeType], themeType);\n }),\n () => observer.disconnect(),\n ];\n }\n this.#highlighter = highlighter;\n this.#textDocument = textDocument;\n this.#tokenizeMaxLineLength = tokenizeMaxLineLength;\n this.#setStyle = setStyle;\n this.#onDeferTokenize = onDeferTokenize;\n this.#debug = __debug ?? false;\n if (\n !isGrammarlessLanguage(textDocument.languageId) &&\n highlighter.getLoadedLanguages().includes(textDocument.languageId)\n ) {\n this.#grammar = highlighter.getLanguage(textDocument.languageId);\n }\n this.#colorMap = [];\n this.#setTheme(typeof theme === 'string' ? theme : theme[this.#themeType]);\n }\n\n // By default, diffs components support dual themes, but the tokenizer only renders\n // the preferred theme. When the theme type is changed, the tokenizer will re-tokenize the document.\n #emitThemeChange(themeName: string, themeType: 'light' | 'dark') {\n this.#themeType = themeType;\n this.#setTheme(themeName);\n this.stopBackgroundTokenize();\n this.#stateStack = [INITIAL];\n if (this.#grammar !== undefined && this.#textDocument.lineCount > 0) {\n this.#scheduleBackgroundTokenize(0);\n }\n }\n\n #setTheme(themeName: string) {\n this.#colorMap = this.#highlighter.setTheme(themeName).colorMap;\n const { colors = {} } = this.#highlighter.getTheme(themeName);\n const selectionBackground = colors['editor.selectionBackground'];\n const lineHighlightBackground = colors['editor.lineHighlightBackground'];\n const gutterForeground = colors['editorLineNumber.foreground'];\n const gutterActiveForeground = colors['editorLineNumber.activeForeground'];\n const cursorForeground = colors['editorCursor.foreground'];\n const findMatchBackground = colors['editor.findMatchBackground'];\n const findMatchHighlightBackground =\n colors['editor.findMatchHighlightBackground'];\n const hintForeground = colors['editorHint.foreground'];\n const infoForeground = colors['editorInfo.foreground'];\n const warningForeground = colors['editorWarning.foreground'];\n const errorForeground = colors['editorError.foreground'];\n this.#setStyle(`:host {\n --diffs-editor-selection-bg: ${selectionBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-line-highlight-bg: ${lineHighlightBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-line-number-fg: ${gutterForeground ?? 'var(--diffs-fg-number)'};\n --diffs-editor-line-number-active-bg: ${lineHighlightBackground ?? 'var(--diffs-line-bg, var(--diffs-bg))'};\n --diffs-editor-line-number-active-fg: ${gutterActiveForeground ?? 'var(--diffs-selection-number-fg)'};\n --diffs-editor-match-bg: ${findMatchBackground ?? 'unset'};\n --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? 'unset'};\n --diffs-editor-cursor-fg: ${cursorForeground ?? 'unset'};\n --diffs-editor-hint-fg: ${hintForeground ?? 'unset'};\n --diffs-editor-info-fg: ${infoForeground ?? 'unset'};\n --diffs-editor-warning-fg: ${warningForeground ?? 'unset'};\n --diffs-editor-error-fg: ${errorForeground ?? 'unset'};\n }`);\n }\n\n cleanUp(): void {\n this.stopBackgroundTokenize();\n this.#detachMessageListener();\n this.#disposes?.forEach((dispose) => dispose());\n this.#disposes = undefined;\n }\n\n // to use `tokenize`, call `prebuildStateStackMap` first to prebuild\n // the state stack map for the given render range.\n tokenize(\n change: TextDocumentChange,\n renderRange?: RenderRange\n ): Map<number, Array<HighlightedToken>> {\n if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId)\n ) {\n throw new Error('Grammar not loaded');\n }\n\n const { lineCount } = this.#textDocument;\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const renderRangeEndLine =\n totalLines === Infinity\n ? lineCount\n : Math.min(startingLine + totalLines, lineCount);\n\n const dirtyStart = change.startLine;\n const viewStart = Math.max(startingLine, dirtyStart);\n const crossesRenderRangeEnd =\n renderRange !== undefined &&\n totalLines !== Infinity &&\n change.lineDelta > 0 &&\n dirtyStart < renderRangeEndLine &&\n change.endLine >= renderRangeEndLine;\n const canReuseCachedStates = change.lineDelta === 0;\n const canCacheTokenizedStates =\n canReuseCachedStates ||\n renderRange === undefined ||\n dirtyStart >= viewStart;\n const changedLineRanges: readonly [number, number][] = canReuseCachedStates\n ? (change.changedLineRanges ?? [[dirtyStart, change.endLine]])\n : [[dirtyStart, change.endLine]];\n let offscreenSyncEnd = -1;\n if (dirtyStart < viewStart) {\n for (const [rangeStart, rangeEnd] of changedLineRanges) {\n if (rangeStart < viewStart) {\n offscreenSyncEnd = Math.max(\n offscreenSyncEnd,\n Math.min(rangeEnd, viewStart - 1)\n );\n }\n }\n }\n const shouldFlushOffscreenLines =\n offscreenSyncEnd >= dirtyStart &&\n (canReuseCachedStates || change.lineDelta < 0);\n if (canReuseCachedStates) {\n this.#buildStateStack(dirtyStart);\n } else {\n this.#stateStack.length = Math.min(\n this.#stateStack.length,\n dirtyStart + 1\n );\n if (renderRange === undefined || dirtyStart >= viewStart) {\n this.#buildStateStack(viewStart);\n }\n }\n\n let changedRangeIndex = 0;\n let currentChangedRangeEnd = changedLineRanges[changedRangeIndex][1];\n let backgroundStartLine: number | undefined;\n let backgroundChangedRangeIndex = 0;\n let line = canReuseCachedStates\n ? changedLineRanges[changedRangeIndex][0]\n : viewStart;\n let state = this.#stateStack[line] ?? INITIAL;\n let settled = false;\n const dirtyLines: Map<number, Array<HighlightedToken>> = new Map();\n const offscreenDirtyLines:\n | Map<number, Array<HighlightedToken>>\n | undefined = shouldFlushOffscreenLines ? new Map() : undefined;\n if (offscreenDirtyLines !== undefined && !canReuseCachedStates) {\n const offscreenEnd = Math.min(\n offscreenSyncEnd + 1,\n viewStart,\n renderRangeEndLine\n );\n if (offscreenEnd > dirtyStart) {\n this.#buildStateStack(offscreenEnd);\n let offscreenLine = dirtyStart;\n let offscreenState = this.#stateStack[offscreenLine] ?? INITIAL;\n for (; offscreenLine < offscreenEnd; offscreenLine++) {\n const resolved = this.#tokenizeLineAt(offscreenLine, offscreenState);\n offscreenState = resolved.state;\n offscreenDirtyLines.set(offscreenLine, resolved.resolvedTokens);\n }\n if (canCacheTokenizedStates) {\n this.#stateStack[offscreenEnd] = offscreenState;\n }\n }\n }\n for (; line < renderRangeEndLine; ) {\n const previousNextState = canReuseCachedStates\n ? this.#stateStack[line + 1]\n : undefined;\n if (canCacheTokenizedStates) {\n this.#stateStack[line] = state;\n }\n\n const { resolvedTokens, state: nextState } = this.#tokenizeLineAt(\n line,\n state\n );\n state = nextState;\n\n if (line >= viewStart) {\n dirtyLines.set(line, resolvedTokens);\n } else {\n offscreenDirtyLines?.set(line, resolvedTokens);\n }\n\n if (canCacheTokenizedStates) {\n this.#stateStack[line + 1] = state;\n }\n settled =\n line >= currentChangedRangeEnd &&\n canReuseCachedStates &&\n previousNextState !== undefined &&\n state.equals(previousNextState);\n if (settled) {\n changedRangeIndex++;\n const nextRange = changedLineRanges[changedRangeIndex];\n if (nextRange === undefined) {\n break;\n }\n if (nextRange[0] >= renderRangeEndLine) {\n backgroundStartLine = nextRange[0];\n backgroundChangedRangeIndex = changedRangeIndex;\n break;\n }\n if (this.#stateStack[nextRange[0]] === undefined) {\n currentChangedRangeEnd = nextRange[1];\n line++;\n } else {\n line = nextRange[0];\n state = this.#stateStack[line] ?? state;\n currentChangedRangeEnd = nextRange[1];\n }\n settled = false;\n continue;\n }\n line++;\n }\n\n if (canCacheTokenizedStates) {\n if (line < renderRangeEndLine) {\n this.#stateStack[line + 1] = state;\n } else {\n this.#stateStack[line] = state;\n }\n }\n\n if (offscreenDirtyLines !== undefined && offscreenDirtyLines.size > 0) {\n this.#onDeferTokenize(offscreenDirtyLines, this.#themeType);\n }\n\n if (backgroundStartLine !== undefined) {\n this.#scheduleBackgroundTokenize(\n backgroundStartLine,\n changedLineRanges,\n backgroundChangedRangeIndex\n );\n } else if (!settled && line < lineCount) {\n const backgroundLine =\n crossesRenderRangeEnd && dirtyStart >= viewStart\n ? renderRangeEndLine\n : dirtyStart < viewStart && !canReuseCachedStates\n ? dirtyStart\n : line;\n this.#scheduleBackgroundTokenize(\n backgroundLine,\n canReuseCachedStates ? changedLineRanges : undefined,\n changedRangeIndex\n );\n }\n\n return dirtyLines;\n }\n\n prebuildStateStack(renderRange?: RenderRange): void {\n this.#prebuildStateStack(renderRange);\n }\n\n stopBackgroundTokenize(): void {\n if (this.#isStopped) {\n return;\n }\n this.#isStopped = true;\n this.#isPaused = false;\n this.#lastLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\n this.#detachMessageListener();\n }\n\n pauseBackgroundTokenize(): void {\n if (this.#isStopped || this.#isPaused) {\n return;\n }\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization paused', {\n jobId: this.#backgroundJobId,\n });\n }\n this.#isPaused = true;\n }\n\n resumeBackgroundTokenize(): void {\n if (\n this.#isStopped ||\n !this.#isPaused ||\n this.#grammar === undefined ||\n this.#lastLine < 0\n ) {\n return;\n }\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization resumed', {\n jobId: this.#backgroundJobId,\n });\n }\n this.#isPaused = false;\n this.#postTokenizeMessage(this.#backgroundJobId);\n }\n\n #attachMessageListener(): void {\n if (this.#isMessageListenerAttached) {\n return;\n }\n globalThis.addEventListener('message', this.#onMessage);\n this.#isMessageListenerAttached = true;\n }\n\n #detachMessageListener(): void {\n if (!this.#isMessageListenerAttached) {\n return;\n }\n globalThis.removeEventListener('message', this.#onMessage);\n this.#isMessageListenerAttached = false;\n }\n\n #postTokenizeMessage(jobId: number): void {\n // use `postMessage` instead of `setTimeout(fn, 0)` to avoid 4ms delay\n globalThis.postMessage({ type: 'tokenize', jobId });\n }\n\n #scheduleBackgroundTokenize(\n startLine: number,\n changedLineRanges?: readonly [number, number][],\n changedRangeIndex = 0\n ): void {\n if (isGrammarlessLanguage(this.#textDocument.languageId)) {\n return;\n }\n\n const jobId = ++this.#backgroundJobId;\n\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization scheduled', {\n jobId,\n startLine,\n changedLineRanges,\n changedRangeIndex,\n });\n }\n\n this.#isStopped = false;\n this.#isPaused = false;\n this.#lastLine = startLine;\n this.#backgroundChangedLineRanges = changedLineRanges;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#attachMessageListener();\n this.#postTokenizeMessage(jobId);\n }\n\n #tokenizeLineAt(\n line: number,\n state: StateStack\n ): { resolvedTokens: Array<HighlightedToken>; state: StateStack } {\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n if (\n this.#grammar === undefined ||\n lineText === '' ||\n lineText.trim() === ''\n ) {\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n return {\n resolvedTokens: result.resolvedTokens,\n state: result.ruleStack,\n };\n }\n\n #buildStateStack(endAt: number) {\n const boundedEndAt = Math.min(\n Math.max(0, endAt),\n this.#textDocument.lineCount\n );\n if (this.#stateStack.length > boundedEndAt || this.#grammar === undefined) {\n return;\n }\n let line = this.#stateStack.length - 1;\n let state = this.#stateStack[line] ?? INITIAL;\n for (; line < boundedEndAt; line++) {\n this.#stateStack[line] = state;\n const lineText = this.#textDocument.getLineText(line);\n if (\n lineText.length <= this.#tokenizeMaxLineLength &&\n lineText !== '' &&\n lineText.trim() !== ''\n ) {\n state = this.#grammar.tokenizeLine2(\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n ).ruleStack;\n }\n }\n this.#stateStack[line] = state;\n }\n\n #backgroundTokenize(jobId: number) {\n if (\n this.#isStopped ||\n this.#isPaused ||\n this.#grammar === undefined ||\n jobId !== this.#backgroundJobId\n ) {\n return;\n }\n\n const t = performance.now();\n const lines = new Map<number, Array<HighlightedToken>>();\n const totalLines = this.#textDocument.lineCount;\n const changedLineRanges = this.#backgroundChangedLineRanges;\n\n let line = this.#lastLine;\n let state = this.#stateStack[line] ?? INITIAL;\n let settled = false;\n let changedRangeIndex = this.#backgroundChangedRangeIndex;\n let currentChangedRangeEnd = changedLineRanges?.[changedRangeIndex]?.[1];\n for (; line < totalLines; ) {\n this.#stateStack[line] = state;\n\n const previousNextState =\n currentChangedRangeEnd !== undefined\n ? this.#stateStack[line + 1]\n : undefined;\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n lines.set(line, [[0, '', lineText]]);\n } else if (lineText === '' || lineText.trim() === '') {\n lines.set(line, [[0, '', lineText]]);\n } else {\n const ret = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n lines.set(line, ret.resolvedTokens);\n state = ret.ruleStack;\n }\n\n this.#stateStack[line + 1] = state;\n settled =\n currentChangedRangeEnd !== undefined &&\n line >= currentChangedRangeEnd &&\n previousNextState !== undefined &&\n state.equals(previousNextState);\n line++;\n if (settled) {\n changedRangeIndex++;\n const nextRange = changedLineRanges?.[changedRangeIndex];\n if (nextRange === undefined) {\n break;\n }\n currentChangedRangeEnd = nextRange[1];\n if (this.#stateStack[nextRange[0]] === undefined) {\n settled = false;\n } else {\n line = nextRange[0];\n state = this.#stateStack[line] ?? state;\n settled = false;\n continue;\n }\n }\n\n // limit the time of partial tokenize to 1ms\n if (performance.now() - t > 1) {\n break;\n }\n }\n\n this.#onDeferTokenize(lines, this.#themeType);\n if (this.#isStopped || this.#isPaused || jobId !== this.#backgroundJobId) {\n return;\n }\n\n if (settled || line >= totalLines) {\n this.stopBackgroundTokenize();\n return;\n }\n\n this.#lastLine = line;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#postTokenizeMessage(jobId);\n }\n}\n\nexport function tokenizeLine(\n grammar: IGrammar,\n colorMap: string[],\n lineText: string,\n stateStack: StateStack,\n timeLimit?: number\n): {\n ruleStack: StateStack;\n resolvedTokens: Array<HighlightedToken>;\n} {\n const result = grammar.tokenizeLine2(lineText, stateStack, timeLimit);\n if (result.stoppedEarly) {\n console.warn(\n `[diffs] Time limit reached when tokenizing line: ${lineText.substring(0, 100)}`\n );\n }\n const rawTokens = result.tokens;\n const tokensLength = rawTokens.length / 2;\n const resolvedTokens: Array<HighlightedToken> = [];\n for (let j = 0; j < tokensLength; j++) {\n const offset = rawTokens[2 * j];\n const nextOffset =\n j + 1 < tokensLength ? rawTokens[2 * j + 2] : lineText.length;\n if (offset === nextOffset) {\n // should never reach here, skip if happens anyway\n continue;\n }\n const metadata = rawTokens[2 * j + 1];\n const bg = EncodedTokenMetadata.getForeground(metadata);\n const fg = colorMap[bg];\n const tokenText = lineText.slice(offset, nextOffset);\n resolvedTokens.push([offset, fg, tokenText]);\n }\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n };\n}\n\nexport function renderLineTokens(\n tokens: Array<HighlightedToken>,\n themeType: 'light' | 'dark'\n): (HTMLElement | string)[] {\n return tokens.map(([char, fg, textContent]) => {\n if (char === 0 && fg === '') {\n if (textContent === '') {\n return h('br');\n }\n return textContent;\n }\n return h('span', {\n dataset: {\n char: char.toString(),\n },\n style: `--diffs-token-${themeType}:${fg};`,\n textContent: textContent,\n });\n });\n}\n\n// Shiki special-cases `text` and `ansi` in codeToHast but does not expose grammars.\nfunction isGrammarlessLanguage(languageId: string): boolean {\n return languageId === 'text' || languageId === 'ansi';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tokenzier.js","names":["#textDocument","#grammar","#highlighter","#buildStateStack","#backgroundJobId","#backgroundTokenize","#themeType","#mediaQueryList","#emitThemeChange","#disposes","#tokenizeMaxLineLength","#setStyle","#onDeferTokenize","#onThemeChange","#debug","#ensureGrammar","#colorMap","#setTheme","#stateStack","#scheduleBackgroundTokenize","#themeName","#detachMessageListener","#tokenizeLineAt","#prebuildStateStack","#isStopped","#isPaused","#lastLine","#backgroundChangedLineRanges","#backgroundChangedRangeIndex","#postTokenizeMessage","#isMessageListenerAttached","#onMessage","#attachMessageListener"],"sources":["../../src/editor/tokenzier.ts"],"sourcesContent":["import {\n EncodedTokenMetadata,\n type IGrammar,\n INITIAL,\n type StateStack,\n} from 'shiki/textmate';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport type {\n BaseCodeOptions,\n DiffsHighlighter,\n HighlightedToken,\n RenderRange,\n} from '../types';\nimport type { TextDocument, TextDocumentChange } from './textDocument';\nimport { addEventListener, debounce, h } from './utils';\n\nexport interface EditorTokenizerProps {\n highlighter: DiffsHighlighter;\n textDocument: TextDocument<unknown>;\n codeOptions: BaseCodeOptions;\n setStyle: (style: string) => void;\n onDeferTokenize: (\n lines: Map<number, Array<HighlightedToken>>,\n themeType: 'dark' | 'light'\n ) => void;\n // Fired after the active theme (light/dark mode or theme name) changes and the\n // new theme CSS has been applied. Lets the editor recompute overlay pieces\n // that captured a resolved theme color, e.g. rounded selection corner masks.\n onThemeChange?: () => void;\n __debug?: boolean;\n}\n\n/** Stoppable code tokenizer for the editor */\nexport class EditorTokenizer {\n static TOKENIZE_TIME_LIMIT = 500;\n\n #highlighter: DiffsHighlighter;\n #grammar: IGrammar | undefined;\n #mediaQueryList: MediaQueryList;\n #themeType: 'light' | 'dark';\n // The resolved name of the theme currently applied to the editor (e.g.\n // `github-light`). Tracked so `syncTheme` can detect a host-driven theme swap\n // even when the light/dark mode itself is unchanged.\n #themeName = '';\n #colorMap: string[];\n #textDocument: TextDocument<unknown>;\n #tokenizeMaxLineLength: number;\n #setStyle: EditorTokenizerProps['setStyle'];\n #onDeferTokenize: EditorTokenizerProps['onDeferTokenize'];\n #onThemeChange: EditorTokenizerProps['onThemeChange'];\n #debug: boolean;\n #disposes?: (() => void)[];\n\n // state\n #stateStack: StateStack[] = [INITIAL]; // cached state stack by line index\n #lastLine: number = -1;\n #isStopped: boolean = true;\n #isPaused: boolean = false;\n #backgroundJobId: number = 0;\n #backgroundChangedLineRanges: readonly [number, number][] | undefined;\n #backgroundChangedRangeIndex: number = 0;\n #isMessageListenerAttached: boolean = false;\n\n #prebuildStateStack = debounce(async (renderRange?: RenderRange) => {\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const endLine = Math.min(\n totalLines === Infinity ? Infinity : startingLine + totalLines,\n this.#textDocument.lineCount\n );\n if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId)\n ) {\n await this.#highlighter.loadLanguage(this.#textDocument.languageId);\n this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n this.#buildStateStack(endLine);\n }, 500);\n\n #onMessage = ({ data }: MessageEvent<unknown>) => {\n if (typeof data !== 'object' || data === null) {\n return;\n }\n const { type, jobId } = data as {\n type?: unknown;\n jobId?: unknown;\n };\n if (\n type === 'tokenize' &&\n typeof jobId === 'number' &&\n jobId === this.#backgroundJobId\n ) {\n this.#backgroundTokenize(jobId);\n }\n };\n\n get themeType(): 'light' | 'dark' {\n return this.#themeType;\n }\n\n constructor({\n codeOptions,\n highlighter,\n textDocument,\n setStyle,\n onDeferTokenize,\n onThemeChange,\n __debug,\n }: EditorTokenizerProps) {\n const {\n themeType = 'system',\n theme = DEFAULT_THEMES,\n tokenizeMaxLineLength = 1000,\n } = codeOptions;\n this.#mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');\n if (themeType === 'system') {\n this.#themeType = this.#mediaQueryList.matches ? 'dark' : 'light';\n } else {\n this.#themeType = themeType;\n }\n // Only track the document/system color scheme when the surface follows it\n // (`themeType: 'system'`). A surface pinned to an explicit 'dark'/'light'\n // theme keeps that theme regardless of the page, so re-tokenizing after an\n // edit must emit the same `--diffs-token-{theme}` variable the SSR markup\n // used; otherwise the edited tokens fall back to the default foreground.\n if (typeof theme !== 'string' && themeType === 'system') {\n const observer = new MutationObserver((mutations) => {\n for (const { type, attributeName } of mutations) {\n if (\n type === 'attributes' &&\n attributeName !== null &&\n (attributeName === 'class' || attributeName.startsWith('data-'))\n ) {\n const themeType =\n getComputedStyle(document.body).colorScheme === 'dark'\n ? 'dark'\n : 'light';\n this.#emitThemeChange(theme[themeType], themeType);\n break;\n }\n }\n });\n observer.observe(document.documentElement, { attributes: true });\n observer.observe(document.body, { attributes: true });\n this.#disposes = [\n addEventListener(this.#mediaQueryList, 'change', (e) => {\n const themeType = e.matches ? 'dark' : 'light';\n this.#emitThemeChange(theme[themeType], themeType);\n }),\n () => observer.disconnect(),\n ];\n }\n this.#highlighter = highlighter;\n this.#textDocument = textDocument;\n this.#tokenizeMaxLineLength = tokenizeMaxLineLength;\n this.#setStyle = setStyle;\n this.#onDeferTokenize = onDeferTokenize;\n this.#onThemeChange = onThemeChange;\n this.#debug = __debug ?? false;\n this.#ensureGrammar();\n this.#colorMap = [];\n this.#setTheme(typeof theme === 'string' ? theme : theme[this.#themeType]);\n }\n\n // By default, diffs components support dual themes, but the tokenizer only renders\n // the preferred theme. When the theme type is changed, the tokenizer will re-tokenize the document.\n #emitThemeChange(themeName: string, themeType: 'light' | 'dark') {\n this.#themeType = themeType;\n this.#setTheme(themeName);\n this.stopBackgroundTokenize();\n this.#stateStack = [INITIAL];\n if (this.#grammar !== undefined && this.#textDocument.lineCount > 0) {\n this.#scheduleBackgroundTokenize(0);\n }\n // The theme CSS is now applied, so overlay pieces that captured a resolved\n // theme color (e.g. rounded selection corner masks) can recompute against\n // the new colors instead of keeping the old light/dark value.\n this.#onThemeChange?.();\n }\n\n // Re-apply the editor's theme from the surface's current code options. Edit\n // mode reuses a single tokenizer across re-renders, so when the host swaps the\n // theme — a theme picker, a light/dark toggle, etc. — we must recompute the\n // active theme and re-tokenize. Without this the editor keeps rendering the\n // theme it captured when it first attached (stale line-highlight background\n // and token colors). System-driven changes are still handled by the\n // observers wired up in the constructor; this covers explicit `themeType`/\n // `theme` option changes that those observers don't see.\n syncTheme(codeOptions: BaseCodeOptions): void {\n const { themeType = 'system', theme = DEFAULT_THEMES } = codeOptions;\n const nextThemeType =\n themeType === 'system'\n ? this.#mediaQueryList.matches\n ? 'dark'\n : 'light'\n : themeType;\n const nextThemeName =\n typeof theme === 'string' ? theme : theme[nextThemeType];\n if (\n nextThemeType === this.#themeType &&\n nextThemeName === this.#themeName\n ) {\n return;\n }\n this.#emitThemeChange(nextThemeName, nextThemeType);\n }\n\n #setTheme(themeName: string) {\n this.#themeName = themeName;\n this.#colorMap = this.#highlighter.setTheme(themeName).colorMap;\n const { colors = {} } = this.#highlighter.getTheme(themeName);\n const selectionBackground = colors['editor.selectionBackground'];\n const lineHighlightBackground = colors['editor.lineHighlightBackground'];\n const cursorForeground = colors['editorCursor.foreground'];\n const findMatchBackground = colors['editor.findMatchBackground'];\n const findMatchHighlightBackground =\n colors['editor.findMatchHighlightBackground'];\n const hintForeground = colors['editorHint.foreground'];\n const infoForeground = colors['editorInfo.foreground'];\n const warningForeground = colors['editorWarning.foreground'];\n const errorForeground = colors['editorError.foreground'];\n this.#setStyle(`:host {\n --diffs-editor-selection-bg: ${selectionBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-line-highlight-bg: ${lineHighlightBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-match-bg: ${findMatchBackground ?? 'unset'};\n --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? 'unset'};\n --diffs-editor-cursor-fg: ${cursorForeground ?? 'unset'};\n --diffs-editor-hint-fg: ${hintForeground ?? 'unset'};\n --diffs-editor-info-fg: ${infoForeground ?? 'unset'};\n --diffs-editor-warning-fg: ${warningForeground ?? 'unset'};\n --diffs-editor-error-fg: ${errorForeground ?? 'unset'};\n }`);\n }\n\n cleanUp(): void {\n this.stopBackgroundTokenize();\n this.#detachMessageListener();\n this.#disposes?.forEach((dispose) => dispose());\n this.#disposes = undefined;\n }\n\n // to use `tokenize`, call `prebuildStateStackMap` first to prebuild\n // the state stack map for the given render range.\n tokenize(\n change: TextDocumentChange,\n renderRange?: RenderRange\n ): Map<number, Array<HighlightedToken>> {\n this.#ensureGrammar();\n if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId)\n ) {\n throw new Error(\n `Grammar for language \"${this.#textDocument.languageId}\" not loaded`\n );\n }\n\n const { lineCount } = this.#textDocument;\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const renderRangeEndLine =\n totalLines === Infinity\n ? lineCount\n : Math.min(startingLine + totalLines, lineCount);\n\n const dirtyStart = change.startLine;\n const viewStart = Math.max(startingLine, dirtyStart);\n const crossesRenderRangeEnd =\n renderRange !== undefined &&\n totalLines !== Infinity &&\n change.lineDelta > 0 &&\n dirtyStart < renderRangeEndLine &&\n change.endLine >= renderRangeEndLine;\n const canReuseCachedStates = change.lineDelta === 0;\n const canCacheTokenizedStates =\n canReuseCachedStates ||\n renderRange === undefined ||\n dirtyStart >= viewStart;\n const changedLineRanges: readonly [number, number][] = canReuseCachedStates\n ? (change.changedLineRanges ?? [[dirtyStart, change.endLine]])\n : [[dirtyStart, change.endLine]];\n let offscreenSyncEnd = -1;\n if (dirtyStart < viewStart) {\n for (const [rangeStart, rangeEnd] of changedLineRanges) {\n if (rangeStart < viewStart) {\n offscreenSyncEnd = Math.max(\n offscreenSyncEnd,\n Math.min(rangeEnd, viewStart - 1)\n );\n }\n }\n }\n const shouldFlushOffscreenLines =\n offscreenSyncEnd >= dirtyStart &&\n (canReuseCachedStates || change.lineDelta < 0);\n if (canReuseCachedStates) {\n this.#buildStateStack(dirtyStart);\n } else {\n this.#stateStack.length = Math.min(\n this.#stateStack.length,\n dirtyStart + 1\n );\n if (renderRange === undefined || dirtyStart >= viewStart) {\n this.#buildStateStack(viewStart);\n }\n }\n\n let changedRangeIndex = 0;\n let currentChangedRangeEnd = changedLineRanges[changedRangeIndex][1];\n let backgroundStartLine: number | undefined;\n let backgroundChangedRangeIndex = 0;\n let line = canReuseCachedStates\n ? changedLineRanges[changedRangeIndex][0]\n : viewStart;\n let settled = false;\n const dirtyLines: Map<number, Array<HighlightedToken>> = new Map();\n const offscreenDirtyLines:\n | Map<number, Array<HighlightedToken>>\n | undefined = shouldFlushOffscreenLines ? new Map() : undefined;\n if (offscreenDirtyLines !== undefined && !canReuseCachedStates) {\n const offscreenEnd = Math.min(\n offscreenSyncEnd + 1,\n viewStart,\n renderRangeEndLine\n );\n if (offscreenEnd > dirtyStart) {\n this.#buildStateStack(offscreenEnd);\n let offscreenLine = dirtyStart;\n let offscreenState = this.#stateStack[offscreenLine] ?? INITIAL;\n for (; offscreenLine < offscreenEnd; offscreenLine++) {\n const resolved = this.#tokenizeLineAt(offscreenLine, offscreenState);\n offscreenState = resolved.state;\n offscreenDirtyLines.set(offscreenLine, resolved.resolvedTokens);\n }\n if (canCacheTokenizedStates) {\n this.#stateStack[offscreenEnd] = offscreenState;\n }\n }\n }\n // Seed the loop's grammar state after the offscreen flush, not before it.\n // When a delete's removed lines reach the viewport's first line, the flush\n // rebuilds the cached state up to `line`; reading it earlier would capture\n // the truncated INITIAL state and color the viewport as if outside an open\n // construct (block comment, template literal) it is actually inside.\n let state = this.#stateStack[line] ?? INITIAL;\n for (; line < renderRangeEndLine; ) {\n const previousNextState = canReuseCachedStates\n ? this.#stateStack[line + 1]\n : undefined;\n if (canCacheTokenizedStates) {\n this.#stateStack[line] = state;\n }\n\n const { resolvedTokens, state: nextState } = this.#tokenizeLineAt(\n line,\n state\n );\n state = nextState;\n\n if (line >= viewStart) {\n dirtyLines.set(line, resolvedTokens);\n } else {\n offscreenDirtyLines?.set(line, resolvedTokens);\n }\n\n if (canCacheTokenizedStates) {\n this.#stateStack[line + 1] = state;\n }\n settled =\n line >= currentChangedRangeEnd &&\n canReuseCachedStates &&\n previousNextState !== undefined &&\n state.equals(previousNextState);\n if (settled) {\n changedRangeIndex++;\n const nextRange = changedLineRanges[changedRangeIndex];\n if (nextRange === undefined) {\n break;\n }\n if (nextRange[0] >= renderRangeEndLine) {\n backgroundStartLine = nextRange[0];\n backgroundChangedRangeIndex = changedRangeIndex;\n break;\n }\n if (this.#stateStack[nextRange[0]] === undefined) {\n currentChangedRangeEnd = nextRange[1];\n line++;\n } else {\n line = nextRange[0];\n state = this.#stateStack[line] ?? state;\n currentChangedRangeEnd = nextRange[1];\n }\n settled = false;\n continue;\n }\n line++;\n }\n\n if (canCacheTokenizedStates) {\n if (line < renderRangeEndLine) {\n this.#stateStack[line + 1] = state;\n } else {\n this.#stateStack[line] = state;\n }\n }\n\n if (offscreenDirtyLines !== undefined && offscreenDirtyLines.size > 0) {\n this.#onDeferTokenize(offscreenDirtyLines, this.#themeType);\n }\n\n if (backgroundStartLine !== undefined) {\n this.#scheduleBackgroundTokenize(\n backgroundStartLine,\n changedLineRanges,\n backgroundChangedRangeIndex\n );\n } else if (!settled && line < lineCount) {\n const backgroundLine =\n crossesRenderRangeEnd && dirtyStart >= viewStart\n ? renderRangeEndLine\n : dirtyStart < viewStart && !canReuseCachedStates\n ? dirtyStart\n : line;\n this.#scheduleBackgroundTokenize(\n backgroundLine,\n canReuseCachedStates ? changedLineRanges : undefined,\n changedRangeIndex\n );\n }\n\n return dirtyLines;\n }\n\n prebuildStateStack(renderRange?: RenderRange): void {\n this.#ensureGrammar();\n this.#prebuildStateStack(renderRange);\n }\n\n #ensureGrammar(): void {\n if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId) &&\n this.#highlighter\n .getLoadedLanguages()\n .includes(this.#textDocument.languageId)\n ) {\n this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n }\n\n stopBackgroundTokenize(): void {\n if (this.#isStopped) {\n return;\n }\n this.#isStopped = true;\n this.#isPaused = false;\n this.#lastLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\n this.#detachMessageListener();\n }\n\n pauseBackgroundTokenize(): void {\n if (this.#isStopped || this.#isPaused) {\n return;\n }\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization paused', {\n jobId: this.#backgroundJobId,\n });\n }\n this.#isPaused = true;\n }\n\n resumeBackgroundTokenize(): void {\n if (\n this.#isStopped ||\n !this.#isPaused ||\n this.#grammar === undefined ||\n this.#lastLine < 0\n ) {\n return;\n }\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization resumed', {\n jobId: this.#backgroundJobId,\n });\n }\n this.#isPaused = false;\n this.#postTokenizeMessage(this.#backgroundJobId);\n }\n\n #attachMessageListener(): void {\n if (this.#isMessageListenerAttached) {\n return;\n }\n globalThis.addEventListener('message', this.#onMessage);\n this.#isMessageListenerAttached = true;\n }\n\n #detachMessageListener(): void {\n if (!this.#isMessageListenerAttached) {\n return;\n }\n globalThis.removeEventListener('message', this.#onMessage);\n this.#isMessageListenerAttached = false;\n }\n\n #postTokenizeMessage(jobId: number): void {\n // use `postMessage` instead of `setTimeout(fn, 0)` to avoid 4ms delay\n globalThis.postMessage({ type: 'tokenize', jobId });\n }\n\n #scheduleBackgroundTokenize(\n startLine: number,\n changedLineRanges?: readonly [number, number][],\n changedRangeIndex = 0\n ): void {\n if (isGrammarlessLanguage(this.#textDocument.languageId)) {\n return;\n }\n\n const jobId = ++this.#backgroundJobId;\n\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization scheduled', {\n jobId,\n startLine,\n changedLineRanges,\n changedRangeIndex,\n });\n }\n\n this.#isStopped = false;\n this.#isPaused = false;\n this.#lastLine = startLine;\n this.#backgroundChangedLineRanges = changedLineRanges;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#attachMessageListener();\n this.#postTokenizeMessage(jobId);\n }\n\n #tokenizeLineAt(\n line: number,\n state: StateStack\n ): { resolvedTokens: Array<HighlightedToken>; state: StateStack } {\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n if (\n this.#grammar === undefined ||\n lineText === '' ||\n lineText.trim() === ''\n ) {\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n return {\n resolvedTokens: result.resolvedTokens,\n state: result.ruleStack,\n };\n }\n\n #buildStateStack(endAt: number) {\n const boundedEndAt = Math.min(\n Math.max(0, endAt),\n this.#textDocument.lineCount\n );\n if (this.#stateStack.length > boundedEndAt || this.#grammar === undefined) {\n return;\n }\n let line = this.#stateStack.length - 1;\n let state = this.#stateStack[line] ?? INITIAL;\n for (; line < boundedEndAt; line++) {\n this.#stateStack[line] = state;\n const lineText = this.#textDocument.getLineText(line);\n if (\n lineText.length <= this.#tokenizeMaxLineLength &&\n lineText !== '' &&\n lineText.trim() !== ''\n ) {\n state = this.#grammar.tokenizeLine2(\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n ).ruleStack;\n }\n }\n this.#stateStack[line] = state;\n }\n\n #backgroundTokenize(jobId: number) {\n if (\n this.#isStopped ||\n this.#isPaused ||\n this.#grammar === undefined ||\n jobId !== this.#backgroundJobId\n ) {\n return;\n }\n\n const t = performance.now();\n const lines = new Map<number, Array<HighlightedToken>>();\n const totalLines = this.#textDocument.lineCount;\n const changedLineRanges = this.#backgroundChangedLineRanges;\n\n let line = this.#lastLine;\n let state = this.#stateStack[line] ?? INITIAL;\n let settled = false;\n let changedRangeIndex = this.#backgroundChangedRangeIndex;\n let currentChangedRangeEnd = changedLineRanges?.[changedRangeIndex]?.[1];\n for (; line < totalLines; ) {\n this.#stateStack[line] = state;\n\n const previousNextState =\n currentChangedRangeEnd !== undefined\n ? this.#stateStack[line + 1]\n : undefined;\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n lines.set(line, [[0, '', lineText]]);\n } else if (lineText === '' || lineText.trim() === '') {\n lines.set(line, [[0, '', lineText]]);\n } else {\n const ret = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n lines.set(line, ret.resolvedTokens);\n state = ret.ruleStack;\n }\n\n this.#stateStack[line + 1] = state;\n settled =\n currentChangedRangeEnd !== undefined &&\n line >= currentChangedRangeEnd &&\n previousNextState !== undefined &&\n state.equals(previousNextState);\n line++;\n if (settled) {\n changedRangeIndex++;\n const nextRange = changedLineRanges?.[changedRangeIndex];\n if (nextRange === undefined) {\n break;\n }\n currentChangedRangeEnd = nextRange[1];\n if (this.#stateStack[nextRange[0]] === undefined) {\n settled = false;\n } else {\n line = nextRange[0];\n state = this.#stateStack[line] ?? state;\n settled = false;\n continue;\n }\n }\n\n // limit the time of partial tokenize to 1ms\n if (performance.now() - t > 1) {\n break;\n }\n }\n\n this.#onDeferTokenize(lines, this.#themeType);\n if (this.#isStopped || this.#isPaused || jobId !== this.#backgroundJobId) {\n return;\n }\n\n if (settled || line >= totalLines) {\n this.stopBackgroundTokenize();\n return;\n }\n\n this.#lastLine = line;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#postTokenizeMessage(jobId);\n }\n}\n\nexport function tokenizeLine(\n grammar: IGrammar,\n colorMap: string[],\n lineText: string,\n stateStack: StateStack,\n timeLimit?: number\n): {\n ruleStack: StateStack;\n resolvedTokens: Array<HighlightedToken>;\n} {\n const result = grammar.tokenizeLine2(lineText, stateStack, timeLimit);\n if (result.stoppedEarly) {\n console.warn(\n `[diffs] Time limit reached when tokenizing line: ${lineText.substring(0, 100)}`\n );\n }\n const rawTokens = result.tokens;\n const tokensLength = rawTokens.length / 2;\n const resolvedTokens: Array<HighlightedToken> = [];\n for (let j = 0; j < tokensLength; j++) {\n const offset = rawTokens[2 * j];\n const nextOffset =\n j + 1 < tokensLength ? rawTokens[2 * j + 2] : lineText.length;\n if (offset === nextOffset) {\n // should never reach here, skip if happens anyway\n continue;\n }\n const metadata = rawTokens[2 * j + 1];\n const bg = EncodedTokenMetadata.getForeground(metadata);\n const fg = colorMap[bg];\n const tokenText = lineText.slice(offset, nextOffset);\n resolvedTokens.push([offset, fg, tokenText]);\n }\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n };\n}\n\nexport function renderLineTokens(\n tokens: Array<HighlightedToken>,\n themeType: 'light' | 'dark'\n): (HTMLElement | string)[] {\n return tokens.map(([char, fg, textContent]) => {\n if (char === 0 && fg === '') {\n if (textContent === '') {\n return h('br');\n }\n return textContent;\n }\n return h('span', {\n dataset: {\n char: char.toString(),\n },\n style: `--diffs-token-${themeType}:${fg};`,\n textContent: textContent,\n });\n });\n}\n\n// Shiki special-cases `text` and `ansi` in codeToHast but does not expose grammars.\nfunction isGrammarlessLanguage(languageId: string): boolean {\n return languageId === 'text' || languageId === 'ansi';\n}\n"],"mappings":"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"}
@@ -13,6 +13,9 @@ declare function clampDomOffset(node: Node, offset: number): number;
13
13
  declare function extend<T extends object>(obj: T, attrs: Partial<T>): T;
14
14
  declare function debounce<T extends (...args: any[]) => void>(func: T, wait: number): (...args: Parameters<T>) => void;
15
15
  declare function round(value: number, precision?: number): number;
16
+ declare function endsWithLineBreak(text: string): boolean;
17
+ declare function createSegmenter(options: Intl.SegmenterOptions): Intl.Segmenter | undefined;
18
+ declare function getGraphemeSegmenter(): Intl.Segmenter | undefined;
16
19
  //#endregion
17
- export { addEventListener, clampDomOffset, debounce, extend, getLineNumberAttr, h, round };
20
+ export { addEventListener, clampDomOffset, createSegmenter, debounce, endsWithLineBreak, extend, getGraphemeSegmenter, getLineNumberAttr, h, round };
18
21
  //# sourceMappingURL=utils.d.ts.map