@pierre/diffs 1.5.2 → 1.6.0-beta.1

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 (274) hide show
  1. package/README.md +4 -3
  2. package/dist/components/CodeView.d.ts.map +1 -1
  3. package/dist/components/CodeView.js +6 -5
  4. package/dist/components/CodeView.js.map +1 -1
  5. package/dist/components/File.d.ts.map +1 -1
  6. package/dist/components/File.js +11 -6
  7. package/dist/components/File.js.map +1 -1
  8. package/dist/components/FileDiff.d.ts.map +1 -1
  9. package/dist/components/FileDiff.js +12 -7
  10. package/dist/components/FileDiff.js.map +1 -1
  11. package/dist/components/FileStream.d.ts +6 -4
  12. package/dist/components/FileStream.d.ts.map +1 -1
  13. package/dist/components/FileStream.js +49 -36
  14. package/dist/components/FileStream.js.map +1 -1
  15. package/dist/constants.d.ts +3 -2
  16. package/dist/constants.d.ts.map +1 -1
  17. package/dist/constants.js +2 -1
  18. package/dist/constants.js.map +1 -1
  19. package/dist/editor/editor.d.ts +2 -1
  20. package/dist/editor/editor.d.ts.map +1 -1
  21. package/dist/editor/editor.js +5 -1
  22. package/dist/editor/editor.js.map +1 -1
  23. package/dist/editor/tokenizer.d.ts +6 -4
  24. package/dist/editor/tokenizer.d.ts.map +1 -1
  25. package/dist/editor/tokenizer.js +25 -470
  26. package/dist/editor/tokenizer.js.map +1 -1
  27. package/dist/highlighter/DiffsEditorTokenizer.d.ts +16 -0
  28. package/dist/highlighter/DiffsEditorTokenizer.d.ts.map +1 -0
  29. package/dist/highlighter/DiffsEditorTokenizer.js +0 -0
  30. package/dist/highlighter/DiffsHighlighter.d.ts +41 -0
  31. package/dist/highlighter/DiffsHighlighter.d.ts.map +1 -0
  32. package/dist/highlighter/DiffsHighlighter.js +39 -0
  33. package/dist/highlighter/DiffsHighlighter.js.map +1 -0
  34. package/dist/highlighter/backends/highlights.d.ts +26 -0
  35. package/dist/highlighter/backends/highlights.d.ts.map +1 -0
  36. package/dist/highlighter/backends/highlights.js +71 -0
  37. package/dist/highlighter/backends/highlights.js.map +1 -0
  38. package/dist/highlighter/backends/shiki.d.ts +27 -0
  39. package/dist/highlighter/backends/shiki.d.ts.map +1 -0
  40. package/dist/highlighter/backends/shiki.js +107 -0
  41. package/dist/highlighter/backends/shiki.js.map +1 -0
  42. package/dist/highlighter/highlighterType.d.ts +13 -0
  43. package/dist/highlighter/highlighterType.d.ts.map +1 -0
  44. package/dist/highlighter/highlighterType.js +32 -0
  45. package/dist/highlighter/highlighterType.js.map +1 -0
  46. package/dist/highlighter/highlights-editor.d.ts +24 -0
  47. package/dist/highlighter/highlights-editor.d.ts.map +1 -0
  48. package/dist/highlighter/highlights-editor.js +166 -0
  49. package/dist/highlighter/highlights-editor.js.map +1 -0
  50. package/dist/highlighter/highlights-stream.d.ts +20 -0
  51. package/dist/highlighter/highlights-stream.d.ts.map +1 -0
  52. package/dist/highlighter/highlights-stream.js +93 -0
  53. package/dist/highlighter/highlights-stream.js.map +1 -0
  54. package/dist/highlighter/languages/areLanguagesAttached.d.ts +2 -1
  55. package/dist/highlighter/languages/areLanguagesAttached.d.ts.map +1 -1
  56. package/dist/highlighter/languages/areLanguagesAttached.js +4 -6
  57. package/dist/highlighter/languages/areLanguagesAttached.js.map +1 -1
  58. package/dist/highlighter/languages/attachResolvedLanguages.d.ts +6 -1
  59. package/dist/highlighter/languages/attachResolvedLanguages.d.ts.map +1 -1
  60. package/dist/highlighter/languages/attachResolvedLanguages.js +6 -11
  61. package/dist/highlighter/languages/attachResolvedLanguages.js.map +1 -1
  62. package/dist/highlighter/languages/constants.d.ts +1 -1
  63. package/dist/highlighter/languages/getResolvedLanguages.d.ts +1 -1
  64. package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts +1 -1
  65. package/dist/highlighter/languages/resolveLanguage.d.ts +1 -1
  66. package/dist/highlighter/languages/resolveLanguage.d.ts.map +1 -1
  67. package/dist/highlighter/languages/resolveLanguage.js +19 -16
  68. package/dist/highlighter/languages/resolveLanguage.js.map +1 -1
  69. package/dist/highlighter/languages/resolveLanguages.d.ts +1 -1
  70. package/dist/highlighter/shared_highlighter.d.ts +23 -9
  71. package/dist/highlighter/shared_highlighter.d.ts.map +1 -1
  72. package/dist/highlighter/shared_highlighter.js +59 -47
  73. package/dist/highlighter/shared_highlighter.js.map +1 -1
  74. package/dist/highlighter/shiki-editor.d.ts +25 -0
  75. package/dist/highlighter/shiki-editor.d.ts.map +1 -0
  76. package/dist/highlighter/shiki-editor.js +483 -0
  77. package/dist/highlighter/shiki-editor.js.map +1 -0
  78. package/dist/highlighter/shiki-stream.d.ts +20 -0
  79. package/dist/highlighter/shiki-stream.d.ts.map +1 -0
  80. package/dist/highlighter/shiki-stream.js +60 -0
  81. package/dist/highlighter/shiki-stream.js.map +1 -0
  82. package/dist/highlighter/stream-tokenizer.d.ts +40 -0
  83. package/dist/highlighter/stream-tokenizer.d.ts.map +1 -0
  84. package/dist/highlighter/stream-tokenizer.js +70 -0
  85. package/dist/highlighter/stream-tokenizer.js.map +1 -0
  86. package/dist/highlighter/themes/areThemesAttached.d.ts +3 -2
  87. package/dist/highlighter/themes/areThemesAttached.d.ts.map +1 -1
  88. package/dist/highlighter/themes/areThemesAttached.js +5 -4
  89. package/dist/highlighter/themes/areThemesAttached.js.map +1 -1
  90. package/dist/highlighter/themes/attachResolvedThemes.d.ts +5 -2
  91. package/dist/highlighter/themes/attachResolvedThemes.d.ts.map +1 -1
  92. package/dist/highlighter/themes/attachResolvedThemes.js +4 -16
  93. package/dist/highlighter/themes/attachResolvedThemes.js.map +1 -1
  94. package/dist/highlighter/themes/cleanUpResolvedThemes.d.ts +3 -1
  95. package/dist/highlighter/themes/cleanUpResolvedThemes.d.ts.map +1 -1
  96. package/dist/highlighter/themes/cleanUpResolvedThemes.js +8 -5
  97. package/dist/highlighter/themes/cleanUpResolvedThemes.js.map +1 -1
  98. package/dist/highlighter/themes/createCSSVariablesTheme.d.ts +7 -0
  99. package/dist/highlighter/themes/createCSSVariablesTheme.d.ts.map +1 -0
  100. package/dist/highlighter/themes/createCSSVariablesTheme.js +89 -0
  101. package/dist/highlighter/themes/createCSSVariablesTheme.js.map +1 -0
  102. package/dist/highlighter/themes/createCachedLoader.d.ts +5 -0
  103. package/dist/highlighter/themes/createCachedLoader.d.ts.map +1 -0
  104. package/dist/highlighter/themes/createCachedLoader.js +15 -0
  105. package/dist/highlighter/themes/createCachedLoader.js.map +1 -0
  106. package/dist/highlighter/themes/getResolvedOrResolveTheme.d.ts +3 -2
  107. package/dist/highlighter/themes/getResolvedOrResolveTheme.d.ts.map +1 -1
  108. package/dist/highlighter/themes/getResolvedOrResolveTheme.js +4 -4
  109. package/dist/highlighter/themes/getResolvedOrResolveTheme.js.map +1 -1
  110. package/dist/highlighter/themes/getResolvedThemes.d.ts +3 -2
  111. package/dist/highlighter/themes/getResolvedThemes.d.ts.map +1 -1
  112. package/dist/highlighter/themes/getResolvedThemes.js +4 -3
  113. package/dist/highlighter/themes/getResolvedThemes.js.map +1 -1
  114. package/dist/highlighter/themes/hasResolvedThemes.d.ts +2 -2
  115. package/dist/highlighter/themes/hasResolvedThemes.d.ts.map +1 -1
  116. package/dist/highlighter/themes/hasResolvedThemes.js +4 -3
  117. package/dist/highlighter/themes/hasResolvedThemes.js.map +1 -1
  118. package/dist/highlighter/themes/registerCustomCSSVariableTheme.d.ts.map +1 -1
  119. package/dist/highlighter/themes/registerCustomCSSVariableTheme.js +3 -3
  120. package/dist/highlighter/themes/registerCustomCSSVariableTheme.js.map +1 -1
  121. package/dist/highlighter/themes/registerCustomTheme.d.ts +9 -4
  122. package/dist/highlighter/themes/registerCustomTheme.d.ts.map +1 -1
  123. package/dist/highlighter/themes/registerCustomTheme.js +8 -16
  124. package/dist/highlighter/themes/registerCustomTheme.js.map +1 -1
  125. package/dist/highlighter/themes/resolveTheme.d.ts +3 -2
  126. package/dist/highlighter/themes/resolveTheme.d.ts.map +1 -1
  127. package/dist/highlighter/themes/resolveTheme.js +4 -7
  128. package/dist/highlighter/themes/resolveTheme.js.map +1 -1
  129. package/dist/highlighter/themes/resolveThemes.d.ts +3 -2
  130. package/dist/highlighter/themes/resolveThemes.d.ts.map +1 -1
  131. package/dist/highlighter/themes/resolveThemes.js +4 -7
  132. package/dist/highlighter/themes/resolveThemes.js.map +1 -1
  133. package/dist/highlighter/themes/themeResolver.d.ts +10 -4
  134. package/dist/highlighter/themes/themeResolver.d.ts.map +1 -1
  135. package/dist/highlighter/themes/themeResolver.js +141 -2
  136. package/dist/highlighter/themes/themeResolver.js.map +1 -1
  137. package/dist/highlighter/themes/types.d.ts +23 -0
  138. package/dist/highlighter/themes/types.d.ts.map +1 -0
  139. package/dist/highlighter/themes/types.js +0 -0
  140. package/dist/highlighter/tokenizer-types.d.ts +35 -0
  141. package/dist/highlighter/tokenizer-types.d.ts.map +1 -0
  142. package/dist/highlighter/tokenizer-types.js +0 -0
  143. package/dist/highlighter/types.d.ts +55 -0
  144. package/dist/highlighter/types.d.ts.map +1 -0
  145. package/dist/highlighter/types.js +0 -0
  146. package/dist/index.d.ts +14 -10
  147. package/dist/index.js +16 -18
  148. package/dist/managers/InteractionManager.d.ts.map +1 -1
  149. package/dist/managers/InteractionManager.js +2 -2
  150. package/dist/managers/InteractionManager.js.map +1 -1
  151. package/dist/node_modules/.pnpm/@types_hast@3.0.4/node_modules/@types/hast/index.d.ts +9 -1
  152. package/dist/node_modules/.pnpm/@types_hast@3.0.4/node_modules/@types/hast/index.d.ts.map +1 -1
  153. package/dist/react/CodeView.js +1 -1
  154. package/dist/react/index.d.ts +8 -3
  155. package/dist/renderers/DiffHunksRenderer.d.ts +2 -1
  156. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  157. package/dist/renderers/DiffHunksRenderer.js +31 -22
  158. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  159. package/dist/renderers/FileRenderer.d.ts +2 -1
  160. package/dist/renderers/FileRenderer.d.ts.map +1 -1
  161. package/dist/renderers/FileRenderer.js +33 -24
  162. package/dist/renderers/FileRenderer.js.map +1 -1
  163. package/dist/shiki-stream/index.d.ts +3 -3
  164. package/dist/shiki-stream/index.js +1 -2
  165. package/dist/shiki-stream/stream.d.ts +4 -4
  166. package/dist/shiki-stream/stream.d.ts.map +1 -1
  167. package/dist/shiki-stream/stream.js +20 -9
  168. package/dist/shiki-stream/stream.js.map +1 -1
  169. package/dist/shiki-stream/types.d.ts +7 -38
  170. package/dist/shiki-stream/types.d.ts.map +1 -1
  171. package/dist/ssr/FileDiffReact.js +1 -1
  172. package/dist/ssr/index.d.ts +7 -2
  173. package/dist/ssr/renderHTML.js +2 -2
  174. package/dist/ssr/renderHTML.js.map +1 -1
  175. package/dist/style.js +1 -1
  176. package/dist/style.js.map +1 -1
  177. package/dist/types.d.ts +10 -11
  178. package/dist/types.d.ts.map +1 -1
  179. package/dist/utils/createSpanNodeFromToken.d.ts +3 -2
  180. package/dist/utils/createSpanNodeFromToken.d.ts.map +1 -1
  181. package/dist/utils/createSpanNodeFromToken.js +4 -5
  182. package/dist/utils/createSpanNodeFromToken.js.map +1 -1
  183. package/dist/utils/cssWrappers.d.ts.map +1 -1
  184. package/dist/utils/cssWrappers.js +12 -0
  185. package/dist/utils/cssWrappers.js.map +1 -1
  186. package/dist/utils/getHighlighterOptions.d.ts.map +1 -1
  187. package/dist/utils/getHighlighterOptions.js +3 -2
  188. package/dist/utils/getHighlighterOptions.js.map +1 -1
  189. package/dist/utils/getHighlighterThemeStyles.d.ts +2 -1
  190. package/dist/utils/getHighlighterThemeStyles.d.ts.map +1 -1
  191. package/dist/utils/getHighlighterThemeStyles.js +13 -3
  192. package/dist/utils/getHighlighterThemeStyles.js.map +1 -1
  193. package/dist/utils/getTokenOptions.d.ts +7 -0
  194. package/dist/utils/getTokenOptions.d.ts.map +1 -0
  195. package/dist/utils/getTokenOptions.js +16 -0
  196. package/dist/utils/getTokenOptions.js.map +1 -0
  197. package/dist/utils/hastToHtml.d.ts +10 -0
  198. package/dist/utils/hastToHtml.d.ts.map +1 -0
  199. package/dist/utils/hastToHtml.js +125 -0
  200. package/dist/utils/hastToHtml.js.map +1 -0
  201. package/dist/utils/parseDiffDecorations.d.ts +2 -1
  202. package/dist/utils/parseDiffDecorations.d.ts.map +1 -1
  203. package/dist/utils/renderDiffWithHighlighter.d.ts +3 -2
  204. package/dist/utils/renderDiffWithHighlighter.d.ts.map +1 -1
  205. package/dist/utils/renderDiffWithHighlighter.js +33 -48
  206. package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
  207. package/dist/utils/renderFileWithHighlighter.d.ts +3 -2
  208. package/dist/utils/renderFileWithHighlighter.d.ts.map +1 -1
  209. package/dist/utils/renderFileWithHighlighter.js +10 -26
  210. package/dist/utils/renderFileWithHighlighter.js.map +1 -1
  211. package/dist/utils/renderTokenLines.d.ts +17 -0
  212. package/dist/utils/renderTokenLines.d.ts.map +1 -0
  213. package/dist/utils/renderTokenLines.js +246 -0
  214. package/dist/utils/renderTokenLines.js.map +1 -0
  215. package/dist/utils/resolvePreferredHighlighter.d.ts +13 -0
  216. package/dist/utils/resolvePreferredHighlighter.d.ts.map +1 -0
  217. package/dist/utils/resolvePreferredHighlighter.js +11 -0
  218. package/dist/utils/resolvePreferredHighlighter.js.map +1 -0
  219. package/dist/utils/setDeferredArrayItem.d.ts +5 -0
  220. package/dist/utils/setDeferredArrayItem.d.ts.map +1 -0
  221. package/dist/utils/setDeferredArrayItem.js +39 -0
  222. package/dist/utils/setDeferredArrayItem.js.map +1 -0
  223. package/dist/utils/tokenStyle.d.ts +7 -0
  224. package/dist/utils/tokenStyle.d.ts.map +1 -0
  225. package/dist/utils/tokenStyle.js +28 -0
  226. package/dist/utils/tokenStyle.js.map +1 -0
  227. package/dist/utils/tokensToHtml.d.ts +8 -0
  228. package/dist/utils/tokensToHtml.d.ts.map +1 -0
  229. package/dist/utils/tokensToHtml.js +45 -0
  230. package/dist/utils/tokensToHtml.js.map +1 -0
  231. package/dist/utils/wrapTokenFragments.js.map +1 -1
  232. package/dist/worker/WorkerPoolManager.d.ts +2 -2
  233. package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
  234. package/dist/worker/WorkerPoolManager.js +56 -46
  235. package/dist/worker/WorkerPoolManager.js.map +1 -1
  236. package/dist/worker/hastLinesTransport.d.ts +14 -0
  237. package/dist/worker/hastLinesTransport.d.ts.map +1 -0
  238. package/dist/worker/hastLinesTransport.js +156 -0
  239. package/dist/worker/hastLinesTransport.js.map +1 -0
  240. package/dist/worker/highlights-sAHlxqlf.js +317 -0
  241. package/dist/worker/highlights-sAHlxqlf.js.map +1 -0
  242. package/dist/worker/index.d.ts +1 -1
  243. package/dist/worker/shiki-Bx2JpdqZ.js +697 -0
  244. package/dist/worker/shiki-Bx2JpdqZ.js.map +1 -0
  245. package/dist/worker/stream-tokenizer-YZ6M1qSx.js +424 -0
  246. package/dist/worker/stream-tokenizer-YZ6M1qSx.js.map +1 -0
  247. package/dist/worker/types.d.ts +5 -3
  248. package/dist/worker/types.d.ts.map +1 -1
  249. package/dist/worker/worker-portable.js +41 -13337
  250. package/dist/worker/worker-portable.js.map +1 -1
  251. package/dist/worker/worker.js +672 -349
  252. package/dist/worker/worker.js.map +1 -1
  253. package/dist/worker/workerMessage.d.ts +24 -0
  254. package/dist/worker/workerMessage.d.ts.map +1 -0
  255. package/dist/worker/workerMessage.js +0 -0
  256. package/package.json +33 -29
  257. package/dist/highlighter/themes/constants.d.ts +0 -5
  258. package/dist/highlighter/themes/constants.d.ts.map +0 -1
  259. package/dist/highlighter/themes/constants.js +0 -6
  260. package/dist/highlighter/themes/constants.js.map +0 -1
  261. package/dist/highlighter/themes/themeResolution.d.ts +0 -7
  262. package/dist/highlighter/themes/themeResolution.d.ts.map +0 -1
  263. package/dist/highlighter/themes/themeResolution.js +0 -21
  264. package/dist/highlighter/themes/themeResolution.js.map +0 -1
  265. package/dist/shiki-stream/tokenizer.d.ts +0 -23
  266. package/dist/shiki-stream/tokenizer.d.ts.map +0 -1
  267. package/dist/shiki-stream/tokenizer.js +0 -72
  268. package/dist/shiki-stream/tokenizer.js.map +0 -1
  269. package/dist/utils/createTransformerWithState.d.ts +0 -12
  270. package/dist/utils/createTransformerWithState.d.ts.map +0 -1
  271. package/dist/utils/createTransformerWithState.js +0 -89
  272. package/dist/utils/createTransformerWithState.js.map +0 -1
  273. package/dist/worker/wasm-B9ZqxnKj.js +0 -8
  274. package/dist/worker/wasm-B9ZqxnKj.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"tokenizer.js","names":[],"sources":["../../src/editor/tokenizer.ts"],"sourcesContent":["import { colorUtils } from '@pierre/theming/color';\nimport {\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\nconst TOKENIZE_TIME_LIMIT = 500;\nlet nextTokenizerId = 0;\n\nexport interface EditorTokenizerProps {\n highlighter: DiffsHighlighter;\n textDocument: TextDocument;\n codeOptions: BaseCodeOptions;\n matchBrackets?: boolean;\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 #highlighter: DiffsHighlighter;\n #grammar: IGrammar | undefined;\n #mediaQueryList: MediaQueryList;\n #themeType: 'light' | 'dark' = '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;\n #tokenizeMaxLineLength: number;\n #setStyle: EditorTokenizerProps['setStyle'];\n #onDeferTokenize: EditorTokenizerProps['onDeferTokenize'];\n #onThemeChange: EditorTokenizerProps['onThemeChange'];\n #matchBrackets: boolean;\n #debug: boolean;\n #disposes?: (() => void)[];\n #isCleanedUp = false;\n\n // state\n #stateStack: StateStack[] = [INITIAL]; // cached state stack by line index\n #comparisonStateStack: StateStack[] = [];\n #comparisonStateStackStart = 0;\n #comparisonLineChanges: NonNullable<\n TextDocumentChange['changedLineChanges']\n > = [];\n #lastLine: number = -1;\n #isStopped: boolean = true;\n #isPaused: boolean = false;\n #backgroundJobId: number = 0;\n #tokenizerId = ++nextTokenizerId;\n #backgroundPrebuildEndLine = -1;\n #pendingPrebuildEndLine = -1;\n #backgroundChangedLineRanges: readonly [number, number][] | undefined;\n #backgroundChangedRangeIndex: number = 0;\n #bracketIgnoredRanges: ([number, number][] | null | undefined)[] = [];\n #isMessageListenerAttached: boolean = false;\n\n #prebuildStateStack = debounce(async (renderRange?: RenderRange) => {\n // Drop work scheduled before cleanUp; a late timer must not call setTheme\n // on a highlighter that tests (or hosts) have already disposed.\n if (this.#isCleanedUp) {\n return;\n }\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 if (this.#isCleanedUp) {\n return;\n }\n this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n this.#ensureActiveTheme();\n this.#scheduleStatePrebuild(endLine);\n }, 500);\n\n #onMessage = ({ data }: MessageEvent<unknown>) => {\n if (typeof data !== 'object' || data === null) {\n return;\n }\n const { type, tokenizerId, jobId } = data as {\n type?: unknown;\n tokenizerId?: unknown;\n jobId?: unknown;\n };\n if (\n type === 'tokenize' &&\n tokenizerId === this.#tokenizerId &&\n typeof jobId === 'number' &&\n jobId === this.#backgroundJobId\n ) {\n if (this.#backgroundPrebuildEndLine >= 0) {\n this.#backgroundPrebuild(jobId);\n } else {\n this.#backgroundTokenize(jobId);\n }\n }\n };\n\n get themeType(): 'light' | 'dark' {\n return this.#themeType;\n }\n\n getStringCommentRegexpRangesInLine(\n lineIndex: number\n ): [number, number][] | null {\n if (\n !this.#matchBrackets ||\n lineIndex < 0 ||\n lineIndex >= this.#textDocument.lineCount\n ) {\n return null;\n }\n this.#ensureGrammar();\n if (this.#grammar === undefined) {\n return null;\n }\n if (this.#bracketIgnoredRanges[lineIndex] === undefined) {\n this.#buildStateStack(lineIndex);\n const state = this.#stateStack[lineIndex] ?? INITIAL;\n const result = this.#tokenizeLineAt(lineIndex, state);\n this.#stateStack[lineIndex + 1] = result.state;\n }\n return this.#bracketIgnoredRanges[lineIndex] ?? null;\n }\n\n constructor({\n codeOptions,\n highlighter,\n textDocument,\n matchBrackets,\n setStyle,\n onDeferTokenize,\n onThemeChange,\n __debug,\n }: EditorTokenizerProps) {\n const {\n themeType: themeTypeOption = 'system',\n theme = DEFAULT_THEMES,\n tokenizeMaxLineLength = 1000,\n } = codeOptions;\n this.#mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');\n let themeType: 'light' | 'dark' | undefined;\n if (themeTypeOption === 'system') {\n // Prefer the host document's computed color-scheme (page CSS/classes can\n // force light/dark while the OS media query differs) over matchMedia.\n themeType = this.#resolveSystemThemeType();\n } else {\n themeType = themeTypeOption;\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' && themeTypeOption === '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 = this.#resolveSystemThemeType();\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', () => {\n // Re-read computed color-scheme so a host-forced scheme still wins\n // when the OS preference changes underneath it.\n const themeType = this.#resolveSystemThemeType();\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.#matchBrackets = matchBrackets !== false;\n this.#debug = __debug ?? false;\n this.#ensureGrammar();\n this.#colorMap = [];\n this.#setTheme(\n typeof theme === 'string' ? theme : theme[themeType],\n typeof theme === 'string' ? undefined : themeType\n );\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 if (themeName === this.#themeName && themeType === this.#themeType) {\n return;\n }\n this.#setTheme(themeName, themeType);\n this.stopBackgroundTokenize();\n this.#stateStack = [INITIAL];\n this.#comparisonStateStack = [];\n this.#comparisonStateStackStart = 0;\n this.#comparisonLineChanges = [];\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 // Respect an explicit host color-scheme override. When the computed value\n // advertises support for both schemes, let the OS preference choose one.\n #resolveSystemThemeType(): 'light' | 'dark' {\n try {\n if (\n typeof document !== 'undefined' &&\n typeof getComputedStyle === 'function' &&\n document.body != null\n ) {\n const colorSchemes = getComputedStyle(document.body).colorScheme.split(\n /\\s+/\n );\n const supportsDark = colorSchemes.includes('dark');\n const supportsLight = colorSchemes.includes('light');\n // A single host-forced scheme wins. `light dark` only declares support\n // for both schemes, so the media query still selects the active one.\n if (supportsDark !== supportsLight) {\n return supportsDark ? 'dark' : 'light';\n }\n }\n } catch {\n // jsdom and similar harnesses may lack getComputedStyle or throw; fall\n // through to the OS media query.\n }\n return this.#mediaQueryList.matches ? 'dark' : 'light';\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 // A single pinned theme does not follow the themeType option or system\n // scheme flips; its own classification stays authoritative.\n if (typeof theme === 'string') {\n const pinnedThemeType = this.#highlighter.getTheme(theme).type;\n if (theme === this.#themeName && pinnedThemeType === this.#themeType) {\n return;\n }\n this.#emitThemeChange(theme, pinnedThemeType);\n return;\n }\n const nextThemeType =\n themeType === 'system' ? this.#resolveSystemThemeType() : themeType;\n const nextThemeName = 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, themeType?: 'light' | 'dark') {\n const { theme, colorMap } = this.#highlighter.setTheme(themeName);\n const { colors = {} } = this.#highlighter.getTheme(themeName);\n const selectionBackground = colors['editor.selectionBackground'];\n const themeLineHighlightBackground =\n colors['editor.lineHighlightBackground'];\n const lineHighlightBackground =\n themeLineHighlightBackground != null &&\n themeLineHighlightBackground.trim() !== '' &&\n !colorUtils.isFullyTransparent(themeLineHighlightBackground)\n ? themeLineHighlightBackground\n : undefined;\n // A usable theme background opts into the semantic active-line mix.\n // Missing backgrounds retain the resolved row color and rely on a border.\n const lineHighlightBorder =\n colors['editor.lineHighlightBorder'] ??\n (lineHighlightBackground == null\n ? 'color-mix(in lab, var(--diffs-bg) 70%, var(--diffs-fg))'\n : 'transparent');\n const activeLineSourceMix =\n lineHighlightBackground == null ? '100%' : '85%';\n const cursorForeground = colors['editorCursor.foreground'];\n const findMatchBackground = colors['editor.findMatchBackground'];\n const findMatchHighlightBackground =\n colors['editor.findMatchHighlightBackground'];\n const bracketMatchBackground = colors['editorBracketMatch.background'];\n const bracketMatchBorder = colors['editorBracketMatch.border'];\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-border: ${lineHighlightBorder};\n --diffs-editor-active-line-source-mix: ${activeLineSourceMix};\n --diffs-editor-match-bg: ${findMatchBackground ?? 'initial'};\n --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? 'initial'};\n --diffs-editor-bracket-match-bg: ${bracketMatchBackground ?? 'initial'};\n --diffs-editor-bracket-match-border: ${bracketMatchBorder ?? 'initial'};\n --diffs-editor-cursor-fg: ${cursorForeground ?? 'initial'};\n --diffs-editor-hint-fg: ${hintForeground ?? 'initial'};\n --diffs-editor-info-fg: ${infoForeground ?? 'initial'};\n --diffs-editor-warning-fg: ${warningForeground ?? 'initial'};\n --diffs-editor-error-fg: ${errorForeground ?? 'initial'};\n }`);\n this.#themeName = themeName;\n this.#themeType = themeType ?? theme.type;\n this.#colorMap = colorMap;\n }\n\n // The shared highlighter is also used for dual-theme SSR (`themes: {dark,light}`),\n // which leaves its active theme on whichever pass finished last (usually light).\n // The tokenizer caches a single-theme colorMap from construction; if we tokenize\n // without re-activating that theme, grammar color indices are looked up in the\n // wrong map — property names resolve to a near-foreground gray while types and\n // comments (stable across maps) still look correct. Re-apply before every\n // tokenize path so a first edit after load matches a later file-switch re-attach.\n #ensureActiveTheme(): void {\n if (this.#themeName === '') {\n return;\n }\n const { colorMap } = this.#highlighter.setTheme(this.#themeName);\n this.#colorMap = colorMap;\n }\n\n cleanUp(): void {\n this.#isCleanedUp = true;\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 hostRealignsRows = false\n ): Map<number, Array<HighlightedToken>> {\n this.#ensureGrammar();\n this.#ensureActiveTheme();\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 =\n change.lineDelta === 0 &&\n (change.changedLineChanges?.every(([, , lineDelta]) => lineDelta === 0) ??\n true);\n if (this.#matchBrackets && !canReuseCachedStates) {\n // Structural edits shift cache indexes, so only the untouched prefix is\n // safe. Same-line edits overwrite every range they re-tokenize and can\n // retain the untouched suffix once grammar state reconverges.\n this.#bracketIgnoredRanges.length = Math.min(\n this.#bracketIgnoredRanges.length,\n change.startLine\n );\n }\n const canReuseShiftedStates =\n hostRealignsRows && change.lineDelta !== 0 && dirtyStart >= startingLine;\n const canCacheTokenizedStates =\n canReuseCachedStates ||\n renderRange === undefined ||\n dirtyStart >= viewStart;\n const changedLineRanges: readonly [number, number][] =\n change.changedLineRanges ?? [[dirtyStart, change.endLine]];\n this.#comparisonStateStack = [];\n this.#comparisonStateStackStart = 0;\n this.#comparisonLineChanges = [];\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.#shiftComparisonStateStack(change);\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 this.#stateStack[offscreenEnd] = offscreenState;\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 : canReuseShiftedStates\n ? this.#getPreviousEndState(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 || canReuseShiftedStates) &&\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 let nextState: StateStack | undefined = this.#stateStack[nextRange[0]];\n if (canReuseShiftedStates) {\n for (\n let stateLine = line + 2;\n stateLine <= nextRange[0];\n stateLine++\n ) {\n nextState = this.#getPreviousEndState(stateLine);\n if (nextState === undefined) {\n break;\n }\n this.#stateStack[stateLine] = nextState;\n }\n }\n if (nextState === undefined) {\n currentChangedRangeEnd = nextRange[1];\n line++;\n } else {\n line = nextRange[0];\n state = nextState;\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 (settled && canReuseShiftedStates && backgroundStartLine === undefined) {\n for (let stateLine = line + 2; stateLine <= lineCount; stateLine++) {\n const previousState = this.#getPreviousEndState(stateLine);\n if (previousState === undefined) {\n break;\n }\n this.#stateStack[stateLine] = previousState;\n }\n this.#comparisonStateStack = [];\n this.#comparisonStateStackStart = 0;\n this.#comparisonLineChanges = [];\n }\n\n if (offscreenDirtyLines !== undefined && offscreenDirtyLines.size > 0) {\n this.#onDeferTokenize(offscreenDirtyLines, this.#themeType);\n }\n\n if (backgroundStartLine !== undefined) {\n if (this.#matchBrackets && canReuseCachedStates) {\n this.#bracketIgnoredRanges.length = Math.min(\n this.#bracketIgnoredRanges.length,\n backgroundStartLine\n );\n }\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 if (this.#matchBrackets && canReuseCachedStates) {\n this.#bracketIgnoredRanges.length = Math.min(\n this.#bracketIgnoredRanges.length,\n backgroundLine\n );\n }\n this.#scheduleBackgroundTokenize(\n backgroundLine,\n changedLineRanges,\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 stopBackgroundTokenize(): void {\n this.#pendingPrebuildEndLine = -1;\n if (this.#isStopped) {\n return;\n }\n this.#isStopped = true;\n this.#isPaused = false;\n this.#lastLine = -1;\n this.#backgroundPrebuildEndLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\n this.#comparisonStateStack = [];\n this.#comparisonStateStackStart = 0;\n this.#comparisonLineChanges = [];\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 #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 #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({\n type: 'tokenize',\n tokenizerId: this.#tokenizerId,\n jobId,\n });\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 if (this.#backgroundPrebuildEndLine >= 0) {\n this.#pendingPrebuildEndLine = Math.max(\n this.#pendingPrebuildEndLine,\n this.#backgroundPrebuildEndLine\n );\n }\n this.#backgroundPrebuildEndLine = -1;\n this.#backgroundChangedLineRanges = changedLineRanges;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#attachMessageListener();\n this.#postTokenizeMessage(jobId);\n }\n\n #scheduleStatePrebuild(endLine: number): void {\n if (this.#grammar === undefined || this.#stateStack.length > endLine) {\n return;\n }\n // Extend an active prebuild, or retain the target until the foreground\n // edit job reconverges and releases the state cache.\n if (!this.#isStopped) {\n if (this.#backgroundPrebuildEndLine >= 0) {\n this.#backgroundPrebuildEndLine = Math.max(\n this.#backgroundPrebuildEndLine,\n endLine\n );\n } else {\n this.#pendingPrebuildEndLine = Math.max(\n this.#pendingPrebuildEndLine,\n endLine\n );\n }\n return;\n }\n\n const jobId = ++this.#backgroundJobId;\n this.#isStopped = false;\n this.#isPaused = false;\n this.#lastLine = this.#stateStack.length - 1;\n this.#backgroundPrebuildEndLine = endLine;\n this.#pendingPrebuildEndLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\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 this.#cacheBracketIgnoredRanges(line, null);\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n if (\n this.#grammar === undefined ||\n lineText === '' ||\n lineText.trim() === ''\n ) {\n this.#cacheBracketIgnoredRanges(line, null);\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n TOKENIZE_TIME_LIMIT,\n this.#matchBrackets\n );\n this.#cacheBracketIgnoredRanges(line, result.bracketIgnoredRanges);\n return {\n resolvedTokens: result.resolvedTokens,\n state: result.ruleStack,\n };\n }\n\n #cacheBracketIgnoredRanges(\n line: number,\n ranges: [number, number][] | null\n ): void {\n if (this.#matchBrackets) {\n this.#bracketIgnoredRanges[line] = ranges;\n }\n }\n\n // Preserve old end states as comparison-only sentinels, copying whichever\n // side of the edit is smaller. Index shifts are resolved lazily on lookup.\n #shiftComparisonStateStack(change: TextDocumentChange): void {\n const lineChanges =\n change.changedLineChanges ??\n ([[change.startLine, change.endLine, change.lineDelta]] as const);\n const comparisonStart = change.startLine + 1;\n const comparisonLength = this.#stateStack.length - comparisonStart;\n if (comparisonStart <= comparisonLength) {\n this.#comparisonStateStack = this.#stateStack;\n this.#comparisonStateStackStart = 0;\n this.#stateStack = this.#stateStack.slice(0, comparisonStart);\n } else {\n this.#comparisonStateStackStart = comparisonStart;\n this.#comparisonStateStack = this.#stateStack.slice(comparisonStart);\n this.#stateStack.length = Math.min(\n this.#stateStack.length,\n comparisonStart\n );\n }\n this.#comparisonLineChanges = lineChanges;\n }\n\n #getPreviousEndState(line: number): StateStack | undefined {\n let previousLine = line;\n for (\n let index = this.#comparisonLineChanges.length - 1;\n index >= 0;\n index--\n ) {\n const [startLine, endLine, lineDelta] =\n this.#comparisonLineChanges[index];\n if (lineDelta === 0) {\n continue;\n }\n if (previousLine > endLine) {\n previousLine -= lineDelta;\n } else if (previousLine > startLine) {\n return this.#stateStack[line];\n }\n }\n return (\n this.#comparisonStateStack[\n previousLine - this.#comparisonStateStackStart\n ] ?? this.#stateStack[line]\n );\n }\n\n #buildStateStack(endAt: number, timeBudget?: number): boolean {\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 true;\n }\n const startedAt = timeBudget === undefined ? 0 : performance.now();\n let line = this.#stateStack.length - 1;\n let state = this.#stateStack[line] ?? INITIAL;\n while (line < boundedEndAt) {\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 const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n TOKENIZE_TIME_LIMIT,\n this.#matchBrackets,\n false\n );\n this.#cacheBracketIgnoredRanges(line, result.bracketIgnoredRanges);\n state = result.ruleStack;\n } else {\n this.#cacheBracketIgnoredRanges(line, null);\n }\n line++;\n this.#stateStack[line] = state;\n if (\n timeBudget !== undefined &&\n performance.now() - startedAt > timeBudget\n ) {\n break;\n }\n }\n return line >= boundedEndAt;\n }\n\n #backgroundPrebuild(jobId: number): void {\n if (\n this.#isStopped ||\n this.#isPaused ||\n this.#grammar === undefined ||\n jobId !== this.#backgroundJobId\n ) {\n return;\n }\n\n this.#ensureActiveTheme();\n // State prebuilds intentionally omit rendered tokens and yield between\n // short chunks so a deep viewport does not monopolize the main thread.\n const complete = this.#buildStateStack(this.#backgroundPrebuildEndLine, 1);\n if (this.#isStopped || this.#isPaused || jobId !== this.#backgroundJobId) {\n return;\n }\n if (complete) {\n this.stopBackgroundTokenize();\n return;\n }\n this.#lastLine = this.#stateStack.length - 1;\n this.#postTokenizeMessage(jobId);\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 this.#ensureActiveTheme();\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.#getPreviousEndState(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 this.#cacheBracketIgnoredRanges(line, null);\n } else if (lineText === '' || lineText.trim() === '') {\n lines.set(line, [[0, '', lineText]]);\n this.#cacheBracketIgnoredRanges(line, null);\n } else {\n const ret = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n TOKENIZE_TIME_LIMIT,\n this.#matchBrackets\n );\n lines.set(line, ret.resolvedTokens);\n this.#cacheBracketIgnoredRanges(line, ret.bracketIgnoredRanges);\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 const pendingPrebuildEndLine = this.#pendingPrebuildEndLine;\n this.stopBackgroundTokenize();\n if (pendingPrebuildEndLine >= 0) {\n this.#scheduleStatePrebuild(pendingPrebuildEndLine);\n }\n return;\n }\n\n this.#lastLine = line;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#postTokenizeMessage(jobId);\n }\n}\n\nfunction tokenizeLine(\n grammar: IGrammar,\n colorMap: string[],\n lineText: string,\n stateStack: StateStack,\n timeLimit?: number,\n collectBracketIgnoredRanges = true,\n resolveTokens = true\n): {\n ruleStack: StateStack;\n resolvedTokens: Array<HighlightedToken>;\n bracketIgnoredRanges: [number, number][];\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 const bracketIgnoredRanges: [number, number][] = [];\n if (!resolveTokens && !collectBracketIgnoredRanges) {\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n bracketIgnoredRanges,\n };\n }\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 if (resolveTokens) {\n const fg = EncodedTokenMetadata.getForeground(metadata);\n resolvedTokens.push([\n offset,\n colorMap[fg],\n lineText.slice(offset, nextOffset),\n ]);\n }\n if (\n collectBracketIgnoredRanges &&\n EncodedTokenMetadata.getTokenType(metadata) > 0\n ) {\n bracketIgnoredRanges.push([offset, nextOffset]);\n }\n }\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n bracketIgnoredRanges,\n };\n}\n\nexport function renderLineTokens(\n tokens: Array<HighlightedToken>\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: `color:${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":"tokenizer.js","names":[],"sources":["../../src/editor/tokenizer.ts"],"sourcesContent":["import { colorUtils } from '@pierre/theming/color';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport type { DiffsEditorTokenizer } from '../highlighter/DiffsEditorTokenizer';\nimport type {\n BaseCodeOptions,\n DiffsHighlighter,\n HighlightedToken,\n RenderRange,\n} from '../types';\nimport type { TextDocument, TextDocumentChange } from './textDocument';\nimport { addEventListener, h } from './utils';\n\nexport interface EditorTokenizerProps {\n highlighter: DiffsHighlighter;\n textDocument: TextDocument;\n codeOptions: BaseCodeOptions;\n matchBrackets?: boolean;\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/** Applies editor theme CSS and delegates tokenization to the selected backend. */\nexport class EditorTokenizer {\n #highlighter: DiffsHighlighter;\n #tokenizer: DiffsEditorTokenizer;\n #mediaQueryList: MediaQueryList;\n #themeType: 'light' | 'dark' = 'dark';\n #themeName = '';\n #setStyle: EditorTokenizerProps['setStyle'];\n #onThemeChange: EditorTokenizerProps['onThemeChange'];\n #disposes?: (() => void)[];\n\n get themeType(): 'light' | 'dark' {\n return this.#themeType;\n }\n\n get highlighter(): DiffsHighlighter {\n return this.#highlighter;\n }\n\n constructor({\n codeOptions,\n highlighter,\n textDocument,\n matchBrackets,\n setStyle,\n onDeferTokenize,\n onThemeChange,\n __debug,\n }: EditorTokenizerProps) {\n const {\n themeType: themeTypeOption = 'system',\n theme = DEFAULT_THEMES,\n tokenizeMaxLineLength = 1000,\n } = codeOptions;\n this.#mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');\n let themeType: 'light' | 'dark' | undefined;\n if (themeTypeOption === 'system') {\n // Prefer the host document's computed color-scheme (page CSS/classes can\n // force light/dark while the OS media query differs) over matchMedia.\n themeType = this.#resolveSystemThemeType();\n } else {\n themeType = themeTypeOption;\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' && themeTypeOption === '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 = this.#resolveSystemThemeType();\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', () => {\n // Re-read computed color-scheme so a host-forced scheme still wins\n // when the OS preference changes underneath it.\n const themeType = this.#resolveSystemThemeType();\n this.#emitThemeChange(theme[themeType], themeType);\n }),\n () => observer.disconnect(),\n ];\n }\n this.#highlighter = highlighter;\n this.#setStyle = setStyle;\n this.#onThemeChange = onThemeChange;\n this.#setTheme(\n typeof theme === 'string' ? theme : theme[themeType],\n typeof theme === 'string' ? undefined : themeType\n );\n this.#tokenizer = highlighter.createEditorTokenizer({\n textDocument,\n theme: this.#themeName,\n tokenizeMaxLineLength,\n matchBrackets,\n __debug,\n onDeferTokenize: (lines) => onDeferTokenize(lines, this.#themeType),\n });\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 if (themeName === this.#themeName && themeType === this.#themeType) {\n return;\n }\n this.#setTheme(themeName, themeType);\n this.#tokenizer.setTheme(themeName);\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 // Respect an explicit host color-scheme override. When the computed value\n // advertises support for both schemes, let the OS preference choose one.\n #resolveSystemThemeType(): 'light' | 'dark' {\n try {\n if (\n typeof document !== 'undefined' &&\n typeof getComputedStyle === 'function' &&\n document.body != null\n ) {\n const colorSchemes = getComputedStyle(document.body).colorScheme.split(\n /\\s+/\n );\n const supportsDark = colorSchemes.includes('dark');\n const supportsLight = colorSchemes.includes('light');\n // A single host-forced scheme wins. `light dark` only declares support\n // for both schemes, so the media query still selects the active one.\n if (supportsDark !== supportsLight) {\n return supportsDark ? 'dark' : 'light';\n }\n }\n } catch {\n // jsdom and similar harnesses may lack getComputedStyle or throw; fall\n // through to the OS media query.\n }\n return this.#mediaQueryList.matches ? 'dark' : 'light';\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 // A single pinned theme does not follow the themeType option or system\n // scheme flips; its own classification stays authoritative.\n if (typeof theme === 'string') {\n const pinnedThemeType = this.#highlighter.getTheme(theme).type;\n if (theme === this.#themeName && pinnedThemeType === this.#themeType) {\n return;\n }\n this.#emitThemeChange(theme, pinnedThemeType);\n return;\n }\n const nextThemeType =\n themeType === 'system' ? this.#resolveSystemThemeType() : themeType;\n const nextThemeName = 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, themeType?: 'light' | 'dark') {\n const theme = this.#highlighter.getTheme(themeName);\n const { colors = {} } = theme;\n const selectionBackground = colors['editor.selectionBackground'];\n const themeLineHighlightBackground =\n colors['editor.lineHighlightBackground'];\n const lineHighlightBackground =\n themeLineHighlightBackground != null &&\n themeLineHighlightBackground.trim() !== '' &&\n !colorUtils.isFullyTransparent(themeLineHighlightBackground)\n ? themeLineHighlightBackground\n : undefined;\n // A usable theme background opts into the semantic active-line mix.\n // Missing backgrounds retain the resolved row color and rely on a border.\n const lineHighlightBorder =\n colors['editor.lineHighlightBorder'] ??\n (lineHighlightBackground == null\n ? 'color-mix(in lab, var(--diffs-bg) 70%, var(--diffs-fg))'\n : 'transparent');\n const activeLineSourceMix =\n lineHighlightBackground == null ? '100%' : '85%';\n const cursorForeground = colors['editorCursor.foreground'];\n const findMatchBackground = colors['editor.findMatchBackground'];\n const findMatchHighlightBackground =\n colors['editor.findMatchHighlightBackground'];\n const bracketMatchBackground = colors['editorBracketMatch.background'];\n const bracketMatchBorder = colors['editorBracketMatch.border'];\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-border: ${lineHighlightBorder};\n --diffs-editor-active-line-source-mix: ${activeLineSourceMix};\n --diffs-editor-match-bg: ${findMatchBackground ?? 'initial'};\n --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? 'initial'};\n --diffs-editor-bracket-match-bg: ${bracketMatchBackground ?? 'initial'};\n --diffs-editor-bracket-match-border: ${bracketMatchBorder ?? 'initial'};\n --diffs-editor-cursor-fg: ${cursorForeground ?? 'initial'};\n --diffs-editor-hint-fg: ${hintForeground ?? 'initial'};\n --diffs-editor-info-fg: ${infoForeground ?? 'initial'};\n --diffs-editor-warning-fg: ${warningForeground ?? 'initial'};\n --diffs-editor-error-fg: ${errorForeground ?? 'initial'};\n }`);\n this.#themeName = themeName;\n this.#themeType = themeType ?? theme.type;\n }\n\n cleanUp(): void {\n this.#tokenizer.dispose();\n this.#disposes?.forEach((dispose) => dispose());\n this.#disposes = undefined;\n }\n\n tokenize(\n change: TextDocumentChange,\n renderRange?: RenderRange,\n hostRealignsRows = false\n ): Map<number, HighlightedToken[]> {\n return this.#tokenizer.tokenize(change, renderRange, hostRealignsRows);\n }\n\n getStringCommentRegexpRangesInLine(\n lineIndex: number\n ): [number, number][] | null {\n return this.#tokenizer.getStringCommentRegexpRangesInLine(lineIndex);\n }\n\n prebuildStateStack(renderRange?: RenderRange): void {\n this.#tokenizer.prebuildStateStack(renderRange);\n }\n\n stopBackgroundTokenize(): void {\n this.#tokenizer.stopBackgroundTokenize();\n }\n pauseBackgroundTokenize(): void {\n this.#tokenizer.pauseBackgroundTokenize();\n }\n resumeBackgroundTokenize(): void {\n this.#tokenizer.resumeBackgroundTokenize();\n }\n}\n\nexport function renderLineTokens(\n tokens: Array<HighlightedToken>\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: `color:${fg};`,\n textContent: textContent,\n });\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { HighlightedToken, RenderRange } from "../types.js";
2
+ import { TextDocumentChange } from "../editor/textDocument.js";
3
+ //#region src/highlighter/DiffsEditorTokenizer.d.ts
4
+ interface DiffsEditorTokenizer {
5
+ tokenize(change: TextDocumentChange, renderRange?: RenderRange, hostRealignsRows?: boolean): Map<number, HighlightedToken[]>;
6
+ prebuildStateStack(renderRange?: RenderRange): void;
7
+ getStringCommentRegexpRangesInLine(lineIndex: number): [number, number][] | null;
8
+ setTheme(themeName: string): void;
9
+ stopBackgroundTokenize(): void;
10
+ pauseBackgroundTokenize(): void;
11
+ resumeBackgroundTokenize(): void;
12
+ dispose(): void;
13
+ }
14
+ //#endregion
15
+ export { DiffsEditorTokenizer };
16
+ //# sourceMappingURL=DiffsEditorTokenizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DiffsEditorTokenizer.d.ts","names":[],"sources":["../../src/highlighter/DiffsEditorTokenizer.ts"],"mappings":";;;UAGiB;EACf,SACE,QAAQ,oBACR,cAAc,aACd,6BACC,YAAY;EAEf,mBAAmB,cAAc;EAEjC,mCACE;EAGF,SAAS;EAET;EAEA;EAEA;EAEA"}
File without changes
@@ -0,0 +1,41 @@
1
+ import { DiffsTheme } from "./themes/types.js";
2
+ import { DiffsEditorTokenizer } from "./DiffsEditorTokenizer.js";
3
+ import { ResolvedLanguage } from "../worker/types.js";
4
+ import { DiffsEditorTokenizerOptions, DiffsStreamTokenizer } from "./tokenizer-types.js";
5
+ import { CodeToHtmlOptions, CodeToTokensOptions, TokensResult } from "./types.js";
6
+ import { HighlighterTypes } from "../types.js";
7
+ import { ThemeResolver } from "@pierre/theming";
8
+ //#region src/highlighter/DiffsHighlighter.d.ts
9
+ /**
10
+ * A different highlighter type cannot load in this thread until every
11
+ * instance of the current type is disposed.
12
+ */
13
+ declare abstract class DiffsHighlighter {
14
+ readonly name: HighlighterTypes;
15
+ readonly themeResolver: ThemeResolver<DiffsTheme>;
16
+ protected disposed: boolean;
17
+ constructor(name: HighlighterTypes, themeResolver: ThemeResolver<DiffsTheme>);
18
+ /**
19
+ * Previously used themes remain available after the shared cache is cleared.
20
+ */
21
+ abstract getTheme(name: string): DiffsTheme;
22
+ abstract codeToTokens(code: string, options: CodeToTokensOptions): TokensResult;
23
+ codeToHtml(code: string, options: CodeToHtmlOptions): string;
24
+ abstract createStreamTokenizer(options: CodeToTokensOptions): DiffsStreamTokenizer;
25
+ abstract createEditorTokenizer(options: DiffsEditorTokenizerOptions): DiffsEditorTokenizer;
26
+ /** Backends with bundled lexers resolve immediately. */
27
+ abstract loadLanguages(languages: readonly string[]): Promise<void>;
28
+ abstract hasLoadedLanguages(languages: readonly string[]): boolean;
29
+ /** Attach grammars resolved elsewhere, such as on the main thread for a worker. */
30
+ abstract attachLanguages(languages: readonly ResolvedLanguage[]): void;
31
+ get isDisposed(): boolean;
32
+ /**
33
+ * Disposed instances cannot be reused.
34
+ */
35
+ dispose(): void;
36
+ protected abstract releaseResources(): void;
37
+ protected assertNotDisposed(): void;
38
+ }
39
+ //#endregion
40
+ export { DiffsHighlighter };
41
+ //# sourceMappingURL=DiffsHighlighter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DiffsHighlighter.d.ts","names":[],"sources":["../../src/highlighter/DiffsHighlighter.ts"],"mappings":";;;;;;;;;;;;uBA0BsB;WAIT,MAAM;WACN,eAAe,cAAc;YAJ9B;EAEV,YACW,MAAM,kBACN,eAAe,cAAc;;;;WAQ/B,SAAS,eAAe;WAExB,aACP,cACA,SAAS,sBACR;EAEH,WAAW,cAAc,SAAS;WASzB,sBACP,SAAS,sBACR;WAEM,sBACP,SAAS,8BACR;;WAGM,cAAc,+BAA+B;WAE7C,mBAAmB;;WAGnB,gBAAgB,oBAAoB;MAEzC;;;;EAOJ;qBASmB;YAET"}
@@ -0,0 +1,39 @@
1
+ import { HighlighterDisposedError, acquireHighlighterType, releaseHighlighterType } from "./highlighterType.js";
2
+ import { tokensToHtml } from "../utils/tokensToHtml.js";
3
+ //#region src/highlighter/DiffsHighlighter.ts
4
+ /**
5
+ * A different highlighter type cannot load in this thread until every
6
+ * instance of the current type is disposed.
7
+ */
8
+ var DiffsHighlighter = class {
9
+ name;
10
+ themeResolver;
11
+ disposed = false;
12
+ constructor(name, themeResolver) {
13
+ this.name = name;
14
+ this.themeResolver = themeResolver;
15
+ acquireHighlighterType(name);
16
+ }
17
+ codeToHtml(code, options) {
18
+ return tokensToHtml(code, this.codeToTokens(code, options), options, this.name === "highlights");
19
+ }
20
+ get isDisposed() {
21
+ return this.disposed;
22
+ }
23
+ /**
24
+ * Disposed instances cannot be reused.
25
+ */
26
+ dispose() {
27
+ if (this.disposed) return;
28
+ this.disposed = true;
29
+ this.releaseResources();
30
+ releaseHighlighterType();
31
+ }
32
+ assertNotDisposed() {
33
+ if (this.disposed) throw new HighlighterDisposedError();
34
+ }
35
+ };
36
+ //#endregion
37
+ export { DiffsHighlighter };
38
+
39
+ //# sourceMappingURL=DiffsHighlighter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DiffsHighlighter.js","names":[],"sources":["../../src/highlighter/DiffsHighlighter.ts"],"sourcesContent":["import type { ThemeResolver } from '@pierre/theming';\n\nimport type { HighlighterTypes } from '../types';\nimport { tokensToHtml } from '../utils/tokensToHtml';\nimport type { ResolvedLanguage } from '../worker/types';\nimport type { DiffsEditorTokenizer } from './DiffsEditorTokenizer';\nimport {\n acquireHighlighterType,\n HighlighterDisposedError,\n releaseHighlighterType,\n} from './highlighterType';\nimport type { DiffsTheme } from './themes/types';\nimport type {\n DiffsEditorTokenizerOptions,\n DiffsStreamTokenizer,\n} from './tokenizer-types';\nimport type {\n CodeToHtmlOptions,\n CodeToTokensOptions,\n TokensResult,\n} from './types';\n\n/**\n * A different highlighter type cannot load in this thread until every\n * instance of the current type is disposed.\n */\nexport abstract class DiffsHighlighter {\n protected disposed = false;\n\n constructor(\n readonly name: HighlighterTypes,\n readonly themeResolver: ThemeResolver<DiffsTheme>\n ) {\n acquireHighlighterType(name);\n }\n\n /**\n * Previously used themes remain available after the shared cache is cleared.\n */\n abstract getTheme(name: string): DiffsTheme;\n\n abstract codeToTokens(\n code: string,\n options: CodeToTokensOptions\n ): TokensResult;\n\n codeToHtml(code: string, options: CodeToHtmlOptions): string {\n return tokensToHtml(\n code,\n this.codeToTokens(code, options),\n options,\n this.name === 'highlights'\n );\n }\n\n abstract createStreamTokenizer(\n options: CodeToTokensOptions\n ): DiffsStreamTokenizer;\n\n abstract createEditorTokenizer(\n options: DiffsEditorTokenizerOptions\n ): DiffsEditorTokenizer;\n\n /** Backends with bundled lexers resolve immediately. */\n abstract loadLanguages(languages: readonly string[]): Promise<void>;\n\n abstract hasLoadedLanguages(languages: readonly string[]): boolean;\n\n /** Attach grammars resolved elsewhere, such as on the main thread for a worker. */\n abstract attachLanguages(languages: readonly ResolvedLanguage[]): void;\n\n get isDisposed(): boolean {\n return this.disposed;\n }\n\n /**\n * Disposed instances cannot be reused.\n */\n dispose(): void {\n if (this.disposed) {\n return;\n }\n this.disposed = true;\n this.releaseResources();\n releaseHighlighterType();\n }\n\n protected abstract releaseResources(): void;\n\n protected assertNotDisposed(): void {\n if (this.disposed) {\n throw new HighlighterDisposedError();\n }\n }\n}\n"],"mappings":";;;;;;;AA0BA,IAAsB,mBAAtB,MAAuC;CAI1B;CACA;CAJX,WAAqB;CAErB,YACE,MACA,eACA;EAFS,KAAA,OAAA;EACA,KAAA,gBAAA;EAET,uBAAuB,IAAI;CAC7B;CAYA,WAAW,MAAc,SAAoC;EAC3D,OAAO,aACL,MACA,KAAK,aAAa,MAAM,OAAO,GAC/B,SACA,KAAK,SAAS,YAChB;CACF;CAkBA,IAAI,aAAsB;EACxB,OAAO,KAAK;CACd;;;;CAKA,UAAgB;EACd,IAAI,KAAK,UACP;EAEF,KAAK,WAAW;EAChB,KAAK,iBAAiB;EACtB,uBAAuB;CACzB;CAIA,oBAAoC;EAClC,IAAI,KAAK,UACP,MAAM,IAAI,yBAAyB;CAEvC;AACF"}
@@ -0,0 +1,26 @@
1
+ import { DiffsTheme } from "../themes/types.js";
2
+ import { DiffsEditorTokenizerOptions, DiffsStreamTokenizer } from "../tokenizer-types.js";
3
+ import { DiffsHighlighter } from "../DiffsHighlighter.js";
4
+ import { CodeToTokensOptions, TokensResult } from "../types.js";
5
+ import { HighlightsEditorTokenizer } from "../highlights-editor.js";
6
+ //#region src/highlighter/backends/highlights.d.ts
7
+ /**
8
+ * Highlights uses bundled lexers. Unsupported and custom languages render as text.
9
+ */
10
+ declare class HighlightsHighlighter extends DiffsHighlighter {
11
+ private readonly usedThemes;
12
+ constructor();
13
+ getTheme(name: string): DiffsTheme;
14
+ codeToTokens(code: string, options: CodeToTokensOptions): TokensResult;
15
+ createEditorTokenizer(options: DiffsEditorTokenizerOptions): HighlightsEditorTokenizer;
16
+ createStreamTokenizer(options: CodeToTokensOptions): DiffsStreamTokenizer;
17
+ loadLanguages(): Promise<void>;
18
+ hasLoadedLanguages(): boolean;
19
+ attachLanguages(): void;
20
+ protected releaseResources(): void;
21
+ private resolveOptions;
22
+ private getZedTheme;
23
+ }
24
+ //#endregion
25
+ export { HighlightsHighlighter };
26
+ //# sourceMappingURL=highlights.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlights.d.ts","names":[],"sources":["../../../src/highlighter/backends/highlights.ts"],"mappings":";;;;;;;;;cAqBa,8BAA8B;mBAExB;EAEjB;EAIA,SAAS,eAAe;EAWxB,aAAa,cAAc,SAAS,sBAAsB;EAO1D,sBACE,SAAS,8BACR;EAOH,sBAAsB,SAAS,sBAAsB;EAIrD,iBAAiB;EAKjB;EAIA;YAIU;UAKF;UAmBA"}
@@ -0,0 +1,71 @@
1
+ import { createDiffsThemeResolver } from "../themes/themeResolver.js";
2
+ import { DiffsHighlighter } from "../DiffsHighlighter.js";
3
+ import { HighlightsEditorTokenizer } from "../highlights-editor.js";
4
+ import { HighlightsStreamTokenizer } from "../highlights-stream.js";
5
+ import { codeToTokens, isSupportedLanguage } from "@pierre/highlights";
6
+ //#region src/highlighter/backends/highlights.ts
7
+ /**
8
+ * Highlights uses bundled lexers. Unsupported and custom languages render as text.
9
+ */
10
+ var HighlightsHighlighter = class extends DiffsHighlighter {
11
+ usedThemes = /* @__PURE__ */ new Map();
12
+ constructor() {
13
+ super("highlights", createDiffsThemeResolver("highlights"));
14
+ }
15
+ getTheme(name) {
16
+ this.assertNotDisposed();
17
+ const theme = this.themeResolver.getResolvedTheme(name) ?? this.usedThemes.get(name);
18
+ if (theme == null) throw new Error(`Theme "${name}" has not been resolved`);
19
+ this.usedThemes.set(name, theme);
20
+ return theme;
21
+ }
22
+ codeToTokens(code, options) {
23
+ this.assertNotDisposed();
24
+ return codeToTokens(code, this.resolveOptions(options));
25
+ }
26
+ createEditorTokenizer(options) {
27
+ this.assertNotDisposed();
28
+ return new HighlightsEditorTokenizer(options, (tokenizerOptions) => this.resolveOptions(tokenizerOptions));
29
+ }
30
+ createStreamTokenizer(options) {
31
+ return new HighlightsStreamTokenizer(this.resolveOptions(options));
32
+ }
33
+ loadLanguages() {
34
+ this.assertNotDisposed();
35
+ return Promise.resolve();
36
+ }
37
+ hasLoadedLanguages() {
38
+ return !this.disposed;
39
+ }
40
+ attachLanguages() {
41
+ this.assertNotDisposed();
42
+ }
43
+ releaseResources() {
44
+ this.usedThemes.clear();
45
+ }
46
+ resolveOptions({ theme, themes, ...options }) {
47
+ const lang = isSupportedLanguage(options.lang) ? options.lang : "text";
48
+ if (theme != null) return {
49
+ ...options,
50
+ lang,
51
+ theme: this.getZedTheme(theme)
52
+ };
53
+ if (themes == null) throw new Error("A theme or themes option is required");
54
+ const resolved = {};
55
+ for (const [key, name] of Object.entries(themes)) resolved[key] = this.getZedTheme(name);
56
+ return {
57
+ ...options,
58
+ lang,
59
+ themes: resolved
60
+ };
61
+ }
62
+ getZedTheme(name) {
63
+ const theme = this.getTheme(name);
64
+ if (theme.zed == null) throw new Error(`Theme "${name}" does not support Highlights`);
65
+ return theme.zed;
66
+ }
67
+ };
68
+ //#endregion
69
+ export { HighlightsHighlighter };
70
+
71
+ //# sourceMappingURL=highlights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlights.js","names":[],"sources":["../../../src/highlighter/backends/highlights.ts"],"sourcesContent":["import {\n codeToTokens,\n type CodeToTokensOptions as HighlightsOptions,\n isSupportedLanguage,\n type Theme,\n} from '@pierre/highlights';\n\nimport { DiffsHighlighter } from '../DiffsHighlighter';\nimport { HighlightsEditorTokenizer } from '../highlights-editor';\nimport { HighlightsStreamTokenizer } from '../highlights-stream';\nimport { createDiffsThemeResolver } from '../themes/themeResolver';\nimport type { DiffsTheme } from '../themes/types';\nimport type {\n DiffsEditorTokenizerOptions,\n DiffsStreamTokenizer,\n} from '../tokenizer-types';\nimport type { CodeToTokensOptions, TokensResult } from '../types';\n\n/**\n * Highlights uses bundled lexers. Unsupported and custom languages render as text.\n */\nexport class HighlightsHighlighter extends DiffsHighlighter {\n // Independent instances need their themes after the shared cache is cleared.\n private readonly usedThemes = new Map<string, DiffsTheme>();\n\n constructor() {\n super('highlights', createDiffsThemeResolver('highlights'));\n }\n\n getTheme(name: string): DiffsTheme {\n this.assertNotDisposed();\n const theme =\n this.themeResolver.getResolvedTheme(name) ?? this.usedThemes.get(name);\n if (theme == null) {\n throw new Error(`Theme \"${name}\" has not been resolved`);\n }\n this.usedThemes.set(name, theme);\n return theme;\n }\n\n codeToTokens(code: string, options: CodeToTokensOptions): TokensResult {\n this.assertNotDisposed();\n // Warning: use the library's shared Wasm instance. It replaces instances\n // above 8 MiB; a private instance keeps its peak memory.\n return codeToTokens(code, this.resolveOptions(options));\n }\n\n createEditorTokenizer(\n options: DiffsEditorTokenizerOptions\n ): HighlightsEditorTokenizer {\n this.assertNotDisposed();\n return new HighlightsEditorTokenizer(options, (tokenizerOptions) =>\n this.resolveOptions(tokenizerOptions)\n );\n }\n\n createStreamTokenizer(options: CodeToTokensOptions): DiffsStreamTokenizer {\n return new HighlightsStreamTokenizer(this.resolveOptions(options));\n }\n\n loadLanguages(): Promise<void> {\n this.assertNotDisposed();\n return Promise.resolve();\n }\n\n hasLoadedLanguages(): boolean {\n return !this.disposed;\n }\n\n attachLanguages(): void {\n this.assertNotDisposed();\n }\n\n protected releaseResources(): void {\n this.usedThemes.clear();\n }\n\n // Omit the unused theme key; callers may pass both keys with one undefined.\n private resolveOptions({\n theme,\n themes,\n ...options\n }: CodeToTokensOptions): HighlightsOptions {\n const lang = isSupportedLanguage(options.lang) ? options.lang : 'text';\n if (theme != null) {\n return { ...options, lang, theme: this.getZedTheme(theme) };\n }\n if (themes == null) {\n throw new Error('A theme or themes option is required');\n }\n const resolved: Record<string, Theme> = {};\n for (const [key, name] of Object.entries(themes)) {\n resolved[key] = this.getZedTheme(name);\n }\n return { ...options, lang, themes: resolved };\n }\n\n private getZedTheme(name: string): Theme {\n const theme = this.getTheme(name);\n if (theme.zed == null) {\n throw new Error(`Theme \"${name}\" does not support Highlights`);\n }\n return theme.zed;\n }\n}\n"],"mappings":";;;;;;;;;AAqBA,IAAa,wBAAb,cAA2C,iBAAiB;CAE1D,6BAA8B,IAAI,IAAwB;CAE1D,cAAc;EACZ,MAAM,cAAc,yBAAyB,YAAY,CAAC;CAC5D;CAEA,SAAS,MAA0B;EACjC,KAAK,kBAAkB;EACvB,MAAM,QACJ,KAAK,cAAc,iBAAiB,IAAI,KAAK,KAAK,WAAW,IAAI,IAAI;EACvE,IAAI,SAAS,MACX,MAAM,IAAI,MAAM,UAAU,KAAK,wBAAwB;EAEzD,KAAK,WAAW,IAAI,MAAM,KAAK;EAC/B,OAAO;CACT;CAEA,aAAa,MAAc,SAA4C;EACrE,KAAK,kBAAkB;EAGvB,OAAO,aAAa,MAAM,KAAK,eAAe,OAAO,CAAC;CACxD;CAEA,sBACE,SAC2B;EAC3B,KAAK,kBAAkB;EACvB,OAAO,IAAI,0BAA0B,UAAU,qBAC7C,KAAK,eAAe,gBAAgB,CACtC;CACF;CAEA,sBAAsB,SAAoD;EACxE,OAAO,IAAI,0BAA0B,KAAK,eAAe,OAAO,CAAC;CACnE;CAEA,gBAA+B;EAC7B,KAAK,kBAAkB;EACvB,OAAO,QAAQ,QAAQ;CACzB;CAEA,qBAA8B;EAC5B,OAAO,CAAC,KAAK;CACf;CAEA,kBAAwB;EACtB,KAAK,kBAAkB;CACzB;CAEA,mBAAmC;EACjC,KAAK,WAAW,MAAM;CACxB;CAGA,eAAuB,EACrB,OACA,QACA,GAAG,WACsC;EACzC,MAAM,OAAO,oBAAoB,QAAQ,IAAI,IAAI,QAAQ,OAAO;EAChE,IAAI,SAAS,MACX,OAAO;GAAE,GAAG;GAAS;GAAM,OAAO,KAAK,YAAY,KAAK;EAAE;EAE5D,IAAI,UAAU,MACZ,MAAM,IAAI,MAAM,sCAAsC;EAExD,MAAM,WAAkC,CAAC;EACzC,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,MAAM,GAC7C,SAAS,OAAO,KAAK,YAAY,IAAI;EAEvC,OAAO;GAAE,GAAG;GAAS;GAAM,QAAQ;EAAS;CAC9C;CAEA,YAAoB,MAAqB;EACvC,MAAM,QAAQ,KAAK,SAAS,IAAI;EAChC,IAAI,MAAM,OAAO,MACf,MAAM,IAAI,MAAM,UAAU,KAAK,8BAA8B;EAE/D,OAAO,MAAM;CACf;AACF"}
@@ -0,0 +1,27 @@
1
+ import { DiffsTheme } from "../themes/types.js";
2
+ import { ResolvedLanguage } from "../../worker/types.js";
3
+ import { DiffsEditorTokenizerOptions, DiffsStreamTokenizer } from "../tokenizer-types.js";
4
+ import { DiffsHighlighter } from "../DiffsHighlighter.js";
5
+ import { CodeToTokensOptions, TokensResult } from "../types.js";
6
+ import { ShikiEditorTokenizer } from "../shiki-editor.js";
7
+ //#region src/highlighter/backends/shiki.d.ts
8
+ type ShikiHighlighterTypes = 'shiki-js' | 'shiki-wasm';
9
+ declare class ShikiHighlighter extends DiffsHighlighter {
10
+ private readonly raw;
11
+ private readonly loadedThemes;
12
+ private readonly attachedLanguages;
13
+ static create(name: ShikiHighlighterTypes): Promise<ShikiHighlighter>;
14
+ private constructor();
15
+ getTheme(themeName: string): DiffsTheme;
16
+ codeToTokens(code: string, options: CodeToTokensOptions): TokensResult;
17
+ createEditorTokenizer(options: DiffsEditorTokenizerOptions): ShikiEditorTokenizer;
18
+ createStreamTokenizer(options: CodeToTokensOptions): DiffsStreamTokenizer;
19
+ loadLanguages(languages: readonly string[]): Promise<void>;
20
+ hasLoadedLanguages(languages: readonly string[]): boolean;
21
+ attachLanguages(languages: readonly ResolvedLanguage[]): void;
22
+ protected releaseResources(): void;
23
+ private resolveOptions;
24
+ }
25
+ //#endregion
26
+ export { ShikiHighlighter };
27
+ //# sourceMappingURL=shiki.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shiki.d.ts","names":[],"sources":["../../../src/highlighter/backends/shiki.ts"],"mappings":";;;;;;;KAsBK;cAEQ,yBAAyB;mBAsBjB;mBAnBF;mBAEA;SAEJ,OAAO,MAAM,wBAAwB,QAAQ;UAanD;EAOP,SAAS,oBAAoB;EAuB7B,aAAa,cAAc,SAAS,sBAAsB;EAI1D,sBACE,SAAS,8BACR;EAIH,sBAAsB,SAAS,sBAAsB;EAI/C,cAAc,+BAA+B;EAQnD,mBAAmB;EAmBnB,gBAAgB,oBAAoB;YA6B1B;UAQF"}
@@ -0,0 +1,107 @@
1
+ import { RegisteredCustomLanguages } from "../languages/constants.js";
2
+ import { createDiffsThemeResolver } from "../themes/themeResolver.js";
3
+ import { attachResolvedLanguages } from "../languages/attachResolvedLanguages.js";
4
+ import { resolveLanguages } from "../languages/resolveLanguages.js";
5
+ import { DiffsHighlighter } from "../DiffsHighlighter.js";
6
+ import { ShikiEditorTokenizer } from "../shiki-editor.js";
7
+ import { ShikiStreamTokenizer } from "../shiki-stream.js";
8
+ import { createCssVariablesTheme, createHighlighterCore } from "shiki/core";
9
+ //#region src/highlighter/backends/shiki.ts
10
+ var ShikiHighlighter = class ShikiHighlighter extends DiffsHighlighter {
11
+ raw;
12
+ loadedThemes = /* @__PURE__ */ new Map();
13
+ attachedLanguages = /* @__PURE__ */ new Set(["text", "ansi"]);
14
+ static async create(name) {
15
+ const engine = name === "shiki-wasm" ? (await import("shiki/engine/oniguruma")).createOnigurumaEngine(import("shiki/wasm")) : (await import("shiki/engine/javascript")).createJavaScriptRegexEngine();
16
+ const raw = await createHighlighterCore({
17
+ themes: [],
18
+ langs: [],
19
+ engine
20
+ });
21
+ return new ShikiHighlighter(name, raw);
22
+ }
23
+ constructor(name, raw) {
24
+ super(name, createDiffsThemeResolver(name));
25
+ this.raw = raw;
26
+ }
27
+ getTheme(themeName) {
28
+ this.assertNotDisposed();
29
+ const loaded = this.loadedThemes.get(themeName);
30
+ const theme = this.themeResolver.getResolvedTheme(themeName) ?? loaded;
31
+ if (theme == null) throw new Error(`Theme "${themeName}" has not been resolved`);
32
+ if (loaded !== theme) {
33
+ const textmate = theme.textmate ?? (theme.cssVariables != null ? createCssVariablesTheme(theme.cssVariables) : void 0);
34
+ if (textmate == null) throw new Error(`Theme "${themeName}" does not support Shiki`);
35
+ this.raw.setTheme({
36
+ ...textmate,
37
+ name: themeName
38
+ });
39
+ this.loadedThemes.set(themeName, theme);
40
+ }
41
+ return theme;
42
+ }
43
+ codeToTokens(code, options) {
44
+ return this.raw.codeToTokens(code, this.resolveOptions(options));
45
+ }
46
+ createEditorTokenizer(options) {
47
+ return new ShikiEditorTokenizer(this.raw, options, this);
48
+ }
49
+ createStreamTokenizer(options) {
50
+ return new ShikiStreamTokenizer(this.raw, this.resolveOptions(options));
51
+ }
52
+ async loadLanguages(languages) {
53
+ this.assertNotDisposed();
54
+ const missing = languages.filter((language) => !this.attachedLanguages.has(language));
55
+ attachResolvedLanguages(await resolveLanguages(missing), this);
56
+ }
57
+ hasLoadedLanguages(languages) {
58
+ if (this.disposed) return false;
59
+ let loaded;
60
+ return languages.every((lang) => {
61
+ if (this.attachedLanguages.has(lang)) return true;
62
+ if (RegisteredCustomLanguages.has(lang)) return false;
63
+ loaded ??= this.raw.getLoadedLanguages();
64
+ return loaded.includes(lang);
65
+ });
66
+ }
67
+ attachLanguages(languages) {
68
+ this.assertNotDisposed();
69
+ for (const lang of languages) {
70
+ if (this.attachedLanguages.has(lang.name)) continue;
71
+ const grammar = lang.data.find((grammar) => grammar.name === lang.name || grammar.aliases?.includes(lang.name) === true);
72
+ if (grammar == null) throw new Error(`attachResolvedLanguages: No returned grammar declares "${lang.name}" as its name or an alias.`);
73
+ this.raw.loadLanguageSync(lang.data);
74
+ try {
75
+ this.raw.getLanguage(lang.name);
76
+ } catch {
77
+ throw new Error(`attachResolvedLanguages: "${grammar.name}" is already loaded without alias "${lang.name}". Load the alias first or give the grammar a unique name.`);
78
+ }
79
+ this.attachedLanguages.add(lang.name);
80
+ }
81
+ }
82
+ releaseResources() {
83
+ this.loadedThemes.clear();
84
+ this.attachedLanguages.clear();
85
+ this.raw.dispose();
86
+ }
87
+ resolveOptions({ theme, themes, ...options }) {
88
+ this.assertNotDisposed();
89
+ if (theme != null) {
90
+ this.getTheme(theme);
91
+ return {
92
+ ...options,
93
+ theme
94
+ };
95
+ }
96
+ if (themes == null) throw new Error("A theme or themes option is required");
97
+ for (const name of Object.values(themes)) this.getTheme(name);
98
+ return {
99
+ ...options,
100
+ themes
101
+ };
102
+ }
103
+ };
104
+ //#endregion
105
+ export { ShikiHighlighter };
106
+
107
+ //# sourceMappingURL=shiki.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shiki.js","names":[],"sources":["../../../src/highlighter/backends/shiki.ts"],"sourcesContent":["import {\n createCssVariablesTheme,\n createHighlighterCore,\n type HighlighterCore,\n type CodeToTokensOptions as ShikiCodeToTokensOptions,\n} from 'shiki/core';\n\nimport type { ResolvedLanguage } from '../../worker/types';\nimport { DiffsHighlighter } from '../DiffsHighlighter';\nimport { attachResolvedLanguages } from '../languages/attachResolvedLanguages';\nimport { RegisteredCustomLanguages } from '../languages/constants';\nimport { resolveLanguages } from '../languages/resolveLanguages';\nimport { ShikiEditorTokenizer } from '../shiki-editor';\nimport { ShikiStreamTokenizer } from '../shiki-stream';\nimport { createDiffsThemeResolver } from '../themes/themeResolver';\nimport type { DiffsTheme } from '../themes/types';\nimport type {\n DiffsEditorTokenizerOptions,\n DiffsStreamTokenizer,\n} from '../tokenizer-types';\nimport type { CodeToTokensOptions, TokensResult } from '../types';\n\ntype ShikiHighlighterTypes = 'shiki-js' | 'shiki-wasm';\n\nexport class ShikiHighlighter extends DiffsHighlighter {\n // Compare theme objects to detect replacements, and retain them when the\n // shared cache is cleared.\n private readonly loadedThemes = new Map<string, DiffsTheme>();\n // Shiki allocates a new language list on each lookup.\n private readonly attachedLanguages = new Set(['text', 'ansi']);\n\n static async create(name: ShikiHighlighterTypes): Promise<ShikiHighlighter> {\n const engine =\n name === 'shiki-wasm'\n ? (await import('shiki/engine/oniguruma')).createOnigurumaEngine(\n import('shiki/wasm')\n )\n : (\n await import('shiki/engine/javascript')\n ).createJavaScriptRegexEngine();\n const raw = await createHighlighterCore({ themes: [], langs: [], engine });\n return new ShikiHighlighter(name, raw);\n }\n\n private constructor(\n name: ShikiHighlighterTypes,\n private readonly raw: HighlighterCore\n ) {\n super(name, createDiffsThemeResolver(name));\n }\n\n getTheme(themeName: string): DiffsTheme {\n this.assertNotDisposed();\n const loaded = this.loadedThemes.get(themeName);\n const theme = this.themeResolver.getResolvedTheme(themeName) ?? loaded;\n if (theme == null) {\n throw new Error(`Theme \"${themeName}\" has not been resolved`);\n }\n if (loaded !== theme) {\n const textmate =\n theme.textmate ??\n (theme.cssVariables != null\n ? createCssVariablesTheme(theme.cssVariables)\n : undefined);\n if (textmate == null) {\n throw new Error(`Theme \"${themeName}\" does not support Shiki`);\n }\n // Pass the object to refresh colors, using the name tokenization looks up.\n this.raw.setTheme({ ...textmate, name: themeName });\n this.loadedThemes.set(themeName, theme);\n }\n return theme;\n }\n\n codeToTokens(code: string, options: CodeToTokensOptions): TokensResult {\n return this.raw.codeToTokens(code, this.resolveOptions(options));\n }\n\n createEditorTokenizer(\n options: DiffsEditorTokenizerOptions\n ): ShikiEditorTokenizer {\n return new ShikiEditorTokenizer(this.raw, options, this);\n }\n\n createStreamTokenizer(options: CodeToTokensOptions): DiffsStreamTokenizer {\n return new ShikiStreamTokenizer(this.raw, this.resolveOptions(options));\n }\n\n async loadLanguages(languages: readonly string[]): Promise<void> {\n this.assertNotDisposed();\n const missing = languages.filter(\n (language) => !this.attachedLanguages.has(language)\n );\n attachResolvedLanguages(await resolveLanguages(missing), this);\n }\n\n hasLoadedLanguages(languages: readonly string[]): boolean {\n if (this.disposed) {\n return false;\n }\n // Custom registrations count only when attached here; bundled grammars\n // loaded on the raw instance by other code are found in Shiki's list.\n let loaded: string[] | undefined;\n return languages.every((lang) => {\n if (this.attachedLanguages.has(lang)) {\n return true;\n }\n if (RegisteredCustomLanguages.has(lang)) {\n return false;\n }\n loaded ??= this.raw.getLoadedLanguages();\n return loaded.includes(lang);\n });\n }\n\n attachLanguages(languages: readonly ResolvedLanguage[]): void {\n this.assertNotDisposed();\n for (const lang of languages) {\n if (this.attachedLanguages.has(lang.name)) {\n continue;\n }\n const grammar = lang.data.find(\n (grammar) =>\n grammar.name === lang.name ||\n grammar.aliases?.includes(lang.name) === true\n );\n if (grammar == null) {\n throw new Error(\n `attachResolvedLanguages: No returned grammar declares \"${lang.name}\" as its name or an alias.`\n );\n }\n this.raw.loadLanguageSync(lang.data);\n // Shiki skips loaded grammars, which can leave new aliases unregistered.\n try {\n this.raw.getLanguage(lang.name);\n } catch {\n throw new Error(\n `attachResolvedLanguages: \"${grammar.name}\" is already loaded without alias \"${lang.name}\". Load the alias first or give the grammar a unique name.`\n );\n }\n this.attachedLanguages.add(lang.name);\n }\n }\n\n protected releaseResources(): void {\n this.loadedThemes.clear();\n this.attachedLanguages.clear();\n this.raw.dispose();\n }\n\n // Attach resolved themes before tokenizing. Omit the unused key because\n // Shiki treats `themes: undefined` as a request for multiple themes.\n private resolveOptions({\n theme,\n themes,\n ...options\n }: CodeToTokensOptions): ShikiCodeToTokensOptions {\n this.assertNotDisposed();\n if (theme != null) {\n this.getTheme(theme);\n return { ...options, theme };\n }\n if (themes == null) {\n throw new Error('A theme or themes option is required');\n }\n for (const name of Object.values(themes)) {\n this.getTheme(name);\n }\n return { ...options, themes };\n }\n}\n"],"mappings":";;;;;;;;;AAwBA,IAAa,mBAAb,MAAa,yBAAyB,iBAAiB;CAsBlC;CAnBnB,+BAAgC,IAAI,IAAwB;CAE5D,oCAAqC,IAAI,IAAI,CAAC,QAAQ,MAAM,CAAC;CAE7D,aAAa,OAAO,MAAwD;EAC1E,MAAM,SACJ,SAAS,gBACJ,MAAM,OAAO,0BAAA,CAA2B,sBACvC,OAAO,aACT,KAEE,MAAM,OAAO,2BAAA,CACb,4BAA4B;EACpC,MAAM,MAAM,MAAM,sBAAsB;GAAE,QAAQ,CAAC;GAAG,OAAO,CAAC;GAAG;EAAO,CAAC;EACzE,OAAO,IAAI,iBAAiB,MAAM,GAAG;CACvC;CAEA,YACE,MACA,KACA;EACA,MAAM,MAAM,yBAAyB,IAAI,CAAC;EAFzB,KAAA,MAAA;CAGnB;CAEA,SAAS,WAA+B;EACtC,KAAK,kBAAkB;EACvB,MAAM,SAAS,KAAK,aAAa,IAAI,SAAS;EAC9C,MAAM,QAAQ,KAAK,cAAc,iBAAiB,SAAS,KAAK;EAChE,IAAI,SAAS,MACX,MAAM,IAAI,MAAM,UAAU,UAAU,wBAAwB;EAE9D,IAAI,WAAW,OAAO;GACpB,MAAM,WACJ,MAAM,aACL,MAAM,gBAAgB,OACnB,wBAAwB,MAAM,YAAY,IAC1C,KAAA;GACN,IAAI,YAAY,MACd,MAAM,IAAI,MAAM,UAAU,UAAU,yBAAyB;GAG/D,KAAK,IAAI,SAAS;IAAE,GAAG;IAAU,MAAM;GAAU,CAAC;GAClD,KAAK,aAAa,IAAI,WAAW,KAAK;EACxC;EACA,OAAO;CACT;CAEA,aAAa,MAAc,SAA4C;EACrE,OAAO,KAAK,IAAI,aAAa,MAAM,KAAK,eAAe,OAAO,CAAC;CACjE;CAEA,sBACE,SACsB;EACtB,OAAO,IAAI,qBAAqB,KAAK,KAAK,SAAS,IAAI;CACzD;CAEA,sBAAsB,SAAoD;EACxE,OAAO,IAAI,qBAAqB,KAAK,KAAK,KAAK,eAAe,OAAO,CAAC;CACxE;CAEA,MAAM,cAAc,WAA6C;EAC/D,KAAK,kBAAkB;EACvB,MAAM,UAAU,UAAU,QACvB,aAAa,CAAC,KAAK,kBAAkB,IAAI,QAAQ,CACpD;EACA,wBAAwB,MAAM,iBAAiB,OAAO,GAAG,IAAI;CAC/D;CAEA,mBAAmB,WAAuC;EACxD,IAAI,KAAK,UACP,OAAO;EAIT,IAAI;EACJ,OAAO,UAAU,OAAO,SAAS;GAC/B,IAAI,KAAK,kBAAkB,IAAI,IAAI,GACjC,OAAO;GAET,IAAI,0BAA0B,IAAI,IAAI,GACpC,OAAO;GAET,WAAW,KAAK,IAAI,mBAAmB;GACvC,OAAO,OAAO,SAAS,IAAI;EAC7B,CAAC;CACH;CAEA,gBAAgB,WAA8C;EAC5D,KAAK,kBAAkB;EACvB,KAAK,MAAM,QAAQ,WAAW;GAC5B,IAAI,KAAK,kBAAkB,IAAI,KAAK,IAAI,GACtC;GAEF,MAAM,UAAU,KAAK,KAAK,MACvB,YACC,QAAQ,SAAS,KAAK,QACtB,QAAQ,SAAS,SAAS,KAAK,IAAI,MAAM,IAC7C;GACA,IAAI,WAAW,MACb,MAAM,IAAI,MACR,0DAA0D,KAAK,KAAK,2BACtE;GAEF,KAAK,IAAI,iBAAiB,KAAK,IAAI;GAEnC,IAAI;IACF,KAAK,IAAI,YAAY,KAAK,IAAI;GAChC,QAAQ;IACN,MAAM,IAAI,MACR,6BAA6B,QAAQ,KAAK,qCAAqC,KAAK,KAAK,2DAC3F;GACF;GACA,KAAK,kBAAkB,IAAI,KAAK,IAAI;EACtC;CACF;CAEA,mBAAmC;EACjC,KAAK,aAAa,MAAM;EACxB,KAAK,kBAAkB,MAAM;EAC7B,KAAK,IAAI,QAAQ;CACnB;CAIA,eAAuB,EACrB,OACA,QACA,GAAG,WAC6C;EAChD,KAAK,kBAAkB;EACvB,IAAI,SAAS,MAAM;GACjB,KAAK,SAAS,KAAK;GACnB,OAAO;IAAE,GAAG;IAAS;GAAM;EAC7B;EACA,IAAI,UAAU,MACZ,MAAM,IAAI,MAAM,sCAAsC;EAExD,KAAK,MAAM,QAAQ,OAAO,OAAO,MAAM,GACrC,KAAK,SAAS,IAAI;EAEpB,OAAO;GAAE,GAAG;GAAS;EAAO;CAC9B;AACF"}
@@ -0,0 +1,13 @@
1
+ import { HighlighterTypes } from "../types.js";
2
+ //#region src/highlighter/highlighterType.d.ts
3
+ declare class HighlighterDisposedError extends Error {
4
+ constructor();
5
+ }
6
+ declare function getHighlighterType(): HighlighterTypes | undefined;
7
+ declare function resolveHighlighterType(type?: HighlighterTypes): HighlighterTypes;
8
+ declare function assertHighlighterType(type: HighlighterTypes): void;
9
+ declare function acquireHighlighterType(type: HighlighterTypes): void;
10
+ declare function releaseHighlighterType(): void;
11
+ //#endregion
12
+ export { HighlighterDisposedError, acquireHighlighterType, assertHighlighterType, getHighlighterType, releaseHighlighterType, resolveHighlighterType };
13
+ //# sourceMappingURL=highlighterType.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlighterType.d.ts","names":[],"sources":["../../src/highlighter/highlighterType.ts"],"mappings":";;cAQa,iCAAiC;EAC5C;;iBAMc,sBAAsB;iBAItB,uBACd,OAAO,mBACN;iBAIa,sBAAsB,MAAM;iBAQ5B,uBAAuB,MAAM;iBAM7B"}
@@ -0,0 +1,32 @@
1
+ import "../constants.js";
2
+ //#region src/highlighter/highlighterType.ts
3
+ let activeType;
4
+ let holds = 0;
5
+ var HighlighterDisposedError = class extends Error {
6
+ constructor() {
7
+ super("Highlighter is disposed");
8
+ this.name = "HighlighterDisposedError";
9
+ }
10
+ };
11
+ function getHighlighterType() {
12
+ return activeType;
13
+ }
14
+ function resolveHighlighterType(type) {
15
+ return type ?? activeType ?? "shiki-js";
16
+ }
17
+ function assertHighlighterType(type) {
18
+ if (activeType != null && activeType !== type) throw new Error(`Cannot load the "${type}" highlighter while "${activeType}" is in use. Only one highlighter type can be active at a time; dispose every "${activeType}" instance (disposeHighlighter() disposes the shared one) before switching.`);
19
+ }
20
+ function acquireHighlighterType(type) {
21
+ assertHighlighterType(type);
22
+ activeType = type;
23
+ holds++;
24
+ }
25
+ function releaseHighlighterType() {
26
+ holds--;
27
+ if (holds === 0) activeType = void 0;
28
+ }
29
+ //#endregion
30
+ export { HighlighterDisposedError, acquireHighlighterType, assertHighlighterType, getHighlighterType, releaseHighlighterType, resolveHighlighterType };
31
+
32
+ //# sourceMappingURL=highlighterType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlighterType.js","names":[],"sources":["../../src/highlighter/highlighterType.ts"],"sourcesContent":["import { DEFAULT_HIGHLIGHTER } from '../constants';\nimport type { HighlighterTypes } from '../types';\n\n// The main thread and each worker allow one highlighter type at a time.\n// Pending creations and live instances prevent switching types.\nlet activeType: HighlighterTypes | undefined;\nlet holds = 0;\n\nexport class HighlighterDisposedError extends Error {\n constructor() {\n super('Highlighter is disposed');\n this.name = 'HighlighterDisposedError';\n }\n}\n\nexport function getHighlighterType(): HighlighterTypes | undefined {\n return activeType;\n}\n\nexport function resolveHighlighterType(\n type?: HighlighterTypes\n): HighlighterTypes {\n return type ?? activeType ?? DEFAULT_HIGHLIGHTER;\n}\n\nexport function assertHighlighterType(type: HighlighterTypes): void {\n if (activeType != null && activeType !== type) {\n throw new Error(\n `Cannot load the \"${type}\" highlighter while \"${activeType}\" is in use. Only one highlighter type can be active at a time; dispose every \"${activeType}\" instance (disposeHighlighter() disposes the shared one) before switching.`\n );\n }\n}\n\nexport function acquireHighlighterType(type: HighlighterTypes): void {\n assertHighlighterType(type);\n activeType = type;\n holds++;\n}\n\nexport function releaseHighlighterType(): void {\n holds--;\n if (holds === 0) {\n activeType = undefined;\n }\n}\n"],"mappings":";;AAKA,IAAI;AACJ,IAAI,QAAQ;AAEZ,IAAa,2BAAb,cAA8C,MAAM;CAClD,cAAc;EACZ,MAAM,yBAAyB;EAC/B,KAAK,OAAO;CACd;AACF;AAEA,SAAgB,qBAAmD;CACjE,OAAO;AACT;AAEA,SAAgB,uBACd,MACkB;CAClB,OAAO,QAAQ,cAAA;AACjB;AAEA,SAAgB,sBAAsB,MAA8B;CAClE,IAAI,cAAc,QAAQ,eAAe,MACvC,MAAM,IAAI,MACR,oBAAoB,KAAK,uBAAuB,WAAW,iFAAiF,WAAW,4EACzJ;AAEJ;AAEA,SAAgB,uBAAuB,MAA8B;CACnE,sBAAsB,IAAI;CAC1B,aAAa;CACb;AACF;AAEA,SAAgB,yBAA+B;CAC7C;CACA,IAAI,UAAU,GACZ,aAAa,KAAA;AAEjB"}