@pierre/diffs 1.3.5 → 1.4.0
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.
- package/dist/components/CodeView.d.ts +113 -68
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +153 -58
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +75 -15
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +223 -62
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +97 -21
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +400 -100
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts +2 -2
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +2 -2
- package/dist/components/UnresolvedFile.js.map +1 -1
- package/dist/components/VirtualizedFile.d.ts +16 -7
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +140 -51
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +14 -8
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +183 -93
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/VirtulizerDevelopment.d.ts +1 -1
- package/dist/components/VirtulizerDevelopment.d.ts.map +1 -1
- package/dist/edit/index.d.ts +7 -4
- package/dist/edit/index.js +5 -1
- package/dist/editor/EditStateManager.d.ts +56 -0
- package/dist/editor/EditStateManager.d.ts.map +1 -0
- package/dist/editor/EditStateManager.js +135 -0
- package/dist/editor/EditStateManager.js.map +1 -0
- package/dist/editor/cloneRetainedDiffSessionSnapshot.d.ts +7 -0
- package/dist/editor/cloneRetainedDiffSessionSnapshot.d.ts.map +1 -0
- package/dist/editor/cloneRetainedDiffSessionSnapshot.js +16 -0
- package/dist/editor/cloneRetainedDiffSessionSnapshot.js.map +1 -0
- package/dist/editor/editPrediction.d.ts +76 -0
- package/dist/editor/editPrediction.d.ts.map +1 -0
- package/dist/editor/editPrediction.js +365 -0
- package/dist/editor/editPrediction.js.map +1 -0
- package/dist/editor/editStack.d.ts +19 -40
- package/dist/editor/editStack.d.ts.map +1 -1
- package/dist/editor/editStack.js +67 -4
- package/dist/editor/editStack.js.map +1 -1
- package/dist/editor/editor.d.ts +118 -29
- package/dist/editor/editor.d.ts.map +1 -1
- package/dist/editor/editor.js +1196 -403
- package/dist/editor/editor.js.map +1 -1
- package/dist/editor/editor2.js +1 -1
- package/dist/editor/languages.d.ts +3 -3
- package/dist/editor/languages.d.ts.map +1 -1
- package/dist/editor/languages.js.map +1 -1
- package/dist/editor/lineAnnotations.d.ts +3 -3
- package/dist/editor/lineAnnotations.d.ts.map +1 -1
- package/dist/editor/lineAnnotations.js +16 -7
- package/dist/editor/lineAnnotations.js.map +1 -1
- package/dist/editor/marker.d.ts +2 -2
- package/dist/editor/marker.d.ts.map +1 -1
- package/dist/editor/marker.js.map +1 -1
- package/dist/editor/matchBrackets.d.ts +2 -2
- package/dist/editor/matchBrackets.d.ts.map +1 -1
- package/dist/editor/matchBrackets.js.map +1 -1
- package/dist/editor/pieceTable.d.ts +1 -1
- package/dist/editor/pieceTable.js.map +1 -1
- package/dist/editor/searchPanel.d.ts +2 -2
- package/dist/editor/searchPanel.d.ts.map +1 -1
- package/dist/editor/searchPanel.js +3 -2
- package/dist/editor/searchPanel.js.map +1 -1
- package/dist/editor/selection.d.ts +33 -23
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +3 -3
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/selectionAction.d.ts +3 -3
- package/dist/editor/selectionAction.d.ts.map +1 -1
- package/dist/editor/selectionAction.js.map +1 -1
- package/dist/editor/textDocument.d.ts +11 -8
- package/dist/editor/textDocument.d.ts.map +1 -1
- package/dist/editor/textDocument.js +28 -5
- package/dist/editor/textDocument.js.map +1 -1
- package/dist/editor/textDocumentChangeTransaction.d.ts +15 -0
- package/dist/editor/textDocumentChangeTransaction.d.ts.map +1 -0
- package/dist/editor/textDocumentChangeTransaction.js +12 -0
- package/dist/editor/textDocumentChangeTransaction.js.map +1 -0
- package/dist/editor/textMeasure.d.ts +5 -0
- package/dist/editor/textMeasure.d.ts.map +1 -1
- package/dist/editor/textMeasure.js +10 -0
- package/dist/editor/textMeasure.js.map +1 -1
- package/dist/editor/tokenizer.d.ts +1 -1
- package/dist/editor/tokenizer.d.ts.map +1 -1
- package/dist/editor/tokenizer.js +6 -3
- package/dist/editor/tokenizer.js.map +1 -1
- package/dist/editor/types.d.ts +267 -0
- package/dist/editor/types.d.ts.map +1 -0
- package/dist/editor/types.js +0 -0
- package/dist/editor/utils.d.ts +2 -1
- package/dist/editor/utils.d.ts.map +1 -1
- package/dist/editor/utils.js +4 -1
- package/dist/editor/utils.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.js +9 -8
- package/dist/managers/InteractionManager.d.ts.map +1 -1
- package/dist/managers/InteractionManager.js +7 -0
- package/dist/managers/InteractionManager.js.map +1 -1
- package/dist/react/CodeView.d.ts +36 -25
- package/dist/react/CodeView.d.ts.map +1 -1
- package/dist/react/CodeView.js +15 -14
- package/dist/react/CodeView.js.map +1 -1
- package/dist/react/EditContext.d.ts +8 -11
- package/dist/react/EditContext.d.ts.map +1 -1
- package/dist/react/EditContext.js +2 -9
- package/dist/react/EditContext.js.map +1 -1
- package/dist/react/File.d.ts +10 -6
- package/dist/react/File.d.ts.map +1 -1
- package/dist/react/File.js +8 -4
- package/dist/react/File.js.map +1 -1
- package/dist/react/FileDiff.d.ts +10 -5
- package/dist/react/FileDiff.d.ts.map +1 -1
- package/dist/react/FileDiff.js +8 -4
- package/dist/react/FileDiff.js.map +1 -1
- package/dist/react/MultiFileDiff.d.ts +8 -5
- package/dist/react/MultiFileDiff.d.ts.map +1 -1
- package/dist/react/MultiFileDiff.js +8 -12
- package/dist/react/MultiFileDiff.js.map +1 -1
- package/dist/react/PatchDiff.d.ts +7 -4
- package/dist/react/PatchDiff.d.ts.map +1 -1
- package/dist/react/PatchDiff.js +8 -4
- package/dist/react/PatchDiff.js.map +1 -1
- package/dist/react/UnresolvedFile.d.ts +3 -3
- package/dist/react/UnresolvedFile.d.ts.map +1 -1
- package/dist/react/UnresolvedFile.js.map +1 -1
- package/dist/react/index.d.ts +8 -5
- package/dist/react/types.d.ts +46 -9
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.d.ts +14 -12
- package/dist/react/utils/renderDiffChildren.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.js +2 -2
- package/dist/react/utils/renderDiffChildren.js.map +1 -1
- package/dist/react/utils/renderFileChildren.d.ts +14 -12
- package/dist/react/utils/renderFileChildren.d.ts.map +1 -1
- package/dist/react/utils/renderFileChildren.js +2 -2
- package/dist/react/utils/renderFileChildren.js.map +1 -1
- package/dist/react/utils/useFileDiffInstance.d.ts +22 -10
- package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +112 -22
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.d.ts +15 -9
- package/dist/react/utils/useFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileInstance.js +84 -25
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +30 -15
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +172 -108
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +27 -11
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +138 -64
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.d.ts +2 -2
- package/dist/renderers/UnresolvedFileHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.js +2 -2
- package/dist/renderers/UnresolvedFileHunksRenderer.js.map +1 -1
- package/dist/shiki-stream/tokenizer.d.ts.map +1 -1
- package/dist/shiki-stream/tokenizer.js +2 -1
- package/dist/shiki-stream/tokenizer.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/preloadDiffs.d.ts +21 -21
- package/dist/ssr/preloadDiffs.d.ts.map +1 -1
- package/dist/ssr/preloadDiffs.js +1 -1
- package/dist/ssr/preloadDiffs.js.map +1 -1
- package/dist/ssr/preloadFile.d.ts +6 -6
- package/dist/ssr/preloadFile.d.ts.map +1 -1
- package/dist/ssr/preloadFile.js.map +1 -1
- package/dist/ssr/preloadPatchFile.d.ts +4 -4
- package/dist/ssr/preloadPatchFile.d.ts.map +1 -1
- package/dist/ssr/preloadPatchFile.js.map +1 -1
- package/dist/style.js +1 -1
- package/dist/types.d.ts +13 -263
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/appendItems.d.ts +5 -0
- package/dist/utils/appendItems.d.ts.map +1 -0
- package/dist/utils/appendItems.js +8 -0
- package/dist/utils/appendItems.js.map +1 -0
- package/dist/utils/areDiffTargetsEqual.js +1 -1
- package/dist/utils/areDiffTargetsEqual.js.map +1 -1
- package/dist/utils/areFileTargetsEqual.d.ts +7 -0
- package/dist/utils/areFileTargetsEqual.d.ts.map +1 -0
- package/dist/utils/areFileTargetsEqual.js +8 -0
- package/dist/utils/areFileTargetsEqual.js.map +1 -0
- package/dist/utils/areManagedSnapshotsEqual.d.ts +1 -1
- package/dist/utils/areManagedSnapshotsEqual.d.ts.map +1 -1
- package/dist/utils/areManagedSnapshotsEqual.js.map +1 -1
- package/dist/utils/areOptionsEqual.d.ts +3 -3
- package/dist/utils/areOptionsEqual.d.ts.map +1 -1
- package/dist/utils/areOptionsEqual.js.map +1 -1
- package/dist/utils/cloneFileDiffMetadata.d.ts +3 -2
- package/dist/utils/cloneFileDiffMetadata.d.ts.map +1 -1
- package/dist/utils/cloneFileDiffMetadata.js +8 -5
- package/dist/utils/cloneFileDiffMetadata.js.map +1 -1
- package/dist/utils/composeCacheKey.d.ts +6 -0
- package/dist/utils/composeCacheKey.d.ts.map +1 -0
- package/dist/utils/composeCacheKey.js +10 -0
- package/dist/utils/composeCacheKey.js.map +1 -0
- package/dist/utils/editSessionAnnotations.d.ts +69 -0
- package/dist/utils/editSessionAnnotations.d.ts.map +1 -0
- package/dist/utils/editSessionAnnotations.js +64 -0
- package/dist/utils/editSessionAnnotations.js.map +1 -0
- package/dist/utils/editSessionHunks.d.ts +5 -3
- package/dist/utils/editSessionHunks.d.ts.map +1 -1
- package/dist/utils/editSessionHunks.js +7 -5
- package/dist/utils/editSessionHunks.js.map +1 -1
- package/dist/utils/getDiffHunksRendererOptions.d.ts +1 -1
- package/dist/utils/getDiffHunksRendererOptions.d.ts.map +1 -1
- package/dist/utils/getDiffHunksRendererOptions.js.map +1 -1
- package/dist/utils/getFileRendererOptions.d.ts +1 -1
- package/dist/utils/getFileRendererOptions.d.ts.map +1 -1
- package/dist/utils/getFileRendererOptions.js.map +1 -1
- package/dist/utils/hydratePartialDiff.d.ts.map +1 -1
- package/dist/utils/hydratePartialDiff.js +2 -1
- package/dist/utils/hydratePartialDiff.js.map +1 -1
- package/dist/utils/lineAnnotationIdentity.d.ts +16 -0
- package/dist/utils/lineAnnotationIdentity.d.ts.map +1 -0
- package/dist/utils/lineAnnotationIdentity.js +17 -0
- package/dist/utils/lineAnnotationIdentity.js.map +1 -0
- package/dist/utils/parseDiffFromFile.d.ts +2 -2
- package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseDiffFromFile.js +6 -6
- package/dist/utils/parseDiffFromFile.js.map +1 -1
- package/dist/utils/parsePatchFiles.d.ts +6 -3
- package/dist/utils/parsePatchFiles.d.ts.map +1 -1
- package/dist/utils/parsePatchFiles.js +34 -9
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.d.ts.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.js +6 -5
- package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
- package/dist/utils/renderFileWithHighlighter.d.ts.map +1 -1
- package/dist/utils/renderFileWithHighlighter.js +7 -4
- package/dist/utils/renderFileWithHighlighter.js.map +1 -1
- package/dist/utils/trimPatchContext.d.ts.map +1 -1
- package/dist/utils/trimPatchContext.js +3 -2
- package/dist/utils/trimPatchContext.js.map +1 -1
- package/dist/utils/updateDiffHunks.js +1 -1
- package/dist/utils/virtualDiffLayout.js +1 -1
- package/dist/worker/WorkerPoolManager.d.ts +4 -3
- package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
- package/dist/worker/WorkerPoolManager.js +33 -4
- package/dist/worker/WorkerPoolManager.js.map +1 -1
- package/dist/worker/types.d.ts +5 -0
- package/dist/worker/types.d.ts.map +1 -1
- package/dist/worker/worker-portable.js +14 -6
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +14 -6
- package/dist/worker/worker.js.map +1 -1
- package/package.json +9 -1
- package/dist/editor/stateStorage.d.ts +0 -15
- package/dist/editor/stateStorage.d.ts.map +0 -1
- package/dist/editor/stateStorage.js +0 -65
- package/dist/editor/stateStorage.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokenizer.js","names":["#isCleanedUp","#textDocument","#grammar","#highlighter","#ensureActiveTheme","#scheduleStatePrebuild","#tokenizerId","#backgroundJobId","#backgroundPrebuildEndLine","#backgroundPrebuild","#backgroundTokenize","#themeType","#matchBrackets","#ensureGrammar","#bracketIgnoredRanges","#buildStateStack","#stateStack","#tokenizeLineAt","#mediaQueryList","#resolveSystemThemeType","#emitThemeChange","#disposes","#tokenizeMaxLineLength","#setStyle","#onDeferTokenize","#onThemeChange","#debug","#colorMap","#setTheme","#themeName","#comparisonStateStack","#comparisonStateStackStart","#comparisonLineChanges","#scheduleBackgroundTokenize","#detachMessageListener","#shiftComparisonStateStack","#getPreviousEndState","#prebuildStateStack","#pendingPrebuildEndLine","#isStopped","#isPaused","#lastLine","#backgroundChangedLineRanges","#backgroundChangedRangeIndex","#postTokenizeMessage","#isMessageListenerAttached","#onMessage","#attachMessageListener","#cacheBracketIgnoredRanges"],"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<unknown>;\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<unknown>;\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 if (this.#matchBrackets) {\n // Clear ignored token ranges for lines invalidated by the edit.\n this.#bracketIgnoredRanges.length = Math.min(\n this.#bracketIgnoredRanges.length,\n change.startLine\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 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 this.#scheduleBackgroundTokenize(\n backgroundStartLine,\n changedLineRanges,\n backgroundChangedRangeIndex\n );\n } else if (!settled && line < lineCount) {\n const backgroundLine =\n crossesRenderRangeEnd && dirtyStart >= viewStart\n ? renderRangeEndLine\n : dirtyStart < viewStart && !canReuseCachedStates\n ? dirtyStart\n : line;\n this.#scheduleBackgroundTokenize(\n backgroundLine,\n 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":";;;;;AAkBA,MAAM,sBAAsB;AAC5B,IAAI,kBAAkB;;AAoBtB,IAAa,kBAAb,MAA6B;CAC3B;CACA;CACA;CACA,aAA+B;CAI/B,aAAa;CACb;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,eAAe;CAGf,cAA4B,CAAC,OAAO;CACpC,wBAAsC,CAAC;CACvC,6BAA6B;CAC7B,yBAEI,CAAC;CACL,YAAoB;CACpB,aAAsB;CACtB,YAAqB;CACrB,mBAA2B;CAC3B,eAAe,EAAE;CACjB,6BAA6B;CAC7B,0BAA0B;CAC1B;CACA,+BAAuC;CACvC,wBAAmE,CAAC;CACpE,6BAAsC;CAEtC,sBAAsB,SAAS,OAAO,gBAA8B;EAGlE,IAAI,KAAKA,cACP;EAEF,MAAM,EAAE,eAAe,GAAG,aAAa,aAAa,eAAe,CAAC;EACpE,MAAM,UAAU,KAAK,IACnB,eAAe,WAAW,WAAW,eAAe,YACpD,KAAKC,cAAc,SACrB;EACA,IACE,KAAKC,aAAa,KAAA,KAClB,CAAC,sBAAsB,KAAKD,cAAc,UAAU,GACpD;GACA,MAAM,KAAKE,aAAa,aAAa,KAAKF,cAAc,UAAU;GAClE,IAAI,KAAKD,cACP;GAEF,KAAKE,WAAW,KAAKC,aAAa,YAChC,KAAKF,cAAc,UACrB;EACF;EACA,KAAKG,mBAAmB;EACxB,KAAKC,uBAAuB,OAAO;CACrC,GAAG,GAAG;CAEN,cAAc,EAAE,WAAkC;EAChD,IAAI,OAAO,SAAS,YAAY,SAAS,MACvC;EAEF,MAAM,EAAE,MAAM,aAAa,UAAU;EAKrC,IACE,SAAS,cACT,gBAAgB,KAAKC,gBACrB,OAAO,UAAU,YACjB,UAAU,KAAKC,kBAEf,IAAI,KAAKC,8BAA8B,GACrC,KAAKC,oBAAoB,KAAK;OAE9B,KAAKC,oBAAoB,KAAK;CAGpC;CAEA,IAAI,YAA8B;EAChC,OAAO,KAAKC;CACd;CAEA,mCACE,WAC2B;EAC3B,IACE,CAAC,KAAKC,kBACN,YAAY,KACZ,aAAa,KAAKX,cAAc,WAEhC,OAAO;EAET,KAAKY,eAAe;EACpB,IAAI,KAAKX,aAAa,KAAA,GACpB,OAAO;EAET,IAAI,KAAKY,sBAAsB,eAAe,KAAA,GAAW;GACvD,KAAKC,iBAAiB,SAAS;GAC/B,MAAM,QAAQ,KAAKC,YAAY,cAAc;GAC7C,MAAM,SAAS,KAAKC,gBAAgB,WAAW,KAAK;GACpD,KAAKD,YAAY,YAAY,KAAK,OAAO;EAC3C;EACA,OAAO,KAAKF,sBAAsB,cAAc;CAClD;CAEA,YAAY,EACV,aACA,aACA,cACA,eACA,UACA,iBACA,eACA,WACuB;EACvB,MAAM,EACJ,WAAW,kBAAkB,UAC7B,QAAQ,gBACR,wBAAwB,QACtB;EACJ,KAAKI,kBAAkB,OAAO,WAAW,8BAA8B;EACvE,IAAI;EACJ,IAAI,oBAAoB,UAGtB,YAAY,KAAKC,wBAAwB;OAEzC,YAAY;EAOd,IAAI,OAAO,UAAU,YAAY,oBAAoB,UAAU;GAC7D,MAAM,WAAW,IAAI,kBAAkB,cAAc;IACnD,KAAK,MAAM,EAAE,MAAM,mBAAmB,WACpC,IACE,SAAS,gBACT,kBAAkB,SACjB,kBAAkB,WAAW,cAAc,WAAW,OAAO,IAC9D;KACA,MAAM,YAAY,KAAKA,wBAAwB;KAC/C,KAAKC,iBAAiB,MAAM,YAAY,SAAS;KACjD;IACF;GAEJ,CAAC;GACD,SAAS,QAAQ,SAAS,iBAAiB,EAAE,YAAY,KAAK,CAAC;GAC/D,SAAS,QAAQ,SAAS,MAAM,EAAE,YAAY,KAAK,CAAC;GACpD,KAAKC,YAAY,CACf,iBAAiB,KAAKH,iBAAiB,gBAAgB;IAGrD,MAAM,YAAY,KAAKC,wBAAwB;IAC/C,KAAKC,iBAAiB,MAAM,YAAY,SAAS;GACnD,CAAC,SACK,SAAS,WAAW,CAC5B;EACF;EACA,KAAKjB,eAAe;EACpB,KAAKF,gBAAgB;EACrB,KAAKqB,yBAAyB;EAC9B,KAAKC,YAAY;EACjB,KAAKC,mBAAmB;EACxB,KAAKC,iBAAiB;EACtB,KAAKb,iBAAiB,kBAAkB;EACxC,KAAKc,SAAS,WAAW;EACzB,KAAKb,eAAe;EACpB,KAAKc,YAAY,CAAC;EAClB,KAAKC,UACH,OAAO,UAAU,WAAW,QAAQ,MAAM,YAC1C,OAAO,UAAU,WAAW,KAAA,IAAY,SAC1C;CACF;CAIA,iBAAiB,WAAmB,WAA6B;EAC/D,IAAI,cAAc,KAAKC,cAAc,cAAc,KAAKlB,YACtD;EAEF,KAAKiB,UAAU,WAAW,SAAS;EACnC,KAAK,uBAAuB;EAC5B,KAAKZ,cAAc,CAAC,OAAO;EAC3B,KAAKc,wBAAwB,CAAC;EAC9B,KAAKC,6BAA6B;EAClC,KAAKC,yBAAyB,CAAC;EAC/B,IAAI,KAAK9B,aAAa,KAAA,KAAa,KAAKD,cAAc,YAAY,GAChE,KAAKgC,4BAA4B,CAAC;EAKpC,KAAKR,iBAAiB;CACxB;CAIA,0BAA4C;EAC1C,IAAI;GACF,IACE,OAAO,aAAa,eACpB,OAAO,qBAAqB,cAC5B,SAAS,QAAQ,MACjB;IACA,MAAM,eAAe,iBAAiB,SAAS,IAAI,CAAC,CAAC,YAAY,MAC/D,KACF;IACA,MAAM,eAAe,aAAa,SAAS,MAAM;IAIjD,IAAI,iBAHkB,aAAa,SAAS,OAGX,GAC/B,OAAO,eAAe,SAAS;GAEnC;EACF,QAAQ,CAGR;EACA,OAAO,KAAKP,gBAAgB,UAAU,SAAS;CACjD;CAUA,UAAU,aAAoC;EAC5C,MAAM,EAAE,YAAY,UAAU,QAAQ,mBAAmB;EAGzD,IAAI,OAAO,UAAU,UAAU;GAC7B,MAAM,kBAAkB,KAAKf,aAAa,SAAS,KAAK,CAAC,CAAC;GAC1D,IAAI,UAAU,KAAK0B,cAAc,oBAAoB,KAAKlB,YACxD;GAEF,KAAKS,iBAAiB,OAAO,eAAe;GAC5C;EACF;EACA,MAAM,gBACJ,cAAc,WAAW,KAAKD,wBAAwB,IAAI;EAC5D,MAAM,gBAAgB,MAAM;EAC5B,IACE,kBAAkB,KAAKR,cACvB,kBAAkB,KAAKkB,YAEvB;EAEF,KAAKT,iBAAiB,eAAe,aAAa;CACpD;CAEA,UAAU,WAAmB,WAA8B;EACzD,MAAM,EAAE,OAAO,aAAa,KAAKjB,aAAa,SAAS,SAAS;EAChE,MAAM,EAAE,SAAS,CAAC,MAAM,KAAKA,aAAa,SAAS,SAAS;EAC5D,MAAM,sBAAsB,OAAO;EACnC,MAAM,+BACJ,OAAO;EACT,MAAM,0BACJ,gCAAgC,QAChC,6BAA6B,KAAK,MAAM,MACxC,CAAC,WAAW,mBAAmB,4BAA4B,IACvD,+BACA,KAAA;EAGN,MAAM,sBACJ,OAAO,kCACN,2BAA2B,OACxB,4DACA;EACN,MAAM,sBACJ,2BAA2B,OAAO,SAAS;EAC7C,MAAM,mBAAmB,OAAO;EAChC,MAAM,sBAAsB,OAAO;EACnC,MAAM,+BACJ,OAAO;EACT,MAAM,yBAAyB,OAAO;EACtC,MAAM,qBAAqB,OAAO;EAClC,MAAM,iBAAiB,OAAO;EAC9B,MAAM,iBAAiB,OAAO;EAC9B,MAAM,oBAAoB,OAAO;EACjC,MAAM,kBAAkB,OAAO;EAC/B,KAAKoB,UAAU;qCACkB,uBAAuB,uBAAuB;8CACrC,oBAAoB;+CACnB,oBAAoB;iCAClC,uBAAuB,UAAU;2CACvB,gCAAgC,UAAU;yCAC5C,0BAA0B,UAAU;6CAChC,sBAAsB,UAAU;kCAC3C,oBAAoB,UAAU;gCAChC,kBAAkB,UAAU;gCAC5B,kBAAkB,UAAU;mCACzB,qBAAqB,UAAU;iCACjC,mBAAmB,UAAU;MACxD;EACF,KAAKM,aAAa;EAClB,KAAKlB,aAAa,aAAa,MAAM;EACrC,KAAKgB,YAAY;CACnB;CASA,qBAA2B;EACzB,IAAI,KAAKE,eAAe,IACtB;EAEF,MAAM,EAAE,aAAa,KAAK1B,aAAa,SAAS,KAAK0B,UAAU;EAC/D,KAAKF,YAAY;CACnB;CAEA,UAAgB;EACd,KAAK3B,eAAe;EACpB,KAAK,uBAAuB;EAC5B,KAAKkC,uBAAuB;EAC5B,KAAKb,WAAW,SAAS,YAAY,QAAQ,CAAC;EAC9C,KAAKA,YAAY,KAAA;CACnB;CAIA,SACE,QACA,aACA,mBAAmB,OACmB;EACtC,KAAKR,eAAe;EACpB,KAAKT,mBAAmB;EACxB,IACE,KAAKF,aAAa,KAAA,KAClB,CAAC,sBAAsB,KAAKD,cAAc,UAAU,GAEpD,MAAM,IAAI,MACR,yBAAyB,KAAKA,cAAc,WAAW,aACzD;EAGF,IAAI,KAAKW,gBAEP,KAAKE,sBAAsB,SAAS,KAAK,IACvC,KAAKA,sBAAsB,QAC3B,OAAO,SACT;EAGF,MAAM,EAAE,cAAc,KAAKb;EAC3B,MAAM,EAAE,eAAe,GAAG,aAAa,aAAa,eAAe,CAAC;EACpE,MAAM,qBACJ,eAAe,WACX,YACA,KAAK,IAAI,eAAe,YAAY,SAAS;EAEnD,MAAM,aAAa,OAAO;EAC1B,MAAM,YAAY,KAAK,IAAI,cAAc,UAAU;EACnD,MAAM,wBACJ,gBAAgB,KAAA,KAChB,eAAe,YACf,OAAO,YAAY,KACnB,aAAa,sBACb,OAAO,WAAW;EACpB,MAAM,uBACJ,OAAO,cAAc,MACpB,OAAO,oBAAoB,OAAO,KAAK,eAAe,cAAc,CAAC,KACpE;EACJ,MAAM,wBACJ,oBAAoB,OAAO,cAAc,KAAK,cAAc;EAC9D,MAAM,0BACJ,wBACA,gBAAgB,KAAA,KAChB,cAAc;EAChB,MAAM,oBACJ,OAAO,qBAAqB,CAAC,CAAC,YAAY,OAAO,OAAO,CAAC;EAC3D,KAAK6B,wBAAwB,CAAC;EAC9B,KAAKC,6BAA6B;EAClC,KAAKC,yBAAyB,CAAC;EAC/B,IAAI,mBAAmB;EACvB,IAAI,aAAa;QACV,MAAM,CAAC,YAAY,aAAa,mBACnC,IAAI,aAAa,WACf,mBAAmB,KAAK,IACtB,kBACA,KAAK,IAAI,UAAU,YAAY,CAAC,CAClC;EAAA;EAIN,MAAM,4BACJ,oBAAoB,eACnB,wBAAwB,OAAO,YAAY;EAC9C,IAAI,sBACF,KAAKjB,iBAAiB,UAAU;OAC3B;GACL,KAAKoB,2BAA2B,MAAM;GACtC,IAAI,gBAAgB,KAAA,KAAa,cAAc,WAC7C,KAAKpB,iBAAiB,SAAS;EAEnC;EAEA,IAAI,oBAAoB;EACxB,IAAI,yBAAyB,kBAAkB,kBAAkB,CAAC;EAClE,IAAI;EACJ,IAAI,8BAA8B;EAClC,IAAI,OAAO,uBACP,kBAAkB,kBAAkB,CAAC,KACrC;EACJ,IAAI,UAAU;EACd,MAAM,6BAAmD,IAAI,IAAI;EACjE,MAAM,sBAEU,4CAA4B,IAAI,IAAI,IAAI,KAAA;EACxD,IAAI,wBAAwB,KAAA,KAAa,CAAC,sBAAsB;GAC9D,MAAM,eAAe,KAAK,IACxB,mBAAmB,GACnB,WACA,kBACF;GACA,IAAI,eAAe,YAAY;IAC7B,KAAKA,iBAAiB,YAAY;IAClC,IAAI,gBAAgB;IACpB,IAAI,iBAAiB,KAAKC,YAAY,kBAAkB;IACxD,OAAO,gBAAgB,cAAc,iBAAiB;KACpD,MAAM,WAAW,KAAKC,gBAAgB,eAAe,cAAc;KACnE,iBAAiB,SAAS;KAC1B,oBAAoB,IAAI,eAAe,SAAS,cAAc;IAChE;IACA,KAAKD,YAAY,gBAAgB;GACnC;EACF;EAMA,IAAI,QAAQ,KAAKA,YAAY,SAAS;EACtC,OAAO,OAAO,qBAAsB;GAClC,MAAM,oBAAoB,uBACtB,KAAKA,YAAY,OAAO,KACxB,wBACE,KAAKoB,qBAAqB,OAAO,CAAC,IAClC,KAAA;GACN,IAAI,yBACF,KAAKpB,YAAY,QAAQ;GAG3B,MAAM,EAAE,gBAAgB,OAAO,cAAc,KAAKC,gBAChD,MACA,KACF;GACA,QAAQ;GAER,IAAI,QAAQ,WACV,WAAW,IAAI,MAAM,cAAc;QAEnC,qBAAqB,IAAI,MAAM,cAAc;GAG/C,IAAI,yBACF,KAAKD,YAAY,OAAO,KAAK;GAE/B,UACE,QAAQ,2BACP,wBAAwB,0BACzB,sBAAsB,KAAA,KACtB,MAAM,OAAO,iBAAiB;GAChC,IAAI,SAAS;IACX;IACA,MAAM,YAAY,kBAAkB;IACpC,IAAI,cAAc,KAAA,GAChB;IAEF,IAAI,UAAU,MAAM,oBAAoB;KACtC,sBAAsB,UAAU;KAChC,8BAA8B;KAC9B;IACF;IACA,IAAI,YAAoC,KAAKA,YAAY,UAAU;IACnE,IAAI,uBACF,KACE,IAAI,YAAY,OAAO,GACvB,aAAa,UAAU,IACvB,aACA;KACA,YAAY,KAAKoB,qBAAqB,SAAS;KAC/C,IAAI,cAAc,KAAA,GAChB;KAEF,KAAKpB,YAAY,aAAa;IAChC;IAEF,IAAI,cAAc,KAAA,GAAW;KAC3B,yBAAyB,UAAU;KACnC;IACF,OAAO;KACL,OAAO,UAAU;KACjB,QAAQ;KACR,yBAAyB,UAAU;IACrC;IACA,UAAU;IACV;GACF;GACA;EACF;EAEA,IAAI,yBACF,IAAI,OAAO,oBACT,KAAKA,YAAY,OAAO,KAAK;OAE7B,KAAKA,YAAY,QAAQ;EAI7B,IAAI,WAAW,yBAAyB,wBAAwB,KAAA,GAAW;GACzE,KAAK,IAAI,YAAY,OAAO,GAAG,aAAa,WAAW,aAAa;IAClE,MAAM,gBAAgB,KAAKoB,qBAAqB,SAAS;IACzD,IAAI,kBAAkB,KAAA,GACpB;IAEF,KAAKpB,YAAY,aAAa;GAChC;GACA,KAAKc,wBAAwB,CAAC;GAC9B,KAAKC,6BAA6B;GAClC,KAAKC,yBAAyB,CAAC;EACjC;EAEA,IAAI,wBAAwB,KAAA,KAAa,oBAAoB,OAAO,GAClE,KAAKR,iBAAiB,qBAAqB,KAAKb,UAAU;EAG5D,IAAI,wBAAwB,KAAA,GAC1B,KAAKsB,4BACH,qBACA,mBACA,2BACF;OACK,IAAI,CAAC,WAAW,OAAO,WAAW;GACvC,MAAM,iBACJ,yBAAyB,cAAc,YACnC,qBACA,aAAa,aAAa,CAAC,uBACzB,aACA;GACR,KAAKA,4BACH,gBACA,mBACA,iBACF;EACF;EAEA,OAAO;CACT;CAEA,mBAAmB,aAAiC;EAClD,KAAKpB,eAAe;EACpB,KAAKwB,oBAAoB,WAAW;CACtC;CAEA,yBAA+B;EAC7B,KAAKC,0BAA0B;EAC/B,IAAI,KAAKC,YACP;EAEF,KAAKA,aAAa;EAClB,KAAKC,YAAY;EACjB,KAAKC,YAAY;EACjB,KAAKjC,6BAA6B;EAClC,KAAKkC,+BAA+B,KAAA;EACpC,KAAKC,+BAA+B;EACpC,KAAKb,wBAAwB,CAAC;EAC9B,KAAKC,6BAA6B;EAClC,KAAKC,yBAAyB,CAAC;EAC/B,KAAKE,uBAAuB;CAC9B;CAEA,0BAAgC;EAC9B,IAAI,KAAKK,cAAc,KAAKC,WAC1B;EAEF,IAAI,KAAKd,QACP,QAAQ,IAAI,iDAAiD,EAC3D,OAAO,KAAKnB,iBACd,CAAC;EAEH,KAAKiC,YAAY;CACnB;CAEA,2BAAiC;EAC/B,IACE,KAAKD,cACL,CAAC,KAAKC,aACN,KAAKtC,aAAa,KAAA,KAClB,KAAKuC,YAAY,GAEjB;EAEF,IAAI,KAAKf,QACP,QAAQ,IAAI,kDAAkD,EAC5D,OAAO,KAAKnB,iBACd,CAAC;EAEH,KAAKiC,YAAY;EACjB,KAAKI,qBAAqB,KAAKrC,gBAAgB;CACjD;CAEA,iBAAuB;EACrB,IACE,KAAKL,aAAa,KAAA,KAClB,CAAC,sBAAsB,KAAKD,cAAc,UAAU,KACpD,KAAKE,aACF,mBAAmB,CAAC,CACpB,SAAS,KAAKF,cAAc,UAAU,GAEzC,KAAKC,WAAW,KAAKC,aAAa,YAChC,KAAKF,cAAc,UACrB;CAEJ;CAEA,yBAA+B;EAC7B,IAAI,KAAK4C,4BACP;EAEF,WAAW,iBAAiB,WAAW,KAAKC,UAAU;EACtD,KAAKD,6BAA6B;CACpC;CAEA,yBAA+B;EAC7B,IAAI,CAAC,KAAKA,4BACR;EAEF,WAAW,oBAAoB,WAAW,KAAKC,UAAU;EACzD,KAAKD,6BAA6B;CACpC;CAEA,qBAAqB,OAAqB;EAExC,WAAW,YAAY;GACrB,MAAM;GACN,aAAa,KAAKvC;GAClB;EACF,CAAC;CACH;CAEA,4BACE,WACA,mBACA,oBAAoB,GACd;EACN,IAAI,sBAAsB,KAAKL,cAAc,UAAU,GACrD;EAGF,MAAM,QAAQ,EAAE,KAAKM;EAErB,IAAI,KAAKmB,QACP,QAAQ,IAAI,oDAAoD;GAC9D;GACA;GACA;GACA;EACF,CAAC;EAGH,KAAKa,aAAa;EAClB,KAAKC,YAAY;EACjB,KAAKC,YAAY;EACjB,IAAI,KAAKjC,8BAA8B,GACrC,KAAK8B,0BAA0B,KAAK,IAClC,KAAKA,yBACL,KAAK9B,0BACP;EAEF,KAAKA,6BAA6B;EAClC,KAAKkC,+BAA+B;EACpC,KAAKC,+BAA+B;EACpC,KAAKI,uBAAuB;EAC5B,KAAKH,qBAAqB,KAAK;CACjC;CAEA,uBAAuB,SAAuB;EAC5C,IAAI,KAAK1C,aAAa,KAAA,KAAa,KAAKc,YAAY,SAAS,SAC3D;EAIF,IAAI,CAAC,KAAKuB,YAAY;GACpB,IAAI,KAAK/B,8BAA8B,GACrC,KAAKA,6BAA6B,KAAK,IACrC,KAAKA,4BACL,OACF;QAEA,KAAK8B,0BAA0B,KAAK,IAClC,KAAKA,yBACL,OACF;GAEF;EACF;EAEA,MAAM,QAAQ,EAAE,KAAK/B;EACrB,KAAKgC,aAAa;EAClB,KAAKC,YAAY;EACjB,KAAKC,YAAY,KAAKzB,YAAY,SAAS;EAC3C,KAAKR,6BAA6B;EAClC,KAAK8B,0BAA0B;EAC/B,KAAKI,+BAA+B,KAAA;EACpC,KAAKC,+BAA+B;EACpC,KAAKI,uBAAuB;EAC5B,KAAKH,qBAAqB,KAAK;CACjC;CAEA,gBACE,MACA,OACgE;EAChE,MAAM,WAAW,KAAK3C,cAAc,YAAY,IAAI;EACpD,IAAI,SAAS,SAAS,KAAKqB,wBAAwB;GACjD,QAAQ,KACN,gBAAgB,KAAK,0BAA0B,SAAS,QAC1D;GACA,KAAK0B,2BAA2B,MAAM,IAAI;GAC1C,OAAO;IAAE,gBAAgB,CAAC;KAAC;KAAG;KAAI;IAAQ,CAAC;IAAG;GAAM;EACtD;EACA,IACE,KAAK9C,aAAa,KAAA,KAClB,aAAa,MACb,SAAS,KAAK,MAAM,IACpB;GACA,KAAK8C,2BAA2B,MAAM,IAAI;GAC1C,OAAO;IAAE,gBAAgB,CAAC;KAAC;KAAG;KAAI;IAAQ,CAAC;IAAG;GAAM;EACtD;EACA,MAAM,SAAS,aACb,KAAK9C,UACL,KAAKyB,WACL,UACA,OACA,qBACA,KAAKf,cACP;EACA,KAAKoC,2BAA2B,MAAM,OAAO,oBAAoB;EACjE,OAAO;GACL,gBAAgB,OAAO;GACvB,OAAO,OAAO;EAChB;CACF;CAEA,2BACE,MACA,QACM;EACN,IAAI,KAAKpC,gBACP,KAAKE,sBAAsB,QAAQ;CAEvC;CAIA,2BAA2B,QAAkC;EAC3D,MAAM,cACJ,OAAO,sBACN,CAAC;GAAC,OAAO;GAAW,OAAO;GAAS,OAAO;EAAS,CAAC;EACxD,MAAM,kBAAkB,OAAO,YAAY;EAE3C,IAAI,mBADqB,KAAKE,YAAY,SAAS,iBACV;GACvC,KAAKc,wBAAwB,KAAKd;GAClC,KAAKe,6BAA6B;GAClC,KAAKf,cAAc,KAAKA,YAAY,MAAM,GAAG,eAAe;EAC9D,OAAO;GACL,KAAKe,6BAA6B;GAClC,KAAKD,wBAAwB,KAAKd,YAAY,MAAM,eAAe;GACnE,KAAKA,YAAY,SAAS,KAAK,IAC7B,KAAKA,YAAY,QACjB,eACF;EACF;EACA,KAAKgB,yBAAyB;CAChC;CAEA,qBAAqB,MAAsC;EACzD,IAAI,eAAe;EACnB,KACE,IAAI,QAAQ,KAAKA,uBAAuB,SAAS,GACjD,SAAS,GACT,SACA;GACA,MAAM,CAAC,WAAW,SAAS,aACzB,KAAKA,uBAAuB;GAC9B,IAAI,cAAc,GAChB;GAEF,IAAI,eAAe,SACjB,gBAAgB;QACX,IAAI,eAAe,WACxB,OAAO,KAAKhB,YAAY;EAE5B;EACA,OACE,KAAKc,sBACH,eAAe,KAAKC,+BACjB,KAAKf,YAAY;CAE1B;CAEA,iBAAiB,OAAe,YAA8B;EAC5D,MAAM,eAAe,KAAK,IACxB,KAAK,IAAI,GAAG,KAAK,GACjB,KAAKf,cAAc,SACrB;EACA,IAAI,KAAKe,YAAY,SAAS,gBAAgB,KAAKd,aAAa,KAAA,GAC9D,OAAO;EAET,MAAM,YAAY,eAAe,KAAA,IAAY,IAAI,YAAY,IAAI;EACjE,IAAI,OAAO,KAAKc,YAAY,SAAS;EACrC,IAAI,QAAQ,KAAKA,YAAY,SAAS;EACtC,OAAO,OAAO,cAAc;GAC1B,KAAKA,YAAY,QAAQ;GACzB,MAAM,WAAW,KAAKf,cAAc,YAAY,IAAI;GACpD,IACE,SAAS,UAAU,KAAKqB,0BACxB,aAAa,MACb,SAAS,KAAK,MAAM,IACpB;IACA,MAAM,SAAS,aACb,KAAKpB,UACL,KAAKyB,WACL,UACA,OACA,qBACA,KAAKf,gBACL,KACF;IACA,KAAKoC,2BAA2B,MAAM,OAAO,oBAAoB;IACjE,QAAQ,OAAO;GACjB,OACE,KAAKA,2BAA2B,MAAM,IAAI;GAE5C;GACA,KAAKhC,YAAY,QAAQ;GACzB,IACE,eAAe,KAAA,KACf,YAAY,IAAI,IAAI,YAAY,YAEhC;EAEJ;EACA,OAAO,QAAQ;CACjB;CAEA,oBAAoB,OAAqB;EACvC,IACE,KAAKuB,cACL,KAAKC,aACL,KAAKtC,aAAa,KAAA,KAClB,UAAU,KAAKK,kBAEf;EAGF,KAAKH,mBAAmB;EAGxB,MAAM,WAAW,KAAKW,iBAAiB,KAAKP,4BAA4B,CAAC;EACzE,IAAI,KAAK+B,cAAc,KAAKC,aAAa,UAAU,KAAKjC,kBACtD;EAEF,IAAI,UAAU;GACZ,KAAK,uBAAuB;GAC5B;EACF;EACA,KAAKkC,YAAY,KAAKzB,YAAY,SAAS;EAC3C,KAAK4B,qBAAqB,KAAK;CACjC;CAEA,oBAAoB,OAAe;EACjC,IACE,KAAKL,cACL,KAAKC,aACL,KAAKtC,aAAa,KAAA,KAClB,UAAU,KAAKK,kBAEf;EAGF,KAAKH,mBAAmB;EAExB,MAAM,IAAI,YAAY,IAAI;EAC1B,MAAM,wBAAQ,IAAI,IAAqC;EACvD,MAAM,aAAa,KAAKH,cAAc;EACtC,MAAM,oBAAoB,KAAKyC;EAE/B,IAAI,OAAO,KAAKD;EAChB,IAAI,QAAQ,KAAKzB,YAAY,SAAS;EACtC,IAAI,UAAU;EACd,IAAI,oBAAoB,KAAK2B;EAC7B,IAAI,yBAAyB,oBAAoB,kBAAkB,GAAG;EACtE,OAAO,OAAO,aAAc;GAC1B,KAAK3B,YAAY,QAAQ;GAEzB,MAAM,oBACJ,2BAA2B,KAAA,IACvB,KAAKoB,qBAAqB,OAAO,CAAC,IAClC,KAAA;GACN,MAAM,WAAW,KAAKnC,cAAc,YAAY,IAAI;GACpD,IAAI,SAAS,SAAS,KAAKqB,wBAAwB;IACjD,QAAQ,KACN,gBAAgB,KAAK,0BAA0B,SAAS,QAC1D;IACA,MAAM,IAAI,MAAM,CAAC;KAAC;KAAG;KAAI;IAAQ,CAAC,CAAC;IACnC,KAAK0B,2BAA2B,MAAM,IAAI;GAC5C,OAAO,IAAI,aAAa,MAAM,SAAS,KAAK,MAAM,IAAI;IACpD,MAAM,IAAI,MAAM,CAAC;KAAC;KAAG;KAAI;IAAQ,CAAC,CAAC;IACnC,KAAKA,2BAA2B,MAAM,IAAI;GAC5C,OAAO;IACL,MAAM,MAAM,aACV,KAAK9C,UACL,KAAKyB,WACL,UACA,OACA,qBACA,KAAKf,cACP;IACA,MAAM,IAAI,MAAM,IAAI,cAAc;IAClC,KAAKoC,2BAA2B,MAAM,IAAI,oBAAoB;IAC9D,QAAQ,IAAI;GACd;GAEA,KAAKhC,YAAY,OAAO,KAAK;GAC7B,UACE,2BAA2B,KAAA,KAC3B,QAAQ,0BACR,sBAAsB,KAAA,KACtB,MAAM,OAAO,iBAAiB;GAChC;GACA,IAAI,SAAS;IACX;IACA,MAAM,YAAY,oBAAoB;IACtC,IAAI,cAAc,KAAA,GAChB;IAEF,yBAAyB,UAAU;IACnC,IAAI,KAAKA,YAAY,UAAU,QAAQ,KAAA,GACrC,UAAU;SACL;KACL,OAAO,UAAU;KACjB,QAAQ,KAAKA,YAAY,SAAS;KAClC,UAAU;KACV;IACF;GACF;GAGA,IAAI,YAAY,IAAI,IAAI,IAAI,GAC1B;EAEJ;EAEA,KAAKQ,iBAAiB,OAAO,KAAKb,UAAU;EAC5C,IAAI,KAAK4B,cAAc,KAAKC,aAAa,UAAU,KAAKjC,kBACtD;EAGF,IAAI,WAAW,QAAQ,YAAY;GACjC,MAAM,yBAAyB,KAAK+B;GACpC,KAAK,uBAAuB;GAC5B,IAAI,0BAA0B,GAC5B,KAAKjC,uBAAuB,sBAAsB;GAEpD;EACF;EAEA,KAAKoC,YAAY;EACjB,KAAKE,+BAA+B;EACpC,KAAKC,qBAAqB,KAAK;CACjC;AACF;AAEA,SAAS,aACP,SACA,UACA,UACA,YACA,WACA,8BAA8B,MAC9B,gBAAgB,MAKhB;CACA,MAAM,SAAS,QAAQ,cAAc,UAAU,YAAY,SAAS;CACpE,IAAI,OAAO,cACT,QAAQ,KACN,oDAAoD,SAAS,UAAU,GAAG,GAAG,GAC/E;CAEF,MAAM,YAAY,OAAO;CACzB,MAAM,eAAe,UAAU,SAAS;CACxC,MAAM,iBAA0C,CAAC;CACjD,MAAM,uBAA2C,CAAC;CAClD,IAAI,CAAC,iBAAiB,CAAC,6BACrB,OAAO;EACL,WAAW,OAAO;EAClB;EACA;CACF;CAEF,KAAK,IAAI,IAAI,GAAG,IAAI,cAAc,KAAK;EACrC,MAAM,SAAS,UAAU,IAAI;EAC7B,MAAM,aACJ,IAAI,IAAI,eAAe,UAAU,IAAI,IAAI,KAAK,SAAS;EACzD,IAAI,WAAW,YAEb;EAEF,MAAM,WAAW,UAAU,IAAI,IAAI;EACnC,IAAI,eAAe;GACjB,MAAM,KAAK,qBAAqB,cAAc,QAAQ;GACtD,eAAe,KAAK;IAClB;IACA,SAAS;IACT,SAAS,MAAM,QAAQ,UAAU;GACnC,CAAC;EACH;EACA,IACE,+BACA,qBAAqB,aAAa,QAAQ,IAAI,GAE9C,qBAAqB,KAAK,CAAC,QAAQ,UAAU,CAAC;CAElD;CACA,OAAO;EACL,WAAW,OAAO;EAClB;EACA;CACF;AACF;AAEA,SAAgB,iBACd,QAC0B;CAC1B,OAAO,OAAO,KAAK,CAAC,MAAM,IAAI,iBAAiB;EAC7C,IAAI,SAAS,KAAK,OAAO,IAAI;GAC3B,IAAI,gBAAgB,IAClB,OAAO,EAAE,IAAI;GAEf,OAAO;EACT;EACA,OAAO,EAAE,QAAQ;GACf,SAAS,EACP,MAAM,KAAK,SAAS,EACtB;GACA,OAAO,SAAS,GAAG;GACN;EACf,CAAC;CACH,CAAC;AACH;AAGA,SAAS,sBAAsB,YAA6B;CAC1D,OAAO,eAAe,UAAU,eAAe;AACjD"}
|
|
1
|
+
{"version":3,"file":"tokenizer.js","names":["#isCleanedUp","#textDocument","#grammar","#highlighter","#ensureActiveTheme","#scheduleStatePrebuild","#tokenizerId","#backgroundJobId","#backgroundPrebuildEndLine","#backgroundPrebuild","#backgroundTokenize","#themeType","#matchBrackets","#ensureGrammar","#bracketIgnoredRanges","#buildStateStack","#stateStack","#tokenizeLineAt","#mediaQueryList","#resolveSystemThemeType","#emitThemeChange","#disposes","#tokenizeMaxLineLength","#setStyle","#onDeferTokenize","#onThemeChange","#debug","#colorMap","#setTheme","#themeName","#comparisonStateStack","#comparisonStateStackStart","#comparisonLineChanges","#scheduleBackgroundTokenize","#detachMessageListener","#shiftComparisonStateStack","#getPreviousEndState","#prebuildStateStack","#pendingPrebuildEndLine","#isStopped","#isPaused","#lastLine","#backgroundChangedLineRanges","#backgroundChangedRangeIndex","#postTokenizeMessage","#isMessageListenerAttached","#onMessage","#attachMessageListener","#cacheBracketIgnoredRanges"],"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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"}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { ChangeTypes, DiffLineAnnotation, FileContents, FileDiffMetadata, Hunk, LineAnnotation, SelectionSide } from "../types.js";
|
|
2
|
+
import { TextDocument } from "./textDocument.js";
|
|
3
|
+
import { Editor, EditorOptions } from "./editor.js";
|
|
4
|
+
|
|
5
|
+
//#region src/editor/types.d.ts
|
|
6
|
+
/** FileDiff baseline and hunk state needed to resume an editing session. */
|
|
7
|
+
interface RetainedDiffSessionSnapshot {
|
|
8
|
+
oldFile: {
|
|
9
|
+
name: string;
|
|
10
|
+
lines: string[];
|
|
11
|
+
} | null;
|
|
12
|
+
type: ChangeTypes;
|
|
13
|
+
hunks: Hunk[];
|
|
14
|
+
}
|
|
15
|
+
/** @internal Current diff state and whether the document changed while editing. */
|
|
16
|
+
interface CapturedDiffSessionState {
|
|
17
|
+
diffSession: RetainedDiffSessionSnapshot;
|
|
18
|
+
hasChanges: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* An edit-completion handler's decision: `'accept'` installs the completed
|
|
22
|
+
* value the event carries, `'reject'` restores the external input. The event
|
|
23
|
+
* is frozen, so re-key the accepted value in place (`event.file.cacheKey =
|
|
24
|
+
* '…'`) before returning `'accept'`.
|
|
25
|
+
*/
|
|
26
|
+
type EditCompletionDecision = 'accept' | 'reject';
|
|
27
|
+
interface EditorActiveLineOptions {
|
|
28
|
+
lineNumberOnly?: boolean;
|
|
29
|
+
side?: SelectionSide;
|
|
30
|
+
}
|
|
31
|
+
type EditorType = 'file' | 'file-diff';
|
|
32
|
+
/** Creates an editor whose editor type matches the supplied options. */
|
|
33
|
+
type EditorFactory<LAnnotation, Caret> = <EType extends EditorType>(editorType: EType, options: EditorOptions<EType, LAnnotation, Caret>, editStateKey?: string) => Editor<EType, LAnnotation, Caret>;
|
|
34
|
+
/**
|
|
35
|
+
* Position in a text document expressed as zero-based line and character offset.
|
|
36
|
+
* The offsets are based on a UTF-16 string representation. So a string of the form
|
|
37
|
+
* `a𐐀b` the character offset of the character `a` is 0, the character offset of `𐐀`
|
|
38
|
+
* is 1 and the character offset of b is 3 since `𐐀` is represented using two code
|
|
39
|
+
* units in UTF-16.
|
|
40
|
+
*
|
|
41
|
+
* Positions are line end character agnostic. So you can not specify a position that
|
|
42
|
+
* denotes `\r|\n` or `\n|` where `|` represents the character offset.
|
|
43
|
+
*/
|
|
44
|
+
interface Position {
|
|
45
|
+
/**
|
|
46
|
+
* Line position in a document (zero-based).
|
|
47
|
+
*
|
|
48
|
+
* If a line number is greater than the number of lines in a document, it
|
|
49
|
+
* defaults back to the number of lines in the document.
|
|
50
|
+
* If a line number is negative, it defaults to 0.
|
|
51
|
+
*
|
|
52
|
+
* The above two properties are implementation specific.
|
|
53
|
+
*/
|
|
54
|
+
readonly line: number;
|
|
55
|
+
/**
|
|
56
|
+
* Character offset on a line in a document (zero-based).
|
|
57
|
+
*
|
|
58
|
+
* The meaning of this offset is determined by the negotiated
|
|
59
|
+
* `PositionEncodingKind`.
|
|
60
|
+
*
|
|
61
|
+
* If the character value is greater than the line length it defaults back
|
|
62
|
+
* to the line length. This property is implementation specific.
|
|
63
|
+
*/
|
|
64
|
+
readonly character: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A range in a text document expressed as (zero-based) start and end positions.
|
|
68
|
+
*
|
|
69
|
+
* If you want to specify a range that contains a line including the line ending
|
|
70
|
+
* character(s) then use an end position denoting the start of the next line.
|
|
71
|
+
* For example:
|
|
72
|
+
* ```ts
|
|
73
|
+
* {
|
|
74
|
+
* start: { line: 5, character: 23 }
|
|
75
|
+
* end : { line 6, character : 0 }
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
interface Range {
|
|
80
|
+
/**
|
|
81
|
+
* The range's start position.
|
|
82
|
+
*/
|
|
83
|
+
readonly start: Position;
|
|
84
|
+
/**
|
|
85
|
+
* The range's end position.
|
|
86
|
+
*/
|
|
87
|
+
readonly end: Position;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* A text edit applicable to a text document.
|
|
91
|
+
*/
|
|
92
|
+
interface TextEdit {
|
|
93
|
+
/**
|
|
94
|
+
* The range of the text document to be manipulated. To insert
|
|
95
|
+
* text into a document create a range where start === end.
|
|
96
|
+
*/
|
|
97
|
+
readonly range: Range;
|
|
98
|
+
/**
|
|
99
|
+
* The string to be inserted. For delete operations use an
|
|
100
|
+
* empty string.
|
|
101
|
+
*/
|
|
102
|
+
readonly newText: string;
|
|
103
|
+
}
|
|
104
|
+
/** Different with `TextEdit`, the range has been resolved to offsets. */
|
|
105
|
+
interface ResolvedTextEdit {
|
|
106
|
+
/** The start offset of the text change. */
|
|
107
|
+
readonly start: number;
|
|
108
|
+
/** The end offset of the text change. */
|
|
109
|
+
readonly end: number;
|
|
110
|
+
/** The string to be inserted. For delete operations use an empty string. */
|
|
111
|
+
readonly text: string;
|
|
112
|
+
}
|
|
113
|
+
/** A normalized text change reported by the editor. */
|
|
114
|
+
interface EditorChange extends ResolvedTextEdit {
|
|
115
|
+
/** The replaced range in the document before the change. */
|
|
116
|
+
range: Range;
|
|
117
|
+
}
|
|
118
|
+
type EditorLineAnnotation<EType extends EditorType = EditorType, LAnnotation = unknown> = EType extends 'file' ? LineAnnotation<LAnnotation> & {
|
|
119
|
+
side?: never;
|
|
120
|
+
} : DiffLineAnnotation<LAnnotation>;
|
|
121
|
+
/** The document and normalized edits reported after an editor change. */
|
|
122
|
+
type EditorChangeEvent<EType extends EditorType, LAnnotation, Caret> = EType extends EditorType ? {
|
|
123
|
+
changes: EditorChange[];
|
|
124
|
+
file: FileContents;
|
|
125
|
+
editor: Editor<EType, LAnnotation, Caret>;
|
|
126
|
+
lineAnnotations?: EditorLineAnnotation<EType, LAnnotation>[];
|
|
127
|
+
} : never;
|
|
128
|
+
/**
|
|
129
|
+
* The direction of a selection.
|
|
130
|
+
* -1: backward
|
|
131
|
+
* 0: none
|
|
132
|
+
* 1: forward
|
|
133
|
+
*/
|
|
134
|
+
type SelectionDirection = -1 | 0 | 1;
|
|
135
|
+
interface EditorSelection extends Range {
|
|
136
|
+
direction: SelectionDirection;
|
|
137
|
+
}
|
|
138
|
+
/** Visual metadata shared by a remote caret and its optional highlight. */
|
|
139
|
+
interface CaretMetadata {
|
|
140
|
+
/** CSS color used for the caret and its derived highlight tint. */
|
|
141
|
+
color: string;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* A non-editable, externally owned selection. This follows the browser's
|
|
145
|
+
* anchor/focus model: matching positions render a caret, and differing
|
|
146
|
+
* positions render a highlighted selection with its caret at `focus`.
|
|
147
|
+
*/
|
|
148
|
+
interface EditorCaret<T> {
|
|
149
|
+
anchor: Position;
|
|
150
|
+
focus: Position;
|
|
151
|
+
metadata: T & CaretMetadata;
|
|
152
|
+
}
|
|
153
|
+
interface EditorViewportState {
|
|
154
|
+
/** Horizontal position owned by the current editable code scroller. */
|
|
155
|
+
scrollLeft: number;
|
|
156
|
+
/** Vertical position of the editor viewport. */
|
|
157
|
+
scrollTop?: number;
|
|
158
|
+
}
|
|
159
|
+
interface EditorViewState {
|
|
160
|
+
selections?: EditorSelection[];
|
|
161
|
+
view?: EditorViewportState;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* `onEditComplete` event argument when a file edit session ends.
|
|
165
|
+
*
|
|
166
|
+
* `file` is a fresh FileContents with the final contents and no `cacheKey` set;
|
|
167
|
+
* accepting installs it.
|
|
168
|
+
*
|
|
169
|
+
* `originalFile` is the last `file` the component was given externally; a
|
|
170
|
+
* revert restores it.
|
|
171
|
+
*
|
|
172
|
+
* `lineAnnotations` is the completed annotation collection, potentially
|
|
173
|
+
* modified based on the edit changes to keep annotations aligned to their
|
|
174
|
+
* intended targets.
|
|
175
|
+
*
|
|
176
|
+
* `originalLineAnnotations` is the last collection provided to the component
|
|
177
|
+
* externally, which a revert keeps.
|
|
178
|
+
*/
|
|
179
|
+
interface FileEditCompleteEvent<LAnnotation, Caret> {
|
|
180
|
+
file: FileContents;
|
|
181
|
+
editor: Editor<'file', LAnnotation, Caret>;
|
|
182
|
+
lineAnnotations: LineAnnotation<LAnnotation>[] | undefined;
|
|
183
|
+
originalFile: FileContents;
|
|
184
|
+
originalLineAnnotations: LineAnnotation<LAnnotation>[];
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* `onEditComplete` event argument when a diff edit session ends.
|
|
188
|
+
*
|
|
189
|
+
* `fileDiff` is a freshly computed diff of the final contents with no
|
|
190
|
+
* `cacheKey` set; accepting installs it.
|
|
191
|
+
*
|
|
192
|
+
* `originalFileDiff` is the last `fileDiff` the component was given externally;
|
|
193
|
+
* a revert restores it.
|
|
194
|
+
*
|
|
195
|
+
* `oldFile`/`newFile` are the completed contents as a file pair, for updating
|
|
196
|
+
* file-pair or patch inputs. `null` marks the absent side of an added file (a
|
|
197
|
+
* deleted file cannot be edited).
|
|
198
|
+
*
|
|
199
|
+
* `lineAnnotations` is the completed annotation collection, potentially
|
|
200
|
+
* modified based on the edit changes to keep annotations aligned to their
|
|
201
|
+
* intended targets.
|
|
202
|
+
*
|
|
203
|
+
* `originalLineAnnotations` is the last collection provided to the component
|
|
204
|
+
* externally, which a revert keeps.
|
|
205
|
+
*/
|
|
206
|
+
interface FileDiffEditCompleteEvent<LAnnotation, Caret> {
|
|
207
|
+
fileDiff: FileDiffMetadata;
|
|
208
|
+
editor: Editor<'file-diff', LAnnotation, Caret>;
|
|
209
|
+
originalFileDiff: FileDiffMetadata;
|
|
210
|
+
oldFile: FileContents | null;
|
|
211
|
+
newFile: FileContents | null;
|
|
212
|
+
lineAnnotations: DiffLineAnnotation<LAnnotation>[] | undefined;
|
|
213
|
+
originalLineAnnotations: DiffLineAnnotation<LAnnotation>[];
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* The exact frozen file or diff completion event observed by the editor before
|
|
217
|
+
* the corresponding component completion callback.
|
|
218
|
+
*/
|
|
219
|
+
type EditorEditCompleteEvent<EType extends EditorType, LAnnotation, Caret> = EType extends 'file' ? FileEditCompleteEvent<LAnnotation, Caret> : FileDiffEditCompleteEvent<LAnnotation, Caret>;
|
|
220
|
+
type EditHistoryCoalescingMode = 'insert' | 'backspace' | 'delete';
|
|
221
|
+
/** One reversible document transaction. */
|
|
222
|
+
interface EditHistoryEntry<EType extends EditorType, LAnnotation = unknown> {
|
|
223
|
+
forwardEdits: ResolvedTextEdit[];
|
|
224
|
+
inverseEdits: ResolvedTextEdit[];
|
|
225
|
+
versionBefore: number;
|
|
226
|
+
versionAfter: number;
|
|
227
|
+
selectionsBefore?: EditorSelection[];
|
|
228
|
+
selectionsAfter?: EditorSelection[];
|
|
229
|
+
lineAnnotationsBefore?: EditorLineAnnotation<EType, LAnnotation>[];
|
|
230
|
+
lineAnnotationsAfter?: EditorLineAnnotation<EType, LAnnotation>[];
|
|
231
|
+
coalescingMode?: EditHistoryCoalescingMode;
|
|
232
|
+
undoBoundary?: boolean;
|
|
233
|
+
}
|
|
234
|
+
/** Undo and redo history for a document. */
|
|
235
|
+
interface EditHistoryState<EType extends EditorType, LAnnotation = unknown> {
|
|
236
|
+
undoStack: EditHistoryEntry<EType, LAnnotation>[];
|
|
237
|
+
redoStack: EditHistoryEntry<EType, LAnnotation>[];
|
|
238
|
+
maxEntries: number;
|
|
239
|
+
canCoalesce: boolean;
|
|
240
|
+
}
|
|
241
|
+
interface EditStateBase<EType extends EditorType, LAnnotation> {
|
|
242
|
+
document: TextDocument<EType, LAnnotation>;
|
|
243
|
+
fileInfo: Pick<FileContents, 'name' | 'lang'>;
|
|
244
|
+
editor: EditorViewState;
|
|
245
|
+
}
|
|
246
|
+
interface FileEditState<LAnnotation = unknown> extends EditStateBase<'file', LAnnotation> {
|
|
247
|
+
type: 'file';
|
|
248
|
+
diffSession?: never;
|
|
249
|
+
}
|
|
250
|
+
interface FileDiffEditState<LAnnotation = unknown> extends EditStateBase<'file-diff', LAnnotation> {
|
|
251
|
+
type: 'file-diff';
|
|
252
|
+
diffSession: RetainedDiffSessionSnapshot;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* The editor-owned objects that make up a complete session. This state is
|
|
256
|
+
* transferred by reference when supplied as `initialState`.
|
|
257
|
+
*/
|
|
258
|
+
type EditState<EType extends EditorType = EditorType, LAnnotation = unknown> = EType extends 'file' ? FileEditState<LAnnotation> : FileDiffEditState<LAnnotation>;
|
|
259
|
+
/** State supplied to a new editor, completed from the attached component. */
|
|
260
|
+
type EditorInitialState<EType extends EditorType = EditorType, LAnnotation = unknown> = EType extends 'file' ? {
|
|
261
|
+
type: 'file';
|
|
262
|
+
} & Partial<Omit<FileEditState<LAnnotation>, 'type'>> : {
|
|
263
|
+
type: 'file-diff';
|
|
264
|
+
} & Partial<Omit<FileDiffEditState<LAnnotation>, 'type'>>;
|
|
265
|
+
//#endregion
|
|
266
|
+
export { CapturedDiffSessionState, CaretMetadata, EditCompletionDecision, EditHistoryCoalescingMode, EditHistoryEntry, EditHistoryState, EditState, EditorActiveLineOptions, EditorCaret, EditorChange, EditorChangeEvent, EditorEditCompleteEvent, EditorFactory, EditorInitialState, EditorLineAnnotation, EditorSelection, EditorType, EditorViewState, EditorViewportState, FileDiffEditCompleteEvent, FileDiffEditState, FileEditCompleteEvent, FileEditState, Position, Range, ResolvedTextEdit, RetainedDiffSessionSnapshot, SelectionDirection, TextEdit };
|
|
267
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/editor/types.ts"],"mappings":"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"}
|
|
File without changes
|
package/dist/editor/utils.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ declare function h<K extends keyof HTMLElementTagNameMap>(tagName: K, props?: {
|
|
|
4
4
|
dataset?: DOMStringMap | string[] | string;
|
|
5
5
|
children?: (Node | string)[];
|
|
6
6
|
} & Partial<Omit<HTMLElementTagNameMap[K], 'style' | 'dataset' | 'children'>>, parent?: Element | ShadowRoot | DocumentFragment): HTMLElementTagNameMap[K];
|
|
7
|
+
declare function isPromise<T>(value: T | Promise<T>): value is Promise<T>;
|
|
7
8
|
declare function addEventListener<K extends keyof HTMLElementEventMap>(el: HTMLElement, event: K, listener: (this: HTMLElement, evt: HTMLElementEventMap[K]) => void, options?: AddEventListenerOptions): () => void;
|
|
8
9
|
declare function addEventListener<K extends keyof DocumentEventMap>(el: Document, event: K, listener: (this: Document, evt: DocumentEventMap[K]) => void, options?: AddEventListenerOptions): () => void;
|
|
9
10
|
declare function addEventListener<K extends keyof WindowEventMap>(el: Window, event: K, listener: (this: Window, evt: WindowEventMap[K]) => void, options?: AddEventListenerOptions): () => void;
|
|
@@ -18,5 +19,5 @@ declare function createSegmenter(options: Intl.SegmenterOptions): Intl.Segmenter
|
|
|
18
19
|
declare function getGraphemeSegmenter(): Intl.Segmenter | undefined;
|
|
19
20
|
declare function lookupScrollContainer(element: HTMLElement): HTMLElement | Document;
|
|
20
21
|
//#endregion
|
|
21
|
-
export { addEventListener, clampDomOffset, createSegmenter, debounce, endsWithLineBreak, extend, getGraphemeSegmenter, getLineNumberAttr, h, lookupScrollContainer, round };
|
|
22
|
+
export { addEventListener, clampDomOffset, createSegmenter, debounce, endsWithLineBreak, extend, getGraphemeSegmenter, getLineNumberAttr, h, isPromise, lookupScrollContainer, round };
|
|
22
23
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","names":[],"sources":["../../src/editor/utils.ts"],"mappings":";iBAAgB,CAAA,iBAAkB,qBAAA,EAChC,OAAA,EAAS,CAAA,EACT,KAAA;EACE,KAAA,YAAiB,OAAA,CAAQ,mBAAA;EACzB,OAAA,GAAU,YAAA;EACV,QAAA,IAAY,IAAA;AAAA,IACV,OAAA,CAAQ,IAAA,CAAK,qBAAA,CAAsB,CAAA,uCACvC,MAAA,GAAS,OAAA,GAAU,UAAA,GAAa,gBAAA,GAC/B,qBAAA,CAAsB,CAAA;AAAA,iBA+BT,gBAAA,iBAAiC,mBAAA,EAC/C,EAAA,EAAI,WAAA,EACJ,KAAA,EAAO,CAAA,EACP,QAAA,GAAW,IAAA,EAAM,WAAA,EAAa,GAAA,EAAK,mBAAA,CAAoB,CAAA,YACvD,OAAA,GAAU,uBAAA;AAAA,iBAEI,gBAAA,iBAAiC,gBAAA,EAC/C,EAAA,EAAI,QAAA,EACJ,KAAA,EAAO,CAAA,EACP,QAAA,GAAW,IAAA,EAAM,QAAA,EAAU,GAAA,EAAK,gBAAA,CAAiB,CAAA,YACjD,OAAA,GAAU,uBAAA;AAAA,iBAEI,gBAAA,iBAAiC,cAAA,EAC/C,EAAA,EAAI,MAAA,EACJ,KAAA,EAAO,CAAA,EACP,QAAA,GAAW,IAAA,EAAM,MAAA,EAAQ,GAAA,EAAK,cAAA,CAAe,CAAA,YAC7C,OAAA,GAAU,uBAAA;AAAA,iBAEI,gBAAA,iBAAiC,sBAAA,EAC/C,EAAA,EAAI,cAAA,EACJ,KAAA,EAAO,CAAA,EACP,QAAA,GAAW,IAAA,EAAM,cAAA,EAAgB,GAAA,EAAK,sBAAA,CAAuB,CAAA,YAC7D,OAAA,GAAU,uBAAA;AAAA,iBAYI,iBAAA,CACd,EAAA,EAAI,WAAW,EACf,GAAA;AAAA,iBAac,cAAA,CAAe,IAAA,EAAM,IAAI,EAAE,MAAA;AAAA,iBAW3B,MAAA,mBAAyB,GAAA,EAAK,CAAA,EAAG,KAAA,EAAO,OAAA,CAAQ,CAAA,IAAK,CAAA;AAAA,iBAKrD,QAAA,eAAuB,IAAA,kBACrC,IAAA,EAAM,CAAA,EACN,IAAA,eACK,IAAA,EAAM,UAAA,CAAW,CAAA;AAAA,iBAQR,KAAA,CAAM,KAAA,UAAe,SAAwB;AAAA,iBAI7C,iBAAA,CAAkB,IAAY;AAAA,iBAM9B,eAAA,CACd,OAAA,EAAS,IAAA,CAAK,gBAAA,GACb,IAAA,CAAK,SAAS;AAAA,iBAYD,oBAAA,IAAwB,IAAA,CAAK,SAAS;AAAA,iBAStC,qBAAA,CACd,OAAA,EAAS,WAAA,GACR,WAAA,GAAc,QAAA"}
|
|
1
|
+
{"version":3,"file":"utils.d.ts","names":[],"sources":["../../src/editor/utils.ts"],"mappings":";iBAAgB,CAAA,iBAAkB,qBAAA,EAChC,OAAA,EAAS,CAAA,EACT,KAAA;EACE,KAAA,YAAiB,OAAA,CAAQ,mBAAA;EACzB,OAAA,GAAU,YAAA;EACV,QAAA,IAAY,IAAA;AAAA,IACV,OAAA,CAAQ,IAAA,CAAK,qBAAA,CAAsB,CAAA,uCACvC,MAAA,GAAS,OAAA,GAAU,UAAA,GAAa,gBAAA,GAC/B,qBAAA,CAAsB,CAAA;AAAA,iBA+BT,SAAA,IAAa,KAAA,EAAO,CAAA,GAAI,OAAA,CAAQ,CAAA,IAAK,KAAA,IAAS,OAAA,CAAQ,CAAA;AAAA,iBAStD,gBAAA,iBAAiC,mBAAA,EAC/C,EAAA,EAAI,WAAA,EACJ,KAAA,EAAO,CAAA,EACP,QAAA,GAAW,IAAA,EAAM,WAAA,EAAa,GAAA,EAAK,mBAAA,CAAoB,CAAA,YACvD,OAAA,GAAU,uBAAA;AAAA,iBAEI,gBAAA,iBAAiC,gBAAA,EAC/C,EAAA,EAAI,QAAA,EACJ,KAAA,EAAO,CAAA,EACP,QAAA,GAAW,IAAA,EAAM,QAAA,EAAU,GAAA,EAAK,gBAAA,CAAiB,CAAA,YACjD,OAAA,GAAU,uBAAA;AAAA,iBAEI,gBAAA,iBAAiC,cAAA,EAC/C,EAAA,EAAI,MAAA,EACJ,KAAA,EAAO,CAAA,EACP,QAAA,GAAW,IAAA,EAAM,MAAA,EAAQ,GAAA,EAAK,cAAA,CAAe,CAAA,YAC7C,OAAA,GAAU,uBAAA;AAAA,iBAEI,gBAAA,iBAAiC,sBAAA,EAC/C,EAAA,EAAI,cAAA,EACJ,KAAA,EAAO,CAAA,EACP,QAAA,GAAW,IAAA,EAAM,cAAA,EAAgB,GAAA,EAAK,sBAAA,CAAuB,CAAA,YAC7D,OAAA,GAAU,uBAAA;AAAA,iBAYI,iBAAA,CACd,EAAA,EAAI,WAAW,EACf,GAAA;AAAA,iBAac,cAAA,CAAe,IAAA,EAAM,IAAI,EAAE,MAAA;AAAA,iBAW3B,MAAA,mBAAyB,GAAA,EAAK,CAAA,EAAG,KAAA,EAAO,OAAA,CAAQ,CAAA,IAAK,CAAA;AAAA,iBAKrD,QAAA,eAAuB,IAAA,kBACrC,IAAA,EAAM,CAAA,EACN,IAAA,eACK,IAAA,EAAM,UAAA,CAAW,CAAA;AAAA,iBAQR,KAAA,CAAM,KAAA,UAAe,SAAwB;AAAA,iBAI7C,iBAAA,CAAkB,IAAY;AAAA,iBAM9B,eAAA,CACd,OAAA,EAAS,IAAA,CAAK,gBAAA,GACb,IAAA,CAAK,SAAS;AAAA,iBAYD,oBAAA,IAAwB,IAAA,CAAK,SAAS;AAAA,iBAStC,qBAAA,CACd,OAAA,EAAS,WAAA,GACR,WAAA,GAAc,QAAA"}
|
package/dist/editor/utils.js
CHANGED
|
@@ -14,6 +14,9 @@ function h(tagName, props, parent) {
|
|
|
14
14
|
if (parent !== void 0) parent.appendChild(el);
|
|
15
15
|
return el;
|
|
16
16
|
}
|
|
17
|
+
function isPromise(value) {
|
|
18
|
+
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
19
|
+
}
|
|
17
20
|
function addEventListener(el, event, listener, options) {
|
|
18
21
|
el.addEventListener(event, listener, options);
|
|
19
22
|
return () => el.removeEventListener(event, listener, options);
|
|
@@ -73,6 +76,6 @@ function lookupScrollContainer(element) {
|
|
|
73
76
|
return ownerDocument;
|
|
74
77
|
}
|
|
75
78
|
//#endregion
|
|
76
|
-
export { addEventListener, clampDomOffset, createSegmenter, debounce, endsWithLineBreak, extend, getGraphemeSegmenter, getLineNumberAttr, h, lookupScrollContainer, round };
|
|
79
|
+
export { addEventListener, clampDomOffset, createSegmenter, debounce, endsWithLineBreak, extend, getGraphemeSegmenter, getLineNumberAttr, h, isPromise, lookupScrollContainer, round };
|
|
77
80
|
|
|
78
81
|
//# sourceMappingURL=utils.js.map
|