@pierre/diffs 1.3.0-beta.2 → 1.3.0-beta.4
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 +4 -0
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +38 -0
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +2 -2
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +13 -13
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +7 -4
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +57 -47
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +1 -1
- package/dist/components/VirtualizedFile.d.ts +1 -1
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +13 -4
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +2 -1
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +36 -42
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/Virtualizer.js +5 -3
- package/dist/components/Virtualizer.js.map +1 -1
- package/dist/components/VirtulizerDevelopment.d.ts.map +1 -1
- package/dist/editor/editStack.d.ts +1 -1
- package/dist/editor/editor.d.ts +14 -6
- package/dist/editor/editor.d.ts.map +1 -1
- package/dist/editor/editor.js +745 -553
- package/dist/editor/editor.js.map +1 -1
- package/dist/editor/editor2.js +6 -0
- package/dist/editor/editor2.js.map +1 -0
- package/dist/editor/lineAnnotations.d.ts +2 -1
- package/dist/editor/lineAnnotations.d.ts.map +1 -1
- package/dist/editor/lineAnnotations.js +111 -1
- package/dist/editor/lineAnnotations.js.map +1 -1
- package/dist/editor/marker.d.ts +33 -0
- package/dist/editor/marker.d.ts.map +1 -0
- package/dist/editor/marker.js +185 -0
- package/dist/editor/marker.js.map +1 -0
- package/dist/editor/pieceTable.d.ts +3 -3
- package/dist/editor/pieceTable.d.ts.map +1 -1
- package/dist/editor/pieceTable.js +44 -33
- package/dist/editor/pieceTable.js.map +1 -1
- package/dist/editor/searchPanel.d.ts +6 -7
- package/dist/editor/searchPanel.d.ts.map +1 -1
- package/dist/editor/searchPanel.js +103 -138
- package/dist/editor/searchPanel.js.map +1 -1
- package/dist/editor/selection.d.ts +19 -3
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +196 -39
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/{quickEdit.d.ts → selectionAction.d.ts} +8 -8
- package/dist/editor/selectionAction.d.ts.map +1 -0
- package/dist/editor/{quickEdit.js → selectionAction.js} +19 -21
- package/dist/editor/selectionAction.js.map +1 -0
- package/dist/editor/sprite.d.ts +8 -0
- package/dist/editor/sprite.d.ts.map +1 -0
- package/dist/editor/sprite.js +45 -0
- package/dist/editor/sprite.js.map +1 -0
- package/dist/editor/textDocument.d.ts +5 -5
- package/dist/editor/textDocument.d.ts.map +1 -1
- package/dist/editor/textDocument.js +9 -9
- package/dist/editor/textDocument.js.map +1 -1
- package/dist/editor/textMeasure.js +3 -3
- package/dist/editor/textMeasure.js.map +1 -1
- package/dist/editor/tokenzier.d.ts +6 -2
- package/dist/editor/tokenzier.d.ts.map +1 -1
- package/dist/editor/tokenzier.js +135 -85
- package/dist/editor/tokenzier.js.map +1 -1
- package/dist/editor/utils.d.ts +3 -1
- package/dist/editor/utils.d.ts.map +1 -1
- package/dist/editor/utils.js +16 -1
- package/dist/editor/utils.js.map +1 -1
- package/dist/highlighter/shared_highlighter.js +3 -29
- package/dist/highlighter/shared_highlighter.js.map +1 -1
- package/dist/highlighter/themes/attachResolvedThemes.js +4 -3
- package/dist/highlighter/themes/attachResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/cleanUpResolvedThemes.js +3 -2
- package/dist/highlighter/themes/cleanUpResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/constants.d.ts +1 -7
- package/dist/highlighter/themes/constants.d.ts.map +1 -1
- package/dist/highlighter/themes/constants.js +1 -4
- package/dist/highlighter/themes/constants.js.map +1 -1
- package/dist/highlighter/themes/getResolvedOrResolveTheme.js +2 -2
- package/dist/highlighter/themes/getResolvedOrResolveTheme.js.map +1 -1
- package/dist/highlighter/themes/getResolvedThemes.js +2 -8
- package/dist/highlighter/themes/getResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/hasResolvedThemes.js +2 -3
- package/dist/highlighter/themes/hasResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/registerCustomCSSVariableTheme.js +1 -1
- package/dist/highlighter/themes/registerCustomTheme.d.ts +5 -3
- package/dist/highlighter/themes/registerCustomTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/registerCustomTheme.js +15 -5
- package/dist/highlighter/themes/registerCustomTheme.js.map +1 -1
- package/dist/highlighter/themes/resolveTheme.js +6 -27
- package/dist/highlighter/themes/resolveTheme.js.map +1 -1
- package/dist/highlighter/themes/resolveThemes.js +5 -12
- package/dist/highlighter/themes/resolveThemes.js.map +1 -1
- package/dist/highlighter/themes/themeResolution.d.ts +8 -0
- package/dist/highlighter/themes/themeResolution.d.ts.map +1 -0
- package/dist/highlighter/themes/themeResolution.js +22 -0
- package/dist/highlighter/themes/themeResolution.js.map +1 -0
- package/dist/highlighter/themes/themeResolver.d.ts +8 -0
- package/dist/highlighter/themes/themeResolver.d.ts.map +1 -0
- package/dist/highlighter/themes/themeResolver.js +8 -0
- package/dist/highlighter/themes/themeResolver.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -3
- package/dist/react/index.d.ts +2 -2
- package/dist/react/jsx.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +1 -0
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +4 -1
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +139 -19
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +2 -2
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +5 -5
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/style.js +1 -1
- package/dist/style.js.map +1 -1
- package/dist/types.d.ts +19 -16
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/computeEstimatedDiffHeights.js +9 -20
- package/dist/utils/computeEstimatedDiffHeights.js.map +1 -1
- package/dist/utils/getHighlighterThemeStyles.js +16 -12
- package/dist/utils/getHighlighterThemeStyles.js.map +1 -1
- package/dist/utils/iterateOverDiff.js +147 -182
- package/dist/utils/iterateOverDiff.js.map +1 -1
- package/dist/utils/parsePatchFiles.js +93 -4
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/updateDiffHunks.d.ts +13 -0
- package/dist/utils/updateDiffHunks.d.ts.map +1 -0
- package/dist/utils/updateDiffHunks.js +171 -0
- package/dist/utils/updateDiffHunks.js.map +1 -0
- package/dist/utils/virtualDiffLayout.d.ts +24 -2
- package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
- package/dist/utils/virtualDiffLayout.js +49 -1
- package/dist/utils/virtualDiffLayout.js.map +1 -1
- package/dist/worker/WorkerPoolManager.js +1 -1
- package/dist/worker/WorkerPoolManager.js.map +1 -1
- package/dist/worker/{wasm-D4DU5jgR.js → wasm-BaDzIkIn.js} +2 -2
- package/dist/worker/wasm-BaDzIkIn.js.map +1 -0
- package/dist/worker/worker-portable.js +1021 -314
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +202 -196
- package/dist/worker/worker.js.map +1 -1
- package/package.json +4 -2
- package/dist/editor/css.d.ts +0 -6
- package/dist/editor/css.d.ts.map +0 -1
- package/dist/editor/css.js +0 -218
- package/dist/editor/css.js.map +0 -1
- package/dist/editor/quickEdit.d.ts.map +0 -1
- package/dist/editor/quickEdit.js.map +0 -1
- package/dist/worker/wasm-D4DU5jgR.js.map +0 -1
package/dist/editor/tokenzier.js
CHANGED
|
@@ -15,84 +15,104 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
15
15
|
#tokenizeMaxLineLength;
|
|
16
16
|
#setStyle;
|
|
17
17
|
#onDeferTokenize;
|
|
18
|
-
#
|
|
19
|
-
#
|
|
18
|
+
#debug;
|
|
19
|
+
#disposes;
|
|
20
|
+
#stateStack = [INITIAL];
|
|
20
21
|
#lastLine = -1;
|
|
21
22
|
#isStopped = true;
|
|
23
|
+
#isPaused = false;
|
|
22
24
|
#backgroundJobId = 0;
|
|
23
25
|
#backgroundChangedLineRanges;
|
|
24
26
|
#backgroundChangedRangeIndex = 0;
|
|
25
|
-
#
|
|
27
|
+
#isMessageListenerAttached = false;
|
|
28
|
+
#prebuildStateStack = debounce(async (renderRange) => {
|
|
26
29
|
const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};
|
|
27
30
|
const endLine = Math.min(totalLines === Infinity ? Infinity : startingLine + totalLines, this.#textDocument.lineCount);
|
|
28
31
|
if (this.#grammar === void 0) {
|
|
29
32
|
await this.#highlighter.loadLanguage(this.#textDocument.languageId);
|
|
30
33
|
this.#grammar = this.#highlighter.getLanguage(this.#textDocument.languageId);
|
|
31
34
|
}
|
|
32
|
-
this.#
|
|
35
|
+
this.#buildStateStack(endLine);
|
|
33
36
|
}, 500);
|
|
34
37
|
#onMessage = ({ data }) => {
|
|
35
|
-
if (data
|
|
38
|
+
if (typeof data !== "object" || data === null) return;
|
|
39
|
+
const { type, jobId } = data;
|
|
40
|
+
if (type === "tokenize" && typeof jobId === "number" && jobId === this.#backgroundJobId) this.#backgroundTokenize(jobId);
|
|
36
41
|
};
|
|
37
|
-
|
|
42
|
+
get themeType() {
|
|
43
|
+
return this.#themeType;
|
|
44
|
+
}
|
|
45
|
+
constructor({ codeOptions, highlighter, textDocument, setStyle, onDeferTokenize, __debug }) {
|
|
46
|
+
const { themeType = "system", theme = DEFAULT_THEMES, tokenizeMaxLineLength = 1e3 } = codeOptions;
|
|
47
|
+
this.#mediaQueryList = window.matchMedia("(prefers-color-scheme: dark)");
|
|
48
|
+
if (themeType === "system") this.#themeType = this.#mediaQueryList.matches ? "dark" : "light";
|
|
49
|
+
else this.#themeType = themeType;
|
|
50
|
+
if (typeof theme !== "string") {
|
|
51
|
+
const observer = new MutationObserver((mutations) => {
|
|
52
|
+
for (const { type, attributeName } of mutations) if (type === "attributes" && attributeName !== null && (attributeName === "class" || attributeName.startsWith("data-"))) {
|
|
53
|
+
const themeType$1 = getComputedStyle(document.body).colorScheme === "dark" ? "dark" : "light";
|
|
54
|
+
this.#emitThemeChange(theme[themeType$1], themeType$1);
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
observer.observe(document.documentElement, { attributes: true });
|
|
59
|
+
observer.observe(document.body, { attributes: true });
|
|
60
|
+
this.#disposes = [addEventListener(this.#mediaQueryList, "change", (e) => {
|
|
61
|
+
const themeType$1 = e.matches ? "dark" : "light";
|
|
62
|
+
this.#emitThemeChange(theme[themeType$1], themeType$1);
|
|
63
|
+
}), () => observer.disconnect()];
|
|
64
|
+
}
|
|
65
|
+
this.#highlighter = highlighter;
|
|
66
|
+
this.#textDocument = textDocument;
|
|
67
|
+
this.#tokenizeMaxLineLength = tokenizeMaxLineLength;
|
|
68
|
+
this.#setStyle = setStyle;
|
|
69
|
+
this.#onDeferTokenize = onDeferTokenize;
|
|
70
|
+
this.#debug = __debug ?? false;
|
|
71
|
+
if (highlighter.getLoadedLanguages().includes(textDocument.languageId)) this.#grammar = highlighter.getLanguage(textDocument.languageId);
|
|
72
|
+
this.#colorMap = [];
|
|
73
|
+
this.#setTheme(typeof theme === "string" ? theme : theme[this.#themeType]);
|
|
74
|
+
}
|
|
75
|
+
#emitThemeChange(themeName, themeType) {
|
|
38
76
|
this.#themeType = themeType;
|
|
39
77
|
this.#setTheme(themeName);
|
|
40
78
|
this.stopBackgroundTokenize();
|
|
41
|
-
this.#
|
|
79
|
+
this.#stateStack = [INITIAL];
|
|
42
80
|
if (this.#grammar !== void 0 && this.#textDocument.lineCount > 0) this.#scheduleBackgroundTokenize(0);
|
|
43
|
-
}
|
|
44
|
-
#setTheme
|
|
81
|
+
}
|
|
82
|
+
#setTheme(themeName) {
|
|
45
83
|
this.#colorMap = this.#highlighter.setTheme(themeName).colorMap;
|
|
46
84
|
const { colors = {} } = this.#highlighter.getTheme(themeName);
|
|
47
85
|
const selectionBackground = colors["editor.selectionBackground"];
|
|
48
86
|
const lineHighlightBackground = colors["editor.lineHighlightBackground"];
|
|
49
87
|
const gutterForeground = colors["editorLineNumber.foreground"];
|
|
50
88
|
const gutterActiveForeground = colors["editorLineNumber.activeForeground"];
|
|
89
|
+
const cursorForeground = colors["editorCursor.foreground"];
|
|
90
|
+
const findMatchBackground = colors["editor.findMatchBackground"];
|
|
91
|
+
const findMatchHighlightBackground = colors["editor.findMatchHighlightBackground"];
|
|
92
|
+
const hintForeground = colors["editorHint.foreground"];
|
|
93
|
+
const infoForeground = colors["editorInfo.foreground"];
|
|
94
|
+
const warningForeground = colors["editorWarning.foreground"];
|
|
95
|
+
const errorForeground = colors["editorError.foreground"];
|
|
51
96
|
this.#setStyle(`:host {
|
|
52
97
|
--diffs-editor-selection-bg: ${selectionBackground ?? "var(--diffs-line-bg)"};
|
|
53
98
|
--diffs-editor-line-highlight-bg: ${lineHighlightBackground ?? "var(--diffs-line-bg)"};
|
|
54
99
|
--diffs-editor-line-number-fg: ${gutterForeground ?? "var(--diffs-fg-number)"};
|
|
55
100
|
--diffs-editor-line-number-active-bg: ${lineHighlightBackground ?? "var(--diffs-line-bg, var(--diffs-bg))"};
|
|
56
101
|
--diffs-editor-line-number-active-fg: ${gutterActiveForeground ?? "var(--diffs-selection-number-fg)"};
|
|
102
|
+
--diffs-editor-match-bg: ${findMatchBackground ?? "unset"};
|
|
103
|
+
--diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? "unset"};
|
|
104
|
+
--diffs-editor-cursor-fg: ${cursorForeground ?? "unset"};
|
|
105
|
+
--diffs-editor-hint-fg: ${hintForeground ?? "unset"};
|
|
106
|
+
--diffs-editor-info-fg: ${infoForeground ?? "unset"};
|
|
107
|
+
--diffs-editor-warning-fg: ${warningForeground ?? "unset"};
|
|
108
|
+
--diffs-editor-error-fg: ${errorForeground ?? "unset"};
|
|
57
109
|
}`);
|
|
58
|
-
};
|
|
59
|
-
#watchColorScheme = (theme) => {
|
|
60
|
-
const observer = new MutationObserver((mutations) => {
|
|
61
|
-
for (const { type, attributeName } of mutations) if (type === "attributes" && attributeName !== null && (attributeName === "class" || attributeName.startsWith("data-"))) {
|
|
62
|
-
const themeType = getComputedStyle(document.body).colorScheme === "dark" ? "dark" : "light";
|
|
63
|
-
this.#onThemeChange(theme[themeType], themeType);
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
observer.observe(document.documentElement, { attributes: true });
|
|
68
|
-
observer.observe(document.body, { attributes: true });
|
|
69
|
-
this.#editorEventDisposes = [addEventListener(this.#mediaQueryList, "change", (e) => {
|
|
70
|
-
const themeType = e.matches ? "dark" : "light";
|
|
71
|
-
this.#onThemeChange(theme[themeType], themeType);
|
|
72
|
-
}), () => observer.disconnect()];
|
|
73
|
-
};
|
|
74
|
-
get themeType() {
|
|
75
|
-
return this.#themeType;
|
|
76
|
-
}
|
|
77
|
-
constructor({ codeOptions, highlighter, textDocument, setStyle, onDeferTokenize }) {
|
|
78
|
-
const { themeType = "system", theme = DEFAULT_THEMES, tokenizeMaxLineLength = 1e3 } = codeOptions;
|
|
79
|
-
this.#mediaQueryList = window.matchMedia("(prefers-color-scheme: dark)");
|
|
80
|
-
if (themeType === "system") this.#themeType = this.#mediaQueryList.matches ? "dark" : "light";
|
|
81
|
-
else this.#themeType = themeType;
|
|
82
|
-
if (typeof theme !== "string") this.#watchColorScheme(theme);
|
|
83
|
-
this.#highlighter = highlighter;
|
|
84
|
-
this.#textDocument = textDocument;
|
|
85
|
-
this.#tokenizeMaxLineLength = tokenizeMaxLineLength;
|
|
86
|
-
this.#setStyle = setStyle;
|
|
87
|
-
this.#onDeferTokenize = onDeferTokenize;
|
|
88
|
-
if (highlighter.getLoadedLanguages().includes(textDocument.languageId)) this.#grammar = highlighter.getLanguage(textDocument.languageId);
|
|
89
|
-
this.#colorMap = [];
|
|
90
|
-
this.#setTheme(typeof theme === "string" ? theme : theme[this.#themeType]);
|
|
91
110
|
}
|
|
92
111
|
cleanUp() {
|
|
112
|
+
this.#detachMessageListener();
|
|
93
113
|
this.stopBackgroundTokenize();
|
|
94
|
-
this.#
|
|
95
|
-
this.#
|
|
114
|
+
this.#disposes?.forEach((dispose) => dispose());
|
|
115
|
+
this.#disposes = void 0;
|
|
96
116
|
}
|
|
97
117
|
tokenize(change, renderRange) {
|
|
98
118
|
if (this.#grammar === void 0) throw new Error("Grammar not loaded");
|
|
@@ -110,42 +130,42 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
110
130
|
for (const [rangeStart, rangeEnd] of changedLineRanges) if (rangeStart < viewStart) offscreenSyncEnd = Math.max(offscreenSyncEnd, Math.min(rangeEnd, viewStart - 1));
|
|
111
131
|
}
|
|
112
132
|
const shouldFlushOffscreenLines = offscreenSyncEnd >= dirtyStart && (canReuseCachedStates || change.lineDelta < 0);
|
|
113
|
-
if (canReuseCachedStates) this.#
|
|
133
|
+
if (canReuseCachedStates) this.#buildStateStack(dirtyStart);
|
|
114
134
|
else {
|
|
115
|
-
this.#
|
|
116
|
-
if (renderRange === void 0 || dirtyStart >= viewStart) this.#
|
|
135
|
+
this.#stateStack.length = Math.min(this.#stateStack.length, dirtyStart + 1);
|
|
136
|
+
if (renderRange === void 0 || dirtyStart >= viewStart) this.#buildStateStack(viewStart);
|
|
117
137
|
}
|
|
118
138
|
let changedRangeIndex = 0;
|
|
119
139
|
let currentChangedRangeEnd = changedLineRanges[changedRangeIndex][1];
|
|
120
140
|
let backgroundStartLine;
|
|
121
141
|
let backgroundChangedRangeIndex = 0;
|
|
122
142
|
let line = canReuseCachedStates ? changedLineRanges[changedRangeIndex][0] : viewStart;
|
|
123
|
-
let state = this.#
|
|
143
|
+
let state = this.#stateStack[line] ?? INITIAL;
|
|
124
144
|
let settled = false;
|
|
125
145
|
const dirtyLines = /* @__PURE__ */ new Map();
|
|
126
146
|
const offscreenDirtyLines = shouldFlushOffscreenLines ? /* @__PURE__ */ new Map() : void 0;
|
|
127
147
|
if (offscreenDirtyLines !== void 0 && !canReuseCachedStates) {
|
|
128
148
|
const offscreenEnd = Math.min(offscreenSyncEnd + 1, viewStart, renderRangeEndLine);
|
|
129
149
|
if (offscreenEnd > dirtyStart) {
|
|
130
|
-
this.#
|
|
150
|
+
this.#buildStateStack(offscreenEnd);
|
|
131
151
|
let offscreenLine = dirtyStart;
|
|
132
|
-
let offscreenState = this.#
|
|
152
|
+
let offscreenState = this.#stateStack[offscreenLine] ?? INITIAL;
|
|
133
153
|
for (; offscreenLine < offscreenEnd; offscreenLine++) {
|
|
134
154
|
const resolved = this.#tokenizeLineAt(offscreenLine, offscreenState);
|
|
135
155
|
offscreenState = resolved.state;
|
|
136
156
|
offscreenDirtyLines.set(offscreenLine, resolved.resolvedTokens);
|
|
137
157
|
}
|
|
138
|
-
if (canCacheTokenizedStates) this.#
|
|
158
|
+
if (canCacheTokenizedStates) this.#stateStack[offscreenEnd] = offscreenState;
|
|
139
159
|
}
|
|
140
160
|
}
|
|
141
161
|
for (; line < renderRangeEndLine;) {
|
|
142
|
-
const previousNextState = canReuseCachedStates ? this.#
|
|
143
|
-
if (canCacheTokenizedStates) this.#
|
|
162
|
+
const previousNextState = canReuseCachedStates ? this.#stateStack[line + 1] : void 0;
|
|
163
|
+
if (canCacheTokenizedStates) this.#stateStack[line] = state;
|
|
144
164
|
const { resolvedTokens, state: nextState } = this.#tokenizeLineAt(line, state);
|
|
145
165
|
state = nextState;
|
|
146
166
|
if (line >= viewStart) dirtyLines.set(line, resolvedTokens);
|
|
147
167
|
else offscreenDirtyLines?.set(line, resolvedTokens);
|
|
148
|
-
if (canCacheTokenizedStates) this.#
|
|
168
|
+
if (canCacheTokenizedStates) this.#stateStack[line + 1] = state;
|
|
149
169
|
settled = line >= currentChangedRangeEnd && canReuseCachedStates && previousNextState !== void 0 && state.equals(previousNextState);
|
|
150
170
|
if (settled) {
|
|
151
171
|
changedRangeIndex++;
|
|
@@ -156,12 +176,12 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
156
176
|
backgroundChangedRangeIndex = changedRangeIndex;
|
|
157
177
|
break;
|
|
158
178
|
}
|
|
159
|
-
if (this.#
|
|
179
|
+
if (this.#stateStack[nextRange[0]] === void 0) {
|
|
160
180
|
currentChangedRangeEnd = nextRange[1];
|
|
161
181
|
line++;
|
|
162
182
|
} else {
|
|
163
183
|
line = nextRange[0];
|
|
164
|
-
state = this.#
|
|
184
|
+
state = this.#stateStack[line] ?? state;
|
|
165
185
|
currentChangedRangeEnd = nextRange[1];
|
|
166
186
|
}
|
|
167
187
|
settled = false;
|
|
@@ -169,8 +189,8 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
169
189
|
}
|
|
170
190
|
line++;
|
|
171
191
|
}
|
|
172
|
-
if (canCacheTokenizedStates) if (line < renderRangeEndLine) this.#
|
|
173
|
-
else this.#
|
|
192
|
+
if (canCacheTokenizedStates) if (line < renderRangeEndLine) this.#stateStack[line + 1] = state;
|
|
193
|
+
else this.#stateStack[line] = state;
|
|
174
194
|
if (offscreenDirtyLines !== void 0 && offscreenDirtyLines.size > 0) this.#onDeferTokenize(offscreenDirtyLines, this.#themeType);
|
|
175
195
|
if (backgroundStartLine !== void 0) this.#scheduleBackgroundTokenize(backgroundStartLine, changedLineRanges, backgroundChangedRangeIndex);
|
|
176
196
|
else if (!settled && line < lineCount) {
|
|
@@ -179,31 +199,61 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
179
199
|
}
|
|
180
200
|
return dirtyLines;
|
|
181
201
|
}
|
|
182
|
-
|
|
183
|
-
this.#
|
|
202
|
+
prebuildStateStack(renderRange) {
|
|
203
|
+
this.#prebuildStateStack(renderRange);
|
|
184
204
|
}
|
|
185
205
|
stopBackgroundTokenize() {
|
|
186
|
-
|
|
206
|
+
if (this.#isStopped) return;
|
|
187
207
|
this.#isStopped = true;
|
|
208
|
+
this.#isPaused = false;
|
|
188
209
|
this.#lastLine = -1;
|
|
189
210
|
this.#backgroundChangedLineRanges = void 0;
|
|
190
211
|
this.#backgroundChangedRangeIndex = 0;
|
|
212
|
+
this.#detachMessageListener();
|
|
191
213
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
this.#
|
|
195
|
-
this.#
|
|
196
|
-
|
|
197
|
-
|
|
214
|
+
pauseBackgroundTokenize() {
|
|
215
|
+
if (this.#isStopped || this.#isPaused) return;
|
|
216
|
+
if (this.#debug) console.log("[diffs/editor] background tokenization paused", { jobId: this.#backgroundJobId });
|
|
217
|
+
this.#isPaused = true;
|
|
218
|
+
}
|
|
219
|
+
resumeBackgroundTokenize() {
|
|
220
|
+
if (this.#isStopped || !this.#isPaused || this.#grammar === void 0 || this.#lastLine < 0) return;
|
|
221
|
+
if (this.#debug) console.log("[diffs/editor] background tokenization resumed", { jobId: this.#backgroundJobId });
|
|
222
|
+
this.#isPaused = false;
|
|
223
|
+
this.#postTokenizeMessage(this.#backgroundJobId);
|
|
224
|
+
}
|
|
225
|
+
#attachMessageListener() {
|
|
226
|
+
if (this.#isMessageListenerAttached) return;
|
|
198
227
|
globalThis.addEventListener("message", this.#onMessage);
|
|
199
|
-
this.#
|
|
228
|
+
this.#isMessageListenerAttached = true;
|
|
229
|
+
}
|
|
230
|
+
#detachMessageListener() {
|
|
231
|
+
if (!this.#isMessageListenerAttached) return;
|
|
232
|
+
globalThis.removeEventListener("message", this.#onMessage);
|
|
233
|
+
this.#isMessageListenerAttached = false;
|
|
200
234
|
}
|
|
201
|
-
#
|
|
235
|
+
#postTokenizeMessage(jobId) {
|
|
202
236
|
globalThis.postMessage({
|
|
203
237
|
type: "tokenize",
|
|
204
238
|
jobId
|
|
205
239
|
});
|
|
206
240
|
}
|
|
241
|
+
#scheduleBackgroundTokenize(startLine, changedLineRanges, changedRangeIndex = 0) {
|
|
242
|
+
const jobId = ++this.#backgroundJobId;
|
|
243
|
+
if (this.#debug) console.log("[diffs/editor] background tokenization scheduled", {
|
|
244
|
+
jobId,
|
|
245
|
+
startLine,
|
|
246
|
+
changedLineRanges,
|
|
247
|
+
changedRangeIndex
|
|
248
|
+
});
|
|
249
|
+
this.#isStopped = false;
|
|
250
|
+
this.#isPaused = false;
|
|
251
|
+
this.#lastLine = startLine;
|
|
252
|
+
this.#backgroundChangedLineRanges = changedLineRanges;
|
|
253
|
+
this.#backgroundChangedRangeIndex = changedRangeIndex;
|
|
254
|
+
this.#attachMessageListener();
|
|
255
|
+
this.#postTokenizeMessage(jobId);
|
|
256
|
+
}
|
|
207
257
|
#tokenizeLineAt(line, state) {
|
|
208
258
|
if (this.#grammar === void 0) throw new Error("Grammar not loaded");
|
|
209
259
|
const lineText = this.#textDocument.getLineText(line);
|
|
@@ -232,32 +282,32 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
232
282
|
state: result.ruleStack
|
|
233
283
|
};
|
|
234
284
|
}
|
|
235
|
-
#
|
|
285
|
+
#buildStateStack(endAt) {
|
|
236
286
|
const boundedEndAt = Math.min(Math.max(0, endAt), this.#textDocument.lineCount);
|
|
237
|
-
if (this.#
|
|
238
|
-
let line = this.#
|
|
239
|
-
let state = this.#
|
|
287
|
+
if (this.#stateStack.length > boundedEndAt || this.#grammar === void 0) return;
|
|
288
|
+
let line = this.#stateStack.length - 1;
|
|
289
|
+
let state = this.#stateStack[line] ?? INITIAL;
|
|
240
290
|
for (; line < boundedEndAt; line++) {
|
|
241
|
-
this.#
|
|
291
|
+
this.#stateStack[line] = state;
|
|
242
292
|
const lineText = this.#textDocument.getLineText(line);
|
|
243
293
|
if (lineText.length <= this.#tokenizeMaxLineLength && lineText !== "" && lineText.trim() !== "") state = this.#grammar.tokenizeLine2(lineText, state, EditorTokenizer.TOKENIZE_TIME_LIMIT).ruleStack;
|
|
244
294
|
}
|
|
245
|
-
this.#
|
|
295
|
+
this.#stateStack[line] = state;
|
|
246
296
|
}
|
|
247
297
|
#backgroundTokenize(jobId) {
|
|
248
|
-
if (this.#isStopped || this.#grammar === void 0 || jobId !== this.#backgroundJobId) return;
|
|
298
|
+
if (this.#isStopped || this.#isPaused || this.#grammar === void 0 || jobId !== this.#backgroundJobId) return;
|
|
249
299
|
const t = performance.now();
|
|
250
300
|
const lines = /* @__PURE__ */ new Map();
|
|
251
301
|
const totalLines = this.#textDocument.lineCount;
|
|
252
302
|
const changedLineRanges = this.#backgroundChangedLineRanges;
|
|
253
303
|
let line = this.#lastLine;
|
|
254
|
-
let state = this.#
|
|
304
|
+
let state = this.#stateStack[line] ?? INITIAL;
|
|
255
305
|
let settled = false;
|
|
256
306
|
let changedRangeIndex = this.#backgroundChangedRangeIndex;
|
|
257
307
|
let currentChangedRangeEnd = changedLineRanges?.[changedRangeIndex]?.[1];
|
|
258
308
|
for (; line < totalLines;) {
|
|
259
|
-
this.#
|
|
260
|
-
const previousNextState = currentChangedRangeEnd !== void 0 ? this.#
|
|
309
|
+
this.#stateStack[line] = state;
|
|
310
|
+
const previousNextState = currentChangedRangeEnd !== void 0 ? this.#stateStack[line + 1] : void 0;
|
|
261
311
|
const lineText = this.#textDocument.getLineText(line);
|
|
262
312
|
if (lineText.length > this.#tokenizeMaxLineLength) {
|
|
263
313
|
console.warn(`[diffs] Line(${line}) too long to tokenize: ${lineText.length}`);
|
|
@@ -276,7 +326,7 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
276
326
|
lines.set(line, ret.resolvedTokens);
|
|
277
327
|
state = ret.ruleStack;
|
|
278
328
|
}
|
|
279
|
-
this.#
|
|
329
|
+
this.#stateStack[line + 1] = state;
|
|
280
330
|
settled = currentChangedRangeEnd !== void 0 && line >= currentChangedRangeEnd && previousNextState !== void 0 && state.equals(previousNextState);
|
|
281
331
|
line++;
|
|
282
332
|
if (settled) {
|
|
@@ -284,25 +334,25 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
284
334
|
const nextRange = changedLineRanges?.[changedRangeIndex];
|
|
285
335
|
if (nextRange === void 0) break;
|
|
286
336
|
currentChangedRangeEnd = nextRange[1];
|
|
287
|
-
if (this.#
|
|
337
|
+
if (this.#stateStack[nextRange[0]] === void 0) settled = false;
|
|
288
338
|
else {
|
|
289
339
|
line = nextRange[0];
|
|
290
|
-
state = this.#
|
|
340
|
+
state = this.#stateStack[line] ?? state;
|
|
291
341
|
settled = false;
|
|
292
342
|
continue;
|
|
293
343
|
}
|
|
294
344
|
}
|
|
295
|
-
if (performance.now() - t >
|
|
345
|
+
if (performance.now() - t > 1) break;
|
|
296
346
|
}
|
|
297
347
|
this.#onDeferTokenize(lines, this.#themeType);
|
|
298
|
-
if (this.#isStopped || jobId !== this.#backgroundJobId) return;
|
|
348
|
+
if (this.#isStopped || this.#isPaused || jobId !== this.#backgroundJobId) return;
|
|
299
349
|
if (settled || line >= totalLines) {
|
|
300
350
|
this.stopBackgroundTokenize();
|
|
301
351
|
return;
|
|
302
352
|
}
|
|
303
353
|
this.#lastLine = line;
|
|
304
354
|
this.#backgroundChangedRangeIndex = changedRangeIndex;
|
|
305
|
-
this.#
|
|
355
|
+
this.#postTokenizeMessage(jobId);
|
|
306
356
|
}
|
|
307
357
|
};
|
|
308
358
|
function tokenizeLine(grammar, colorMap, lineText, stateStack, timeLimit) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokenzier.js","names":["#textDocument","#grammar","#highlighter","#buildStateStackMap","#backgroundJobId","#backgroundTokenize","#themeType","#setTheme","#stateStackCache","#scheduleBackgroundTokenize","#colorMap","#setStyle","#onThemeChange","#editorEventDisposes","#mediaQueryList","#watchColorScheme","#tokenizeMaxLineLength","#onDeferTokenize","changedLineRanges: readonly [number, number][]","backgroundStartLine: number | undefined","dirtyLines: Map<number, Array<HighlightedToken>>","offscreenDirtyLines:\n | Map<number, Array<HighlightedToken>>\n | undefined","#tokenizeLineAt","#prebuildStateStackMap","#onMessage","#isStopped","#lastLine","#backgroundChangedLineRanges","#backgroundChangedRangeIndex","#postBackgroundTokenizeMessage","resolvedTokens: Array<HighlightedToken>"],"sources":["../../src/editor/tokenzier.ts"],"sourcesContent":["import {\n EncodedTokenMetadata,\n type IGrammar,\n INITIAL,\n type StateStack,\n} from 'shiki/textmate';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport type {\n BaseCodeOptions,\n DiffsHighlighter,\n HighlightedToken,\n RenderRange,\n ThemesType,\n} from '../types';\nimport type { TextDocument, TextDocumentChange } from './textDocument';\nimport { addEventListener, debounce, h } from './utils';\n\nexport interface EditorTokenizerProps {\n highlighter: DiffsHighlighter;\n textDocument: TextDocument<unknown>;\n codeOptions: BaseCodeOptions;\n setStyle: (style: string) => void;\n onDeferTokenize: (\n lines: Map<number, Array<HighlightedToken>>,\n themeType: 'dark' | 'light'\n ) => void;\n}\n\n/** Stoppable code tokenizer for the editor */\nexport class EditorTokenizer {\n static TOKENIZE_TIME_LIMIT = 500;\n\n #highlighter: DiffsHighlighter;\n #grammar: IGrammar | undefined;\n #mediaQueryList: MediaQueryList;\n #themeType: 'light' | 'dark';\n #colorMap: string[];\n #textDocument: TextDocument<unknown>;\n #tokenizeMaxLineLength: number;\n #setStyle: EditorTokenizerProps['setStyle'];\n #onDeferTokenize: EditorTokenizerProps['onDeferTokenize'];\n #editorEventDisposes?: (() => void)[];\n\n // state\n #stateStackCache: StateStack[] = [INITIAL];\n #lastLine: number = -1;\n #isStopped: boolean = true;\n #backgroundJobId: number = 0;\n #backgroundChangedLineRanges: readonly [number, number][] | undefined;\n #backgroundChangedRangeIndex: number = 0;\n\n #prebuildStateStackMap = debounce(async (renderRange?: RenderRange) => {\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const endLine = Math.min(\n totalLines === Infinity ? Infinity : startingLine + totalLines,\n this.#textDocument.lineCount\n );\n if (this.#grammar === undefined) {\n await this.#highlighter.loadLanguage(this.#textDocument.languageId);\n this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n this.#buildStateStackMap(endLine);\n }, 500);\n\n #onMessage = ({\n data,\n }: MessageEvent<{ type: 'tokenize'; jobId: number }>) => {\n if (data.type === 'tokenize' && data.jobId === this.#backgroundJobId) {\n this.#backgroundTokenize(data.jobId);\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 #onThemeChange = (themeName: string, themeType: 'light' | 'dark') => {\n this.#themeType = themeType;\n this.#setTheme(themeName);\n this.stopBackgroundTokenize();\n this.#stateStackCache = [INITIAL];\n if (this.#grammar !== undefined && this.#textDocument.lineCount > 0) {\n this.#scheduleBackgroundTokenize(0);\n }\n };\n\n #setTheme = (themeName: string): void => {\n this.#colorMap = this.#highlighter.setTheme(themeName).colorMap;\n const { colors = {} } = this.#highlighter.getTheme(themeName);\n const selectionBackground = colors['editor.selectionBackground'];\n const lineHighlightBackground = colors['editor.lineHighlightBackground'];\n const gutterForeground = colors['editorLineNumber.foreground'];\n const gutterActiveForeground = colors['editorLineNumber.activeForeground'];\n this.#setStyle(`:host {\n --diffs-editor-selection-bg: ${selectionBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-line-highlight-bg: ${lineHighlightBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-line-number-fg: ${gutterForeground ?? 'var(--diffs-fg-number)'};\n --diffs-editor-line-number-active-bg: ${lineHighlightBackground ?? 'var(--diffs-line-bg, var(--diffs-bg))'};\n --diffs-editor-line-number-active-fg: ${gutterActiveForeground ?? 'var(--diffs-selection-number-fg)'};\n }`);\n };\n\n #watchColorScheme = (theme: ThemesType) => {\n const observer = new MutationObserver((mutations) => {\n for (const { type, attributeName } of mutations) {\n if (\n type === 'attributes' &&\n attributeName !== null &&\n (attributeName === 'class' || attributeName.startsWith('data-'))\n ) {\n const themeType =\n getComputedStyle(document.body).colorScheme === 'dark'\n ? 'dark'\n : 'light';\n this.#onThemeChange(theme[themeType], themeType);\n break;\n }\n }\n });\n observer.observe(document.documentElement, { attributes: true });\n observer.observe(document.body, { attributes: true });\n this.#editorEventDisposes = [\n addEventListener(this.#mediaQueryList, 'change', (e) => {\n const themeType = e.matches ? 'dark' : 'light';\n this.#onThemeChange(theme[themeType], themeType);\n }),\n () => observer.disconnect(),\n ];\n };\n\n get themeType(): 'light' | 'dark' {\n return this.#themeType;\n }\n\n constructor({\n codeOptions,\n highlighter,\n textDocument,\n setStyle,\n onDeferTokenize,\n }: EditorTokenizerProps) {\n const {\n themeType = 'system',\n theme = DEFAULT_THEMES,\n tokenizeMaxLineLength = 1000,\n } = codeOptions;\n this.#mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');\n if (themeType === 'system') {\n this.#themeType = this.#mediaQueryList.matches ? 'dark' : 'light';\n } else {\n this.#themeType = themeType;\n }\n if (typeof theme !== 'string') {\n this.#watchColorScheme(theme);\n }\n this.#highlighter = highlighter;\n this.#textDocument = textDocument;\n this.#tokenizeMaxLineLength = tokenizeMaxLineLength;\n this.#setStyle = setStyle;\n this.#onDeferTokenize = onDeferTokenize;\n if (highlighter.getLoadedLanguages().includes(textDocument.languageId)) {\n this.#grammar = highlighter.getLanguage(textDocument.languageId);\n }\n this.#colorMap = [];\n this.#setTheme(typeof theme === 'string' ? theme : theme[this.#themeType]);\n }\n\n cleanUp(): void {\n this.stopBackgroundTokenize();\n this.#editorEventDisposes?.forEach((dispose) => dispose());\n this.#editorEventDisposes = undefined;\n }\n\n // to use `tokenize`, call `prebuildStateStackMap` first to prebuild\n // the state stack map for the given render range.\n tokenize(\n change: TextDocumentChange,\n renderRange?: RenderRange\n ): Map<number, Array<HighlightedToken>> {\n if (this.#grammar === undefined) {\n throw new Error('Grammar not loaded');\n }\n\n const { lineCount } = this.#textDocument;\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const renderRangeEndLine =\n totalLines === Infinity\n ? lineCount\n : Math.min(startingLine + totalLines, lineCount);\n\n const dirtyStart = change.startLine;\n const viewStart = Math.max(startingLine, dirtyStart);\n const crossesRenderRangeEnd =\n renderRange !== undefined &&\n totalLines !== Infinity &&\n change.lineDelta > 0 &&\n dirtyStart < renderRangeEndLine &&\n change.endLine >= renderRangeEndLine;\n const canReuseCachedStates = change.lineDelta === 0;\n const canCacheTokenizedStates =\n canReuseCachedStates ||\n renderRange === undefined ||\n dirtyStart >= viewStart;\n const changedLineRanges: readonly [number, number][] = canReuseCachedStates\n ? (change.changedLineRanges ?? [[dirtyStart, change.endLine]])\n : [[dirtyStart, change.endLine]];\n let offscreenSyncEnd = -1;\n if (dirtyStart < viewStart) {\n for (const [rangeStart, rangeEnd] of changedLineRanges) {\n if (rangeStart < viewStart) {\n offscreenSyncEnd = Math.max(\n offscreenSyncEnd,\n Math.min(rangeEnd, viewStart - 1)\n );\n }\n }\n }\n const shouldFlushOffscreenLines =\n offscreenSyncEnd >= dirtyStart &&\n (canReuseCachedStates || change.lineDelta < 0);\n if (canReuseCachedStates) {\n this.#buildStateStackMap(dirtyStart);\n } else {\n this.#stateStackCache.length = Math.min(\n this.#stateStackCache.length,\n dirtyStart + 1\n );\n if (renderRange === undefined || dirtyStart >= viewStart) {\n this.#buildStateStackMap(viewStart);\n }\n }\n\n let changedRangeIndex = 0;\n let currentChangedRangeEnd = changedLineRanges[changedRangeIndex][1];\n let backgroundStartLine: number | undefined;\n let backgroundChangedRangeIndex = 0;\n let line = canReuseCachedStates\n ? changedLineRanges[changedRangeIndex][0]\n : viewStart;\n let state = this.#stateStackCache[line] ?? INITIAL;\n let settled = false;\n const dirtyLines: Map<number, Array<HighlightedToken>> = new Map();\n const offscreenDirtyLines:\n | Map<number, Array<HighlightedToken>>\n | undefined = shouldFlushOffscreenLines ? new Map() : undefined;\n if (offscreenDirtyLines !== undefined && !canReuseCachedStates) {\n const offscreenEnd = Math.min(\n offscreenSyncEnd + 1,\n viewStart,\n renderRangeEndLine\n );\n if (offscreenEnd > dirtyStart) {\n this.#buildStateStackMap(offscreenEnd);\n let offscreenLine = dirtyStart;\n let offscreenState = this.#stateStackCache[offscreenLine] ?? INITIAL;\n for (; offscreenLine < offscreenEnd; offscreenLine++) {\n const resolved = this.#tokenizeLineAt(offscreenLine, offscreenState);\n offscreenState = resolved.state;\n offscreenDirtyLines.set(offscreenLine, resolved.resolvedTokens);\n }\n if (canCacheTokenizedStates) {\n this.#stateStackCache[offscreenEnd] = offscreenState;\n }\n }\n }\n for (; line < renderRangeEndLine; ) {\n const previousNextState = canReuseCachedStates\n ? this.#stateStackCache[line + 1]\n : undefined;\n if (canCacheTokenizedStates) {\n this.#stateStackCache[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.#stateStackCache[line + 1] = state;\n }\n settled =\n line >= currentChangedRangeEnd &&\n canReuseCachedStates &&\n previousNextState !== undefined &&\n state.equals(previousNextState);\n if (settled) {\n changedRangeIndex++;\n const nextRange = changedLineRanges[changedRangeIndex];\n if (nextRange === undefined) {\n break;\n }\n if (nextRange[0] >= renderRangeEndLine) {\n backgroundStartLine = nextRange[0];\n backgroundChangedRangeIndex = changedRangeIndex;\n break;\n }\n if (this.#stateStackCache[nextRange[0]] === undefined) {\n currentChangedRangeEnd = nextRange[1];\n line++;\n } else {\n line = nextRange[0];\n state = this.#stateStackCache[line] ?? state;\n currentChangedRangeEnd = nextRange[1];\n }\n settled = false;\n continue;\n }\n line++;\n }\n\n if (canCacheTokenizedStates) {\n if (line < renderRangeEndLine) {\n this.#stateStackCache[line + 1] = state;\n } else {\n this.#stateStackCache[line] = state;\n }\n }\n\n if (offscreenDirtyLines !== undefined && offscreenDirtyLines.size > 0) {\n this.#onDeferTokenize(offscreenDirtyLines, this.#themeType);\n }\n\n if (backgroundStartLine !== undefined) {\n this.#scheduleBackgroundTokenize(\n backgroundStartLine,\n changedLineRanges,\n backgroundChangedRangeIndex\n );\n } else if (!settled && line < lineCount) {\n const backgroundLine =\n crossesRenderRangeEnd && dirtyStart >= viewStart\n ? renderRangeEndLine\n : dirtyStart < viewStart && !canReuseCachedStates\n ? dirtyStart\n : line;\n this.#scheduleBackgroundTokenize(\n backgroundLine,\n canReuseCachedStates ? changedLineRanges : undefined,\n changedRangeIndex\n );\n }\n\n return dirtyLines;\n }\n\n prebuildStateStackMap(renderRange?: RenderRange): void {\n this.#prebuildStateStackMap(renderRange);\n }\n\n stopBackgroundTokenize(): void {\n removeEventListener('message', this.#onMessage);\n this.#isStopped = true;\n this.#lastLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\n }\n\n #scheduleBackgroundTokenize(\n startLine: number,\n changedLineRanges?: readonly [number, number][],\n changedRangeIndex = 0\n ): void {\n const jobId = ++this.#backgroundJobId;\n\n this.#isStopped = false;\n this.#lastLine = startLine;\n this.#backgroundChangedLineRanges = changedLineRanges;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n\n globalThis.addEventListener('message', this.#onMessage);\n this.#postBackgroundTokenizeMessage(jobId);\n }\n\n #postBackgroundTokenizeMessage(jobId: number): void {\n // use `postMessage` instead of `setTimeout(fn, 0)` to avoid 4ms delay\n globalThis.postMessage({ type: 'tokenize', jobId });\n }\n\n #tokenizeLineAt(\n line: number,\n state: StateStack\n ): { resolvedTokens: Array<HighlightedToken>; state: StateStack } {\n if (this.#grammar === undefined) {\n throw new Error('Grammar not loaded');\n }\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n if (lineText === '' || lineText.trim() === '') {\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n return {\n resolvedTokens: result.resolvedTokens,\n state: result.ruleStack,\n };\n }\n\n #buildStateStackMap(endAt: number) {\n const boundedEndAt = Math.min(\n Math.max(0, endAt),\n this.#textDocument.lineCount\n );\n if (\n this.#stateStackCache.length > boundedEndAt ||\n this.#grammar === undefined\n ) {\n return;\n }\n let line = this.#stateStackCache.length - 1;\n let state = this.#stateStackCache[line] ?? INITIAL;\n for (; line < boundedEndAt; line++) {\n this.#stateStackCache[line] = state;\n const lineText = this.#textDocument.getLineText(line);\n if (\n lineText.length <= this.#tokenizeMaxLineLength &&\n lineText !== '' &&\n lineText.trim() !== ''\n ) {\n state = this.#grammar.tokenizeLine2(\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n ).ruleStack;\n }\n }\n this.#stateStackCache[line] = state;\n }\n\n #backgroundTokenize(jobId: number) {\n if (\n this.#isStopped ||\n this.#grammar === undefined ||\n jobId !== this.#backgroundJobId\n ) {\n return;\n }\n\n const t = performance.now();\n const lines = new Map<number, Array<HighlightedToken>>();\n const totalLines = this.#textDocument.lineCount;\n const changedLineRanges = this.#backgroundChangedLineRanges;\n\n let line = this.#lastLine;\n let state = this.#stateStackCache[line] ?? INITIAL;\n let settled = false;\n let changedRangeIndex = this.#backgroundChangedRangeIndex;\n let currentChangedRangeEnd = changedLineRanges?.[changedRangeIndex]?.[1];\n for (; line < totalLines; ) {\n this.#stateStackCache[line] = state;\n\n const previousNextState =\n currentChangedRangeEnd !== undefined\n ? this.#stateStackCache[line + 1]\n : undefined;\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n lines.set(line, [[0, '', lineText]]);\n } else if (lineText === '' || lineText.trim() === '') {\n lines.set(line, [[0, '', lineText]]);\n } else {\n const ret = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n lines.set(line, ret.resolvedTokens);\n state = ret.ruleStack;\n }\n\n this.#stateStackCache[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.#stateStackCache[nextRange[0]] === undefined) {\n settled = false;\n } else {\n line = nextRange[0];\n state = this.#stateStackCache[line] ?? state;\n settled = false;\n continue;\n }\n }\n\n // limit the time of partial tokenize to 2ms\n if (performance.now() - t > 2) {\n break;\n }\n }\n\n this.#onDeferTokenize(lines, this.#themeType);\n if (this.#isStopped || jobId !== this.#backgroundJobId) {\n return;\n }\n\n if (settled || line >= totalLines) {\n this.stopBackgroundTokenize();\n return;\n }\n\n this.#lastLine = line;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#postBackgroundTokenizeMessage(jobId);\n }\n}\n\nexport function tokenizeLine(\n grammar: IGrammar,\n colorMap: string[],\n lineText: string,\n stateStack: StateStack,\n timeLimit?: number\n): {\n ruleStack: StateStack;\n resolvedTokens: Array<HighlightedToken>;\n} {\n const result = grammar.tokenizeLine2(lineText, stateStack, timeLimit);\n if (result.stoppedEarly) {\n console.warn(\n `[diffs] Time limit reached when tokenizing line: ${lineText.substring(0, 100)}`\n );\n }\n const rawTokens = result.tokens;\n const tokensLength = rawTokens.length / 2;\n const resolvedTokens: Array<HighlightedToken> = [];\n for (let j = 0; j < tokensLength; j++) {\n const offset = rawTokens[2 * j];\n const nextOffset =\n j + 1 < tokensLength ? rawTokens[2 * j + 2] : lineText.length;\n if (offset === nextOffset) {\n // should never reach here, skip if happens anyway\n continue;\n }\n const metadata = rawTokens[2 * j + 1];\n const bg = EncodedTokenMetadata.getForeground(metadata);\n const fg = colorMap[bg];\n const tokenText = lineText.slice(offset, nextOffset);\n resolvedTokens.push([offset, fg, tokenText]);\n }\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n };\n}\n\nexport function renderLineTokens(\n tokens: Array<HighlightedToken>,\n themeType: 'light' | 'dark'\n): (HTMLElement | string)[] {\n return tokens.map(([char, fg, textContent]) => {\n if (char === 0 && fg === '') {\n if (textContent === '') {\n return h('br');\n }\n return textContent;\n }\n return h('span', {\n dataset: {\n char: char.toString(),\n },\n style: `--diffs-token-${themeType}:${fg};`,\n textContent: textContent,\n });\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tokenzier.js","names":["#textDocument","#grammar","#highlighter","#buildStateStack","#backgroundJobId","#backgroundTokenize","#themeType","#mediaQueryList","themeType","#emitThemeChange","#disposes","#tokenizeMaxLineLength","#setStyle","#onDeferTokenize","#debug","#colorMap","#setTheme","#stateStack","#scheduleBackgroundTokenize","#detachMessageListener","changedLineRanges: readonly [number, number][]","backgroundStartLine: number | undefined","dirtyLines: Map<number, Array<HighlightedToken>>","offscreenDirtyLines:\n | Map<number, Array<HighlightedToken>>\n | undefined","#tokenizeLineAt","#prebuildStateStack","#isStopped","#isPaused","#lastLine","#backgroundChangedLineRanges","#backgroundChangedRangeIndex","#postTokenizeMessage","#isMessageListenerAttached","#onMessage","#attachMessageListener","resolvedTokens: Array<HighlightedToken>"],"sources":["../../src/editor/tokenzier.ts"],"sourcesContent":["import {\n EncodedTokenMetadata,\n type IGrammar,\n INITIAL,\n type StateStack,\n} from 'shiki/textmate';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport type {\n BaseCodeOptions,\n DiffsHighlighter,\n HighlightedToken,\n RenderRange,\n} from '../types';\nimport type { TextDocument, TextDocumentChange } from './textDocument';\nimport { addEventListener, debounce, h } from './utils';\n\nexport interface EditorTokenizerProps {\n highlighter: DiffsHighlighter;\n textDocument: TextDocument<unknown>;\n codeOptions: BaseCodeOptions;\n setStyle: (style: string) => void;\n onDeferTokenize: (\n lines: Map<number, Array<HighlightedToken>>,\n themeType: 'dark' | 'light'\n ) => void;\n __debug?: boolean;\n}\n\n/** Stoppable code tokenizer for the editor */\nexport class EditorTokenizer {\n static TOKENIZE_TIME_LIMIT = 500;\n\n #highlighter: DiffsHighlighter;\n #grammar: IGrammar | undefined;\n #mediaQueryList: MediaQueryList;\n #themeType: 'light' | 'dark';\n #colorMap: string[];\n #textDocument: TextDocument<unknown>;\n #tokenizeMaxLineLength: number;\n #setStyle: EditorTokenizerProps['setStyle'];\n #onDeferTokenize: EditorTokenizerProps['onDeferTokenize'];\n #debug: boolean;\n #disposes?: (() => void)[];\n\n // state\n #stateStack: StateStack[] = [INITIAL]; // cached state stack by line index\n #lastLine: number = -1;\n #isStopped: boolean = true;\n #isPaused: boolean = false;\n #backgroundJobId: number = 0;\n #backgroundChangedLineRanges: readonly [number, number][] | undefined;\n #backgroundChangedRangeIndex: number = 0;\n #isMessageListenerAttached: boolean = false;\n\n #prebuildStateStack = debounce(async (renderRange?: RenderRange) => {\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const endLine = Math.min(\n totalLines === Infinity ? Infinity : startingLine + totalLines,\n this.#textDocument.lineCount\n );\n if (this.#grammar === undefined) {\n await this.#highlighter.loadLanguage(this.#textDocument.languageId);\n this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n this.#buildStateStack(endLine);\n }, 500);\n\n #onMessage = ({ data }: MessageEvent<unknown>) => {\n if (typeof data !== 'object' || data === null) {\n return;\n }\n const { type, jobId } = data as {\n type?: unknown;\n jobId?: unknown;\n };\n if (\n type === 'tokenize' &&\n typeof jobId === 'number' &&\n jobId === this.#backgroundJobId\n ) {\n this.#backgroundTokenize(jobId);\n }\n };\n\n get themeType(): 'light' | 'dark' {\n return this.#themeType;\n }\n\n constructor({\n codeOptions,\n highlighter,\n textDocument,\n setStyle,\n onDeferTokenize,\n __debug,\n }: EditorTokenizerProps) {\n const {\n themeType = 'system',\n theme = DEFAULT_THEMES,\n tokenizeMaxLineLength = 1000,\n } = codeOptions;\n this.#mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');\n if (themeType === 'system') {\n this.#themeType = this.#mediaQueryList.matches ? 'dark' : 'light';\n } else {\n this.#themeType = themeType;\n }\n if (typeof theme !== 'string') {\n const observer = new MutationObserver((mutations) => {\n for (const { type, attributeName } of mutations) {\n if (\n type === 'attributes' &&\n attributeName !== null &&\n (attributeName === 'class' || attributeName.startsWith('data-'))\n ) {\n const themeType =\n getComputedStyle(document.body).colorScheme === 'dark'\n ? 'dark'\n : 'light';\n this.#emitThemeChange(theme[themeType], themeType);\n break;\n }\n }\n });\n observer.observe(document.documentElement, { attributes: true });\n observer.observe(document.body, { attributes: true });\n this.#disposes = [\n addEventListener(this.#mediaQueryList, 'change', (e) => {\n const themeType = e.matches ? 'dark' : 'light';\n this.#emitThemeChange(theme[themeType], themeType);\n }),\n () => observer.disconnect(),\n ];\n }\n this.#highlighter = highlighter;\n this.#textDocument = textDocument;\n this.#tokenizeMaxLineLength = tokenizeMaxLineLength;\n this.#setStyle = setStyle;\n this.#onDeferTokenize = onDeferTokenize;\n this.#debug = __debug ?? false;\n if (highlighter.getLoadedLanguages().includes(textDocument.languageId)) {\n this.#grammar = highlighter.getLanguage(textDocument.languageId);\n }\n this.#colorMap = [];\n this.#setTheme(typeof theme === 'string' ? theme : theme[this.#themeType]);\n }\n\n // By default, diffs components support dual themes, but the tokenizer only renders\n // the preferred theme. When the theme type is changed, the tokenizer will re-tokenize the document.\n #emitThemeChange(themeName: string, themeType: 'light' | 'dark') {\n this.#themeType = themeType;\n this.#setTheme(themeName);\n this.stopBackgroundTokenize();\n this.#stateStack = [INITIAL];\n if (this.#grammar !== undefined && this.#textDocument.lineCount > 0) {\n this.#scheduleBackgroundTokenize(0);\n }\n }\n\n #setTheme(themeName: string) {\n this.#colorMap = this.#highlighter.setTheme(themeName).colorMap;\n const { colors = {} } = this.#highlighter.getTheme(themeName);\n const selectionBackground = colors['editor.selectionBackground'];\n const lineHighlightBackground = colors['editor.lineHighlightBackground'];\n const gutterForeground = colors['editorLineNumber.foreground'];\n const gutterActiveForeground = colors['editorLineNumber.activeForeground'];\n const cursorForeground = colors['editorCursor.foreground'];\n const findMatchBackground = colors['editor.findMatchBackground'];\n const findMatchHighlightBackground =\n colors['editor.findMatchHighlightBackground'];\n const hintForeground = colors['editorHint.foreground'];\n const infoForeground = colors['editorInfo.foreground'];\n const warningForeground = colors['editorWarning.foreground'];\n const errorForeground = colors['editorError.foreground'];\n this.#setStyle(`:host {\n --diffs-editor-selection-bg: ${selectionBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-line-highlight-bg: ${lineHighlightBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-line-number-fg: ${gutterForeground ?? 'var(--diffs-fg-number)'};\n --diffs-editor-line-number-active-bg: ${lineHighlightBackground ?? 'var(--diffs-line-bg, var(--diffs-bg))'};\n --diffs-editor-line-number-active-fg: ${gutterActiveForeground ?? 'var(--diffs-selection-number-fg)'};\n --diffs-editor-match-bg: ${findMatchBackground ?? 'unset'};\n --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? 'unset'};\n --diffs-editor-cursor-fg: ${cursorForeground ?? 'unset'};\n --diffs-editor-hint-fg: ${hintForeground ?? 'unset'};\n --diffs-editor-info-fg: ${infoForeground ?? 'unset'};\n --diffs-editor-warning-fg: ${warningForeground ?? 'unset'};\n --diffs-editor-error-fg: ${errorForeground ?? 'unset'};\n }`);\n }\n\n cleanUp(): void {\n this.#detachMessageListener();\n this.stopBackgroundTokenize();\n this.#disposes?.forEach((dispose) => dispose());\n this.#disposes = undefined;\n }\n\n // to use `tokenize`, call `prebuildStateStackMap` first to prebuild\n // the state stack map for the given render range.\n tokenize(\n change: TextDocumentChange,\n renderRange?: RenderRange\n ): Map<number, Array<HighlightedToken>> {\n if (this.#grammar === undefined) {\n throw new Error('Grammar not loaded');\n }\n\n const { lineCount } = this.#textDocument;\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const renderRangeEndLine =\n totalLines === Infinity\n ? lineCount\n : Math.min(startingLine + totalLines, lineCount);\n\n const dirtyStart = change.startLine;\n const viewStart = Math.max(startingLine, dirtyStart);\n const crossesRenderRangeEnd =\n renderRange !== undefined &&\n totalLines !== Infinity &&\n change.lineDelta > 0 &&\n dirtyStart < renderRangeEndLine &&\n change.endLine >= renderRangeEndLine;\n const canReuseCachedStates = change.lineDelta === 0;\n const canCacheTokenizedStates =\n canReuseCachedStates ||\n renderRange === undefined ||\n dirtyStart >= viewStart;\n const changedLineRanges: readonly [number, number][] = canReuseCachedStates\n ? (change.changedLineRanges ?? [[dirtyStart, change.endLine]])\n : [[dirtyStart, change.endLine]];\n let offscreenSyncEnd = -1;\n if (dirtyStart < viewStart) {\n for (const [rangeStart, rangeEnd] of changedLineRanges) {\n if (rangeStart < viewStart) {\n offscreenSyncEnd = Math.max(\n offscreenSyncEnd,\n Math.min(rangeEnd, viewStart - 1)\n );\n }\n }\n }\n const shouldFlushOffscreenLines =\n offscreenSyncEnd >= dirtyStart &&\n (canReuseCachedStates || change.lineDelta < 0);\n if (canReuseCachedStates) {\n this.#buildStateStack(dirtyStart);\n } else {\n this.#stateStack.length = Math.min(\n this.#stateStack.length,\n dirtyStart + 1\n );\n if (renderRange === undefined || dirtyStart >= viewStart) {\n this.#buildStateStack(viewStart);\n }\n }\n\n let changedRangeIndex = 0;\n let currentChangedRangeEnd = changedLineRanges[changedRangeIndex][1];\n let backgroundStartLine: number | undefined;\n let backgroundChangedRangeIndex = 0;\n let line = canReuseCachedStates\n ? changedLineRanges[changedRangeIndex][0]\n : viewStart;\n let state = this.#stateStack[line] ?? INITIAL;\n let settled = false;\n const dirtyLines: Map<number, Array<HighlightedToken>> = new Map();\n const offscreenDirtyLines:\n | Map<number, Array<HighlightedToken>>\n | undefined = shouldFlushOffscreenLines ? new Map() : undefined;\n if (offscreenDirtyLines !== undefined && !canReuseCachedStates) {\n const offscreenEnd = Math.min(\n offscreenSyncEnd + 1,\n viewStart,\n renderRangeEndLine\n );\n if (offscreenEnd > dirtyStart) {\n this.#buildStateStack(offscreenEnd);\n let offscreenLine = dirtyStart;\n let offscreenState = this.#stateStack[offscreenLine] ?? INITIAL;\n for (; offscreenLine < offscreenEnd; offscreenLine++) {\n const resolved = this.#tokenizeLineAt(offscreenLine, offscreenState);\n offscreenState = resolved.state;\n offscreenDirtyLines.set(offscreenLine, resolved.resolvedTokens);\n }\n if (canCacheTokenizedStates) {\n this.#stateStack[offscreenEnd] = offscreenState;\n }\n }\n }\n for (; line < renderRangeEndLine; ) {\n const previousNextState = canReuseCachedStates\n ? this.#stateStack[line + 1]\n : undefined;\n if (canCacheTokenizedStates) {\n this.#stateStack[line] = state;\n }\n\n const { resolvedTokens, state: nextState } = this.#tokenizeLineAt(\n line,\n state\n );\n state = nextState;\n\n if (line >= viewStart) {\n dirtyLines.set(line, resolvedTokens);\n } else {\n offscreenDirtyLines?.set(line, resolvedTokens);\n }\n\n if (canCacheTokenizedStates) {\n this.#stateStack[line + 1] = state;\n }\n settled =\n line >= currentChangedRangeEnd &&\n canReuseCachedStates &&\n previousNextState !== undefined &&\n state.equals(previousNextState);\n if (settled) {\n changedRangeIndex++;\n const nextRange = changedLineRanges[changedRangeIndex];\n if (nextRange === undefined) {\n break;\n }\n if (nextRange[0] >= renderRangeEndLine) {\n backgroundStartLine = nextRange[0];\n backgroundChangedRangeIndex = changedRangeIndex;\n break;\n }\n if (this.#stateStack[nextRange[0]] === undefined) {\n currentChangedRangeEnd = nextRange[1];\n line++;\n } else {\n line = nextRange[0];\n state = this.#stateStack[line] ?? state;\n currentChangedRangeEnd = nextRange[1];\n }\n settled = false;\n continue;\n }\n line++;\n }\n\n if (canCacheTokenizedStates) {\n if (line < renderRangeEndLine) {\n this.#stateStack[line + 1] = state;\n } else {\n this.#stateStack[line] = state;\n }\n }\n\n if (offscreenDirtyLines !== undefined && offscreenDirtyLines.size > 0) {\n this.#onDeferTokenize(offscreenDirtyLines, this.#themeType);\n }\n\n if (backgroundStartLine !== undefined) {\n this.#scheduleBackgroundTokenize(\n backgroundStartLine,\n changedLineRanges,\n backgroundChangedRangeIndex\n );\n } else if (!settled && line < lineCount) {\n const backgroundLine =\n crossesRenderRangeEnd && dirtyStart >= viewStart\n ? renderRangeEndLine\n : dirtyStart < viewStart && !canReuseCachedStates\n ? dirtyStart\n : line;\n this.#scheduleBackgroundTokenize(\n backgroundLine,\n canReuseCachedStates ? changedLineRanges : undefined,\n changedRangeIndex\n );\n }\n\n return dirtyLines;\n }\n\n prebuildStateStack(renderRange?: RenderRange): void {\n this.#prebuildStateStack(renderRange);\n }\n\n stopBackgroundTokenize(): void {\n if (this.#isStopped) {\n return;\n }\n this.#isStopped = true;\n this.#isPaused = false;\n this.#lastLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\n this.#detachMessageListener();\n }\n\n pauseBackgroundTokenize(): void {\n if (this.#isStopped || this.#isPaused) {\n return;\n }\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization paused', {\n jobId: this.#backgroundJobId,\n });\n }\n this.#isPaused = true;\n }\n\n resumeBackgroundTokenize(): void {\n if (\n this.#isStopped ||\n !this.#isPaused ||\n this.#grammar === undefined ||\n this.#lastLine < 0\n ) {\n return;\n }\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization resumed', {\n jobId: this.#backgroundJobId,\n });\n }\n this.#isPaused = false;\n this.#postTokenizeMessage(this.#backgroundJobId);\n }\n\n #attachMessageListener(): void {\n if (this.#isMessageListenerAttached) {\n return;\n }\n globalThis.addEventListener('message', this.#onMessage);\n this.#isMessageListenerAttached = true;\n }\n\n #detachMessageListener(): void {\n if (!this.#isMessageListenerAttached) {\n return;\n }\n globalThis.removeEventListener('message', this.#onMessage);\n this.#isMessageListenerAttached = false;\n }\n\n #postTokenizeMessage(jobId: number): void {\n // use `postMessage` instead of `setTimeout(fn, 0)` to avoid 4ms delay\n globalThis.postMessage({ type: 'tokenize', jobId });\n }\n\n #scheduleBackgroundTokenize(\n startLine: number,\n changedLineRanges?: readonly [number, number][],\n changedRangeIndex = 0\n ): void {\n const jobId = ++this.#backgroundJobId;\n\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization scheduled', {\n jobId,\n startLine,\n changedLineRanges,\n changedRangeIndex,\n });\n }\n\n this.#isStopped = false;\n this.#isPaused = false;\n this.#lastLine = startLine;\n this.#backgroundChangedLineRanges = changedLineRanges;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#attachMessageListener();\n this.#postTokenizeMessage(jobId);\n }\n\n #tokenizeLineAt(\n line: number,\n state: StateStack\n ): { resolvedTokens: Array<HighlightedToken>; state: StateStack } {\n if (this.#grammar === undefined) {\n throw new Error('Grammar not loaded');\n }\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n if (lineText === '' || lineText.trim() === '') {\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n return {\n resolvedTokens: result.resolvedTokens,\n state: result.ruleStack,\n };\n }\n\n #buildStateStack(endAt: number) {\n const boundedEndAt = Math.min(\n Math.max(0, endAt),\n this.#textDocument.lineCount\n );\n if (this.#stateStack.length > boundedEndAt || this.#grammar === undefined) {\n return;\n }\n let line = this.#stateStack.length - 1;\n let state = this.#stateStack[line] ?? INITIAL;\n for (; line < boundedEndAt; line++) {\n this.#stateStack[line] = state;\n const lineText = this.#textDocument.getLineText(line);\n if (\n lineText.length <= this.#tokenizeMaxLineLength &&\n lineText !== '' &&\n lineText.trim() !== ''\n ) {\n state = this.#grammar.tokenizeLine2(\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n ).ruleStack;\n }\n }\n this.#stateStack[line] = state;\n }\n\n #backgroundTokenize(jobId: number) {\n if (\n this.#isStopped ||\n this.#isPaused ||\n this.#grammar === undefined ||\n jobId !== this.#backgroundJobId\n ) {\n return;\n }\n\n const t = performance.now();\n const lines = new Map<number, Array<HighlightedToken>>();\n const totalLines = this.#textDocument.lineCount;\n const changedLineRanges = this.#backgroundChangedLineRanges;\n\n let line = this.#lastLine;\n let state = this.#stateStack[line] ?? INITIAL;\n let settled = false;\n let changedRangeIndex = this.#backgroundChangedRangeIndex;\n let currentChangedRangeEnd = changedLineRanges?.[changedRangeIndex]?.[1];\n for (; line < totalLines; ) {\n this.#stateStack[line] = state;\n\n const previousNextState =\n currentChangedRangeEnd !== undefined\n ? this.#stateStack[line + 1]\n : undefined;\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n lines.set(line, [[0, '', lineText]]);\n } else if (lineText === '' || lineText.trim() === '') {\n lines.set(line, [[0, '', lineText]]);\n } else {\n const ret = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n lines.set(line, ret.resolvedTokens);\n state = ret.ruleStack;\n }\n\n this.#stateStack[line + 1] = state;\n settled =\n currentChangedRangeEnd !== undefined &&\n line >= currentChangedRangeEnd &&\n previousNextState !== undefined &&\n state.equals(previousNextState);\n line++;\n if (settled) {\n changedRangeIndex++;\n const nextRange = changedLineRanges?.[changedRangeIndex];\n if (nextRange === undefined) {\n break;\n }\n currentChangedRangeEnd = nextRange[1];\n if (this.#stateStack[nextRange[0]] === undefined) {\n settled = false;\n } else {\n line = nextRange[0];\n state = this.#stateStack[line] ?? state;\n settled = false;\n continue;\n }\n }\n\n // limit the time of partial tokenize to 1ms\n if (performance.now() - t > 1) {\n break;\n }\n }\n\n this.#onDeferTokenize(lines, this.#themeType);\n if (this.#isStopped || this.#isPaused || jobId !== this.#backgroundJobId) {\n return;\n }\n\n if (settled || line >= totalLines) {\n this.stopBackgroundTokenize();\n return;\n }\n\n this.#lastLine = line;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#postTokenizeMessage(jobId);\n }\n}\n\nexport function tokenizeLine(\n grammar: IGrammar,\n colorMap: string[],\n lineText: string,\n stateStack: StateStack,\n timeLimit?: number\n): {\n ruleStack: StateStack;\n resolvedTokens: Array<HighlightedToken>;\n} {\n const result = grammar.tokenizeLine2(lineText, stateStack, timeLimit);\n if (result.stoppedEarly) {\n console.warn(\n `[diffs] Time limit reached when tokenizing line: ${lineText.substring(0, 100)}`\n );\n }\n const rawTokens = result.tokens;\n const tokensLength = rawTokens.length / 2;\n const resolvedTokens: Array<HighlightedToken> = [];\n for (let j = 0; j < tokensLength; j++) {\n const offset = rawTokens[2 * j];\n const nextOffset =\n j + 1 < tokensLength ? rawTokens[2 * j + 2] : lineText.length;\n if (offset === nextOffset) {\n // should never reach here, skip if happens anyway\n continue;\n }\n const metadata = rawTokens[2 * j + 1];\n const bg = EncodedTokenMetadata.getForeground(metadata);\n const fg = colorMap[bg];\n const tokenText = lineText.slice(offset, nextOffset);\n resolvedTokens.push([offset, fg, tokenText]);\n }\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n };\n}\n\nexport function renderLineTokens(\n tokens: Array<HighlightedToken>,\n themeType: 'light' | 'dark'\n): (HTMLElement | string)[] {\n return tokens.map(([char, fg, textContent]) => {\n if (char === 0 && fg === '') {\n if (textContent === '') {\n return h('br');\n }\n return textContent;\n }\n return h('span', {\n dataset: {\n char: char.toString(),\n },\n style: `--diffs-token-${themeType}:${fg};`,\n textContent: textContent,\n });\n });\n}\n"],"mappings":"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"}
|
package/dist/editor/utils.d.ts
CHANGED
|
@@ -8,9 +8,11 @@ declare function addEventListener<K extends keyof HTMLElementEventMap>(el: HTMLE
|
|
|
8
8
|
declare function addEventListener<K extends keyof DocumentEventMap>(el: Document, event: K, listener: (this: Document, evt: DocumentEventMap[K]) => void, options?: AddEventListenerOptions): () => void;
|
|
9
9
|
declare function addEventListener<K extends keyof WindowEventMap>(el: Window, event: K, listener: (this: Window, evt: WindowEventMap[K]) => void, options?: AddEventListenerOptions): () => void;
|
|
10
10
|
declare function addEventListener<K extends keyof MediaQueryListEventMap>(el: MediaQueryList, event: K, listener: (this: MediaQueryList, evt: MediaQueryListEventMap[K]) => void, options?: AddEventListenerOptions): () => void;
|
|
11
|
+
declare function getLineNumberAttr(el: HTMLElement, key?: string): number | undefined;
|
|
12
|
+
declare function clampDomOffset(node: Node, offset: number): number;
|
|
11
13
|
declare function extend<T extends object>(obj: T, attrs: Partial<T>): T;
|
|
12
14
|
declare function debounce<T extends (...args: any[]) => void>(func: T, wait: number): (...args: Parameters<T>) => void;
|
|
13
15
|
declare function round(value: number, precision?: number): number;
|
|
14
16
|
//#endregion
|
|
15
|
-
export { addEventListener, debounce, extend, h, round };
|
|
17
|
+
export { addEventListener, clampDomOffset, debounce, extend, getLineNumberAttr, h, round };
|
|
16
18
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","names":["h","K","HTMLElementTagNameMap","CSSStyleDeclaration","Partial","DOMStringMap","Node","Omit","Element","ShadowRoot","DocumentFragment","addEventListener","HTMLElementEventMap","HTMLElement","AddEventListenerOptions","DocumentEventMap","Document","WindowEventMap","Window","MediaQueryListEventMap","MediaQueryList","extend","T","debounce","Parameters","round"],"sources":["../../src/editor/utils.d.ts"],"sourcesContent":["export declare function h<K extends keyof HTMLElementTagNameMap>(tagName: K, props?: {\n style?: string | Partial<CSSStyleDeclaration>;\n dataset?: DOMStringMap | string[] | string;\n children?: (Node | string)[];\n} & Partial<Omit<HTMLElementTagNameMap[K], 'style' | 'dataset' | 'children'>>, parent?: Element | ShadowRoot | DocumentFragment): HTMLElementTagNameMap[K];\nexport declare function addEventListener<K extends keyof HTMLElementEventMap>(el: HTMLElement, event: K, listener: (this: HTMLElement, evt: HTMLElementEventMap[K]) => void, options?: AddEventListenerOptions): () => void;\nexport declare function addEventListener<K extends keyof DocumentEventMap>(el: Document, event: K, listener: (this: Document, evt: DocumentEventMap[K]) => void, options?: AddEventListenerOptions): () => void;\nexport declare function addEventListener<K extends keyof WindowEventMap>(el: Window, event: K, listener: (this: Window, evt: WindowEventMap[K]) => void, options?: AddEventListenerOptions): () => void;\nexport declare function addEventListener<K extends keyof MediaQueryListEventMap>(el: MediaQueryList, event: K, listener: (this: MediaQueryList, evt: MediaQueryListEventMap[K]) => void, options?: AddEventListenerOptions): () => void;\nexport declare function extend<T extends object>(obj: T, attrs: Partial<T>): T;\nexport declare function debounce<T extends (...args: any[]) => void>(func: T, wait: number): (...args: Parameters<T>) => void;\nexport declare function round(value: number, precision?: number): number;\n//# sourceMappingURL=utils.d.ts.map"],"mappings":";iBAAwBA,kBAAkBE,gCAAgCD,QAC7CE;EADLH,KAAC,CAAA,EAAA,MAAAC,GACJG,OADI,CACID,mBADJ,CAAA;EAAiBD,OAAAA,CAAAA,EAE5BG,YAF4BH,GAAAA,MAAAA,EAAAA,GAAAA,MAAAA;EAAgCD,QAAAA,CAAAA,EAAAA,CAG1DK,IAH0DL,GAAAA,MAAAA,CAAAA,EAAAA;CAC7CE,GAGzBC,OAHyBD,CAGjBI,IAHiBJ,CAGZD,qBAHYC,CAGUF,CAHVE,CAAAA,EAAAA,OAAAA,GAAAA,SAAAA,GAAAA,UAAAA,CAAAA,CAAAA,EAAAA,MAAAA,CAAAA,EAG2DK,OAH3DL,GAGqEM,UAHrEN,GAGkFO,gBAHlFP,CAAAA,EAGqGD,qBAHrGC,CAG2HF,CAH3HE,CAAAA;AAARC,iBAIGO,gBAJHP,CAAAA,UAAAA,MAIoCQ,mBAJpCR,CAAAA,CAAAA,EAAAA,EAI6DS,WAJ7DT,EAAAA,KAAAA,EAIiFH,CAJjFG,EAAAA,QAAAA,EAAAA,CAAAA,IAAAA,EAIqGS,WAJrGT,EAAAA,GAAAA,EAIuHQ,mBAJvHR,CAI2IH,CAJ3IG,CAAAA,EAAAA,GAAAA,IAAAA,EAAAA,OAAAA,CAAAA,EAIkKU,uBAJlKV,CAAAA,EAAAA,GAAAA,GAAAA,IAAAA;AACPC,iBAIUM,gBAJVN,CAAAA,UAAAA,MAI2CU,gBAJ3CV,CAAAA,CAAAA,EAAAA,EAIiEW,QAJjEX,EAAAA,KAAAA,EAIkFJ,CAJlFI,EAAAA,QAAAA,EAAAA,CAAAA,IAAAA,EAIsGW,QAJtGX,EAAAA,GAAAA,EAIqHU,gBAJrHV,CAIsIJ,CAJtII,CAAAA,EAAAA,GAAAA,IAAAA,EAAAA,OAAAA,CAAAA,EAI6JS,uBAJ7JT,CAAAA,EAAAA,GAAAA,GAAAA,IAAAA;AACEC,iBAIQK,gBAJRL,CAAAA,UAAAA,MAIyCW,cAJzCX,CAAAA,CAAAA,EAAAA,EAI6DY,MAJ7DZ,EAAAA,KAAAA,EAI4EL,CAJ5EK,EAAAA,QAAAA,EAAAA,CAAAA,IAAAA,EAIgGY,MAJhGZ,EAAAA,GAAAA,EAI6GW,cAJ7GX,CAI4HL,CAJ5HK,CAAAA,EAAAA,GAAAA,IAAAA,EAAAA,OAAAA,CAAAA,EAImJQ,uBAJnJR,CAAAA,EAAAA,GAAAA,GAAAA,IAAAA;AACCJ,iBAIOS,gBAJPT,CAAAA,UAAAA,MAIwCiB,sBAJxCjB,CAAAA,CAAAA,EAAAA,EAIoEkB,cAJpElB,EAAAA,KAAAA,EAI2FD,CAJ3FC,EAAAA,QAAAA,EAAAA,CAAAA,IAAAA,EAI+GkB,cAJ/GlB,EAAAA,GAAAA,EAIoIiB,sBAJpIjB,CAI2JD,CAJ3JC,CAAAA,EAAAA,GAAAA,IAAAA,EAAAA,OAAAA,CAAAA,EAIkLY,uBAJlLZ,CAAAA,EAAAA,GAAAA,GAAAA,IAAAA;AAAsBD,iBAKfoB,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","names":["h","K","HTMLElementTagNameMap","CSSStyleDeclaration","Partial","DOMStringMap","Node","Omit","Element","ShadowRoot","DocumentFragment","addEventListener","HTMLElementEventMap","HTMLElement","AddEventListenerOptions","DocumentEventMap","Document","WindowEventMap","Window","MediaQueryListEventMap","MediaQueryList","getLineNumberAttr","clampDomOffset","extend","T","debounce","Parameters","round"],"sources":["../../src/editor/utils.d.ts"],"sourcesContent":["export declare function h<K extends keyof HTMLElementTagNameMap>(tagName: K, props?: {\n style?: string | Partial<CSSStyleDeclaration>;\n dataset?: DOMStringMap | string[] | string;\n children?: (Node | string)[];\n} & Partial<Omit<HTMLElementTagNameMap[K], 'style' | 'dataset' | 'children'>>, parent?: Element | ShadowRoot | DocumentFragment): HTMLElementTagNameMap[K];\nexport declare function addEventListener<K extends keyof HTMLElementEventMap>(el: HTMLElement, event: K, listener: (this: HTMLElement, evt: HTMLElementEventMap[K]) => void, options?: AddEventListenerOptions): () => void;\nexport declare function addEventListener<K extends keyof DocumentEventMap>(el: Document, event: K, listener: (this: Document, evt: DocumentEventMap[K]) => void, options?: AddEventListenerOptions): () => void;\nexport declare function addEventListener<K extends keyof WindowEventMap>(el: Window, event: K, listener: (this: Window, evt: WindowEventMap[K]) => void, options?: AddEventListenerOptions): () => void;\nexport declare function addEventListener<K extends keyof MediaQueryListEventMap>(el: MediaQueryList, event: K, listener: (this: MediaQueryList, evt: MediaQueryListEventMap[K]) => void, options?: AddEventListenerOptions): () => void;\nexport declare function getLineNumberAttr(el: HTMLElement, key?: string): number | undefined;\nexport declare function clampDomOffset(node: Node, offset: number): number;\nexport declare function extend<T extends object>(obj: T, attrs: Partial<T>): T;\nexport declare function debounce<T extends (...args: any[]) => void>(func: T, wait: number): (...args: Parameters<T>) => void;\nexport declare function round(value: number, precision?: number): number;\n//# sourceMappingURL=utils.d.ts.map"],"mappings":"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"}
|
package/dist/editor/utils.js
CHANGED
|
@@ -18,6 +18,21 @@ function addEventListener(el, event, listener, options) {
|
|
|
18
18
|
el.addEventListener(event, listener, options);
|
|
19
19
|
return () => el.removeEventListener(event, listener);
|
|
20
20
|
}
|
|
21
|
+
function getLineNumberAttr(el, key = "line") {
|
|
22
|
+
const value = el.dataset[key];
|
|
23
|
+
if (value === void 0) return;
|
|
24
|
+
const lineNumber = parseInt(value, 10);
|
|
25
|
+
if (Number.isNaN(lineNumber)) return;
|
|
26
|
+
return lineNumber;
|
|
27
|
+
}
|
|
28
|
+
function clampDomOffset(node, offset) {
|
|
29
|
+
if (node.nodeType === 3) {
|
|
30
|
+
const length = node.textContent?.length ?? 0;
|
|
31
|
+
return Math.max(0, Math.min(offset, length));
|
|
32
|
+
}
|
|
33
|
+
if (node.nodeType === 1) return Math.max(0, Math.min(offset, node.childNodes.length));
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
21
36
|
function extend(obj, attrs) {
|
|
22
37
|
return Object.assign(obj, attrs);
|
|
23
38
|
}
|
|
@@ -33,5 +48,5 @@ function round(value, precision = 1e3) {
|
|
|
33
48
|
}
|
|
34
49
|
|
|
35
50
|
//#endregion
|
|
36
|
-
export { addEventListener, debounce, extend, h, round };
|
|
51
|
+
export { addEventListener, clampDomOffset, debounce, extend, getLineNumberAttr, h, round };
|
|
37
52
|
//# sourceMappingURL=utils.js.map
|
package/dist/editor/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":["timeout: ReturnType<typeof setTimeout>"],"sources":["../../src/editor/utils.ts"],"sourcesContent":["export function h<K extends keyof HTMLElementTagNameMap>(\n tagName: K,\n props?: {\n style?: string | Partial<CSSStyleDeclaration>;\n dataset?: DOMStringMap | string[] | string;\n children?: (Node | string)[];\n } & Partial<Omit<HTMLElementTagNameMap[K], 'style' | 'dataset' | 'children'>>,\n parent?: Element | ShadowRoot | DocumentFragment\n): HTMLElementTagNameMap[K] {\n const { style, dataset, children, ...attrs } = props ?? {};\n const el = document.createElement(tagName);\n Object.assign(el, attrs);\n if (style !== undefined) {\n if (typeof style === 'string') {\n el.style.cssText = style;\n } else {\n Object.assign(el.style, style);\n }\n }\n if (dataset !== undefined) {\n if (typeof dataset === 'string') {\n el.dataset[dataset] = '';\n } else if (Array.isArray(dataset)) {\n dataset.forEach((key) => {\n el.dataset[key] = '';\n });\n } else {\n Object.assign(el.dataset, dataset);\n }\n }\n if (children !== undefined) {\n el.replaceChildren(...children);\n }\n if (parent !== undefined) {\n parent.appendChild(el);\n }\n return el;\n}\n\nexport function addEventListener<K extends keyof HTMLElementEventMap>(\n el: HTMLElement,\n event: K,\n listener: (this: HTMLElement, evt: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions\n): () => void;\nexport function addEventListener<K extends keyof DocumentEventMap>(\n el: Document,\n event: K,\n listener: (this: Document, evt: DocumentEventMap[K]) => void,\n options?: AddEventListenerOptions\n): () => void;\nexport function addEventListener<K extends keyof WindowEventMap>(\n el: Window,\n event: K,\n listener: (this: Window, evt: WindowEventMap[K]) => void,\n options?: AddEventListenerOptions\n): () => void;\nexport function addEventListener<K extends keyof MediaQueryListEventMap>(\n el: MediaQueryList,\n event: K,\n listener: (this: MediaQueryList, evt: MediaQueryListEventMap[K]) => void,\n options?: AddEventListenerOptions\n): () => void;\nexport function addEventListener(\n el: HTMLElement | Document | ShadowRoot | Window | MediaQueryList,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions\n) {\n el.addEventListener(event, listener, options);\n return () => el.removeEventListener(event, listener);\n}\n\nexport function extend<T extends object>(obj: T, attrs: Partial<T>): T {\n return Object.assign(obj, attrs);\n}\n\n// oxlint-disable-next-line typescript/no-explicit-any\nexport function debounce<T extends (...args: any[]) => void>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout>;\n return function (this: ThisType<T>, ...args: Parameters<T>) {\n clearTimeout(timeout);\n timeout = setTimeout(() => func.apply(this, args), wait);\n };\n}\n\nexport function round(value: number, precision: number = 1000): number {\n return Math.round(value * precision) / precision;\n}\n"],"mappings":";AAAA,SAAgB,EACd,SACA,OAKA,QAC0B;CAC1B,MAAM,EAAE,OAAO,SAAS,SAAU,GAAG,UAAU,SAAS,EAAE;CAC1D,MAAM,KAAK,SAAS,cAAc,QAAQ;AAC1C,QAAO,OAAO,IAAI,MAAM;AACxB,KAAI,UAAU,OACZ,KAAI,OAAO,UAAU,SACnB,IAAG,MAAM,UAAU;KAEnB,QAAO,OAAO,GAAG,OAAO,MAAM;AAGlC,KAAI,YAAY,OACd,KAAI,OAAO,YAAY,SACrB,IAAG,QAAQ,WAAW;UACb,MAAM,QAAQ,QAAQ,CAC/B,SAAQ,SAAS,QAAQ;AACvB,KAAG,QAAQ,OAAO;GAClB;KAEF,QAAO,OAAO,GAAG,SAAS,QAAQ;AAGtC,KAAI,aAAa,OACf,IAAG,gBAAgB,GAAG,SAAS;AAEjC,KAAI,WAAW,OACb,QAAO,YAAY,GAAG;AAExB,QAAO;;AA2BT,SAAgB,iBACd,IACA,OACA,UACA,SACA;AACA,IAAG,iBAAiB,OAAO,UAAU,QAAQ;AAC7C,cAAa,GAAG,oBAAoB,OAAO,SAAS;;AAGtD,SAAgB,OAAyB,KAAQ,OAAsB;AACrE,QAAO,OAAO,OAAO,KAAK,MAAM;;AAIlC,SAAgB,SACd,MACA,MACkC;CAClC,IAAIA;AACJ,QAAO,SAA6B,GAAG,MAAqB;AAC1D,eAAa,QAAQ;AACrB,YAAU,iBAAiB,KAAK,MAAM,MAAM,KAAK,EAAE,KAAK;;;AAI5D,SAAgB,MAAM,OAAe,YAAoB,KAAc;AACrE,QAAO,KAAK,MAAM,QAAQ,UAAU,GAAG"}
|
|
1
|
+
{"version":3,"file":"utils.js","names":["timeout: ReturnType<typeof setTimeout>"],"sources":["../../src/editor/utils.ts"],"sourcesContent":["export function h<K extends keyof HTMLElementTagNameMap>(\n tagName: K,\n props?: {\n style?: string | Partial<CSSStyleDeclaration>;\n dataset?: DOMStringMap | string[] | string;\n children?: (Node | string)[];\n } & Partial<Omit<HTMLElementTagNameMap[K], 'style' | 'dataset' | 'children'>>,\n parent?: Element | ShadowRoot | DocumentFragment\n): HTMLElementTagNameMap[K] {\n const { style, dataset, children, ...attrs } = props ?? {};\n const el = document.createElement(tagName);\n Object.assign(el, attrs);\n if (style !== undefined) {\n if (typeof style === 'string') {\n el.style.cssText = style;\n } else {\n Object.assign(el.style, style);\n }\n }\n if (dataset !== undefined) {\n if (typeof dataset === 'string') {\n el.dataset[dataset] = '';\n } else if (Array.isArray(dataset)) {\n dataset.forEach((key) => {\n el.dataset[key] = '';\n });\n } else {\n Object.assign(el.dataset, dataset);\n }\n }\n if (children !== undefined) {\n el.replaceChildren(...children);\n }\n if (parent !== undefined) {\n parent.appendChild(el);\n }\n return el;\n}\n\nexport function addEventListener<K extends keyof HTMLElementEventMap>(\n el: HTMLElement,\n event: K,\n listener: (this: HTMLElement, evt: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions\n): () => void;\nexport function addEventListener<K extends keyof DocumentEventMap>(\n el: Document,\n event: K,\n listener: (this: Document, evt: DocumentEventMap[K]) => void,\n options?: AddEventListenerOptions\n): () => void;\nexport function addEventListener<K extends keyof WindowEventMap>(\n el: Window,\n event: K,\n listener: (this: Window, evt: WindowEventMap[K]) => void,\n options?: AddEventListenerOptions\n): () => void;\nexport function addEventListener<K extends keyof MediaQueryListEventMap>(\n el: MediaQueryList,\n event: K,\n listener: (this: MediaQueryList, evt: MediaQueryListEventMap[K]) => void,\n options?: AddEventListenerOptions\n): () => void;\nexport function addEventListener(\n el: HTMLElement | Document | ShadowRoot | Window | MediaQueryList,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions\n) {\n el.addEventListener(event, listener, options);\n return () => el.removeEventListener(event, listener);\n}\n\nexport function getLineNumberAttr(\n el: HTMLElement,\n key = 'line'\n): number | undefined {\n const value = el.dataset[key];\n if (value === undefined) {\n return undefined;\n }\n const lineNumber = parseInt(value, 10);\n if (Number.isNaN(lineNumber)) {\n return undefined;\n }\n return lineNumber;\n}\n\nexport function clampDomOffset(node: Node, offset: number): number {\n if (node.nodeType === 3) {\n const length = (node as Text).textContent?.length ?? 0;\n return Math.max(0, Math.min(offset, length));\n }\n if (node.nodeType === 1) {\n return Math.max(0, Math.min(offset, node.childNodes.length));\n }\n return 0;\n}\n\nexport function extend<T extends object>(obj: T, attrs: Partial<T>): T {\n return Object.assign(obj, attrs);\n}\n\n// oxlint-disable-next-line typescript/no-explicit-any\nexport function debounce<T extends (...args: any[]) => void>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout>;\n return function (this: ThisType<T>, ...args: Parameters<T>) {\n clearTimeout(timeout);\n timeout = setTimeout(() => func.apply(this, args), wait);\n };\n}\n\nexport function round(value: number, precision: number = 1000): number {\n return Math.round(value * precision) / precision;\n}\n"],"mappings":";AAAA,SAAgB,EACd,SACA,OAKA,QAC0B;CAC1B,MAAM,EAAE,OAAO,SAAS,SAAU,GAAG,UAAU,SAAS,EAAE;CAC1D,MAAM,KAAK,SAAS,cAAc,QAAQ;AAC1C,QAAO,OAAO,IAAI,MAAM;AACxB,KAAI,UAAU,OACZ,KAAI,OAAO,UAAU,SACnB,IAAG,MAAM,UAAU;KAEnB,QAAO,OAAO,GAAG,OAAO,MAAM;AAGlC,KAAI,YAAY,OACd,KAAI,OAAO,YAAY,SACrB,IAAG,QAAQ,WAAW;UACb,MAAM,QAAQ,QAAQ,CAC/B,SAAQ,SAAS,QAAQ;AACvB,KAAG,QAAQ,OAAO;GAClB;KAEF,QAAO,OAAO,GAAG,SAAS,QAAQ;AAGtC,KAAI,aAAa,OACf,IAAG,gBAAgB,GAAG,SAAS;AAEjC,KAAI,WAAW,OACb,QAAO,YAAY,GAAG;AAExB,QAAO;;AA2BT,SAAgB,iBACd,IACA,OACA,UACA,SACA;AACA,IAAG,iBAAiB,OAAO,UAAU,QAAQ;AAC7C,cAAa,GAAG,oBAAoB,OAAO,SAAS;;AAGtD,SAAgB,kBACd,IACA,MAAM,QACc;CACpB,MAAM,QAAQ,GAAG,QAAQ;AACzB,KAAI,UAAU,OACZ;CAEF,MAAM,aAAa,SAAS,OAAO,GAAG;AACtC,KAAI,OAAO,MAAM,WAAW,CAC1B;AAEF,QAAO;;AAGT,SAAgB,eAAe,MAAY,QAAwB;AACjE,KAAI,KAAK,aAAa,GAAG;EACvB,MAAM,SAAU,KAAc,aAAa,UAAU;AACrD,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,OAAO,CAAC;;AAE9C,KAAI,KAAK,aAAa,EACpB,QAAO,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,KAAK,WAAW,OAAO,CAAC;AAE9D,QAAO;;AAGT,SAAgB,OAAyB,KAAQ,OAAsB;AACrE,QAAO,OAAO,OAAO,KAAK,MAAM;;AAIlC,SAAgB,SACd,MACA,MACkC;CAClC,IAAIA;AACJ,QAAO,SAA6B,GAAG,MAAqB;AAC1D,eAAa,QAAQ;AACrB,YAAU,iBAAiB,KAAK,MAAM,MAAM,KAAK,EAAE,KAAK;;;AAI5D,SAAgB,MAAM,OAAe,YAAoB,KAAc;AACrE,QAAO,KAAK,MAAM,QAAQ,UAAU,GAAG"}
|