stream-monaco 0.0.13 → 0.0.15
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/README.md +8 -0
- package/README.zh-CN.md +6 -2
- package/dist/index.cjs +102 -39
- package/dist/index.d.cts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +102 -39
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -80,6 +80,13 @@ The `useMonaco()` function returns an object with the following methods:
|
|
|
80
80
|
- **`setUpdateThrottleMs(ms)`** - Change update throttle at runtime
|
|
81
81
|
- **`getUpdateThrottleMs()`** - Get current throttle value
|
|
82
82
|
|
|
83
|
+
#### Diff streaming highlight tip
|
|
84
|
+
|
|
85
|
+
Monaco's diff computation is async and cancels/restarts when models change. If you stream updates too frequently (e.g. per token / every frame), the diff may only finish once streaming stops, so the difference highlights appear "at the end".
|
|
86
|
+
|
|
87
|
+
- Set `diffUpdateThrottleMs` (default: 50) to let the diff worker complete intermediate computations during streaming.
|
|
88
|
+
- Set it to `0` to restore pure RAF batching (most responsive, but may delay diff highlights under heavy streaming).
|
|
89
|
+
|
|
83
90
|
### Install
|
|
84
91
|
|
|
85
92
|
```bash
|
|
@@ -473,6 +480,7 @@ cleanupEditor()
|
|
|
473
480
|
### Troubleshooting
|
|
474
481
|
|
|
475
482
|
- Editor invisible after build: configure Monaco web workers correctly.
|
|
483
|
+
- Diff editor renders blank during early mount/streaming: ensure Monaco workers are configured before `createEditor`/`createDiffEditor` (e.g. call `preloadMonacoWorkers()` as early as possible).
|
|
476
484
|
- Theme not applied: ensure theme name is included in `themes`.
|
|
477
485
|
- Language highlighting missing: ensure the language is included and supported by Shiki.
|
|
478
486
|
|
package/README.zh-CN.md
CHANGED
|
@@ -720,11 +720,15 @@ onUnmounted(() => {
|
|
|
720
720
|
|
|
721
721
|
确保正确配置了 Monaco Editor 的 Web Workers(参考上面的 Vite/Webpack 配置)。
|
|
722
722
|
|
|
723
|
-
#### 2.
|
|
723
|
+
#### 2. Diff 编辑器流式更新时内容区空白
|
|
724
|
+
|
|
725
|
+
确保在调用 `createEditor` / `createDiffEditor` 之前已正确配置 Monaco 的 workers(建议尽早调用 `preloadMonacoWorkers()`)。
|
|
726
|
+
|
|
727
|
+
#### 3. 主题不生效
|
|
724
728
|
|
|
725
729
|
检查主题名称是否正确,确保主题已在 `themes` 数组中注册。
|
|
726
730
|
|
|
727
|
-
####
|
|
731
|
+
#### 4. 语言高亮不工作
|
|
728
732
|
|
|
729
733
|
确保语言已在 `languages` 数组中包含,并且 Shiki 支持该语言。
|
|
730
734
|
|
package/dist/index.cjs
CHANGED
|
@@ -516,11 +516,15 @@ var DiffEditorManager = class {
|
|
|
516
516
|
revealBatchOnIdleMsOption;
|
|
517
517
|
scrollWatcherSuppressionMs = 500;
|
|
518
518
|
diffScrollWatcherSuppressionTimer = null;
|
|
519
|
-
|
|
519
|
+
appendBufferOriginalDiff = [];
|
|
520
|
+
appendBufferModifiedDiff = [];
|
|
520
521
|
appendBufferDiffScheduled = false;
|
|
522
|
+
diffUpdateThrottleMs = 50;
|
|
523
|
+
lastAppendFlushTimeDiff = 0;
|
|
524
|
+
appendFlushThrottleTimerDiff = null;
|
|
521
525
|
rafScheduler = createRafScheduler();
|
|
522
526
|
diffHeightManager = null;
|
|
523
|
-
constructor(options, maxHeightValue, maxHeightCSS, autoScrollOnUpdate, autoScrollInitial, autoScrollThresholdPx, autoScrollThresholdLines, diffAutoScroll, revealDebounceMsOption) {
|
|
527
|
+
constructor(options, maxHeightValue, maxHeightCSS, autoScrollOnUpdate, autoScrollInitial, autoScrollThresholdPx, autoScrollThresholdLines, diffAutoScroll, revealDebounceMsOption, diffUpdateThrottleMsOption) {
|
|
524
528
|
this.options = options;
|
|
525
529
|
this.maxHeightValue = maxHeightValue;
|
|
526
530
|
this.maxHeightCSS = maxHeightCSS;
|
|
@@ -531,6 +535,40 @@ var DiffEditorManager = class {
|
|
|
531
535
|
this.diffAutoScroll = diffAutoScroll;
|
|
532
536
|
this.revealDebounceMsOption = revealDebounceMsOption;
|
|
533
537
|
}
|
|
538
|
+
scheduleFlushAppendBufferDiff() {
|
|
539
|
+
if (this.appendBufferDiffScheduled) return;
|
|
540
|
+
this.appendBufferDiffScheduled = true;
|
|
541
|
+
const schedule = () => {
|
|
542
|
+
this.rafScheduler.schedule("appendDiff", () => this.flushAppendBufferDiff());
|
|
543
|
+
};
|
|
544
|
+
const throttle = this.diffUpdateThrottleMs;
|
|
545
|
+
if (!throttle) {
|
|
546
|
+
schedule();
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
const now = Date.now();
|
|
550
|
+
const since = now - this.lastAppendFlushTimeDiff;
|
|
551
|
+
if (since >= throttle) {
|
|
552
|
+
schedule();
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
if (this.appendFlushThrottleTimerDiff != null) return;
|
|
556
|
+
const wait = throttle - since;
|
|
557
|
+
this.appendFlushThrottleTimerDiff = setTimeout(() => {
|
|
558
|
+
this.appendFlushThrottleTimerDiff = null;
|
|
559
|
+
schedule();
|
|
560
|
+
}, wait);
|
|
561
|
+
}
|
|
562
|
+
flushOriginalAppendBufferSync() {
|
|
563
|
+
if (!this.originalModel) return;
|
|
564
|
+
if (this.appendBufferOriginalDiff.length === 0) return;
|
|
565
|
+
this.rafScheduler.cancel("appendDiff");
|
|
566
|
+
this.appendBufferDiffScheduled = false;
|
|
567
|
+
const text = this.appendBufferOriginalDiff.join("");
|
|
568
|
+
this.appendBufferOriginalDiff.length = 0;
|
|
569
|
+
if (!text) return;
|
|
570
|
+
this.appendToModel(this.originalModel, text);
|
|
571
|
+
}
|
|
534
572
|
computedHeight() {
|
|
535
573
|
var _originalEditor$getMo, _modifiedEditor$getMo, _originalEditor$getSc, _modifiedEditor$getSc;
|
|
536
574
|
if (!this.diffEditorView) return Math.min(1 * 18 + padding, this.maxHeightValue);
|
|
@@ -778,6 +816,7 @@ var DiffEditorManager = class {
|
|
|
778
816
|
});
|
|
779
817
|
this.lastKnownOriginalCode = originalCode;
|
|
780
818
|
this.lastKnownModifiedCode = modifiedCode;
|
|
819
|
+
this.diffUpdateThrottleMs = this.options.diffUpdateThrottleMs ?? 50;
|
|
781
820
|
this.shouldAutoScrollDiff = !!(this.autoScrollInitial && this.diffAutoScroll);
|
|
782
821
|
if (this.diffScrollWatcher) {
|
|
783
822
|
this.diffScrollWatcher.dispose();
|
|
@@ -894,16 +933,14 @@ var DiffEditorManager = class {
|
|
|
894
933
|
const prevM = this.lastKnownModifiedCode;
|
|
895
934
|
let didImmediate = false;
|
|
896
935
|
if (originalCode !== prevO && originalCode.startsWith(prevO)) {
|
|
897
|
-
this.
|
|
936
|
+
this.appendOriginal(originalCode.slice(prevO.length));
|
|
898
937
|
this.lastKnownOriginalCode = originalCode;
|
|
899
938
|
didImmediate = true;
|
|
900
939
|
}
|
|
901
940
|
if (modifiedCode !== prevM && modifiedCode.startsWith(prevM)) {
|
|
902
|
-
|
|
903
|
-
this.appendToModel(this.modifiedModel, modifiedCode.slice(prevM.length));
|
|
941
|
+
this.appendModified(modifiedCode.slice(prevM.length));
|
|
904
942
|
this.lastKnownModifiedCode = modifiedCode;
|
|
905
943
|
didImmediate = true;
|
|
906
|
-
this.maybeScrollDiffToBottom(this.modifiedModel.getLineCount(), prevLine);
|
|
907
944
|
}
|
|
908
945
|
if (originalCode !== this.lastKnownOriginalCode || modifiedCode !== this.lastKnownModifiedCode) {
|
|
909
946
|
this.pendingDiffUpdate = {
|
|
@@ -921,8 +958,11 @@ var DiffEditorManager = class {
|
|
|
921
958
|
}
|
|
922
959
|
const prev = this.lastKnownOriginalCode ?? this.originalModel.getValue();
|
|
923
960
|
if (prev === newCode) return;
|
|
924
|
-
if (newCode.startsWith(prev) && prev.length < newCode.length) this.
|
|
925
|
-
else
|
|
961
|
+
if (newCode.startsWith(prev) && prev.length < newCode.length) this.appendOriginal(newCode.slice(prev.length), codeLanguage);
|
|
962
|
+
else {
|
|
963
|
+
this.flushOriginalAppendBufferSync();
|
|
964
|
+
this.applyMinimalEditToModel(this.originalModel, prev, newCode);
|
|
965
|
+
}
|
|
926
966
|
this.lastKnownOriginalCode = newCode;
|
|
927
967
|
}
|
|
928
968
|
updateModified(newCode, codeLanguage) {
|
|
@@ -933,12 +973,12 @@ var DiffEditorManager = class {
|
|
|
933
973
|
}
|
|
934
974
|
const prev = this.lastKnownModifiedCode ?? this.modifiedModel.getValue();
|
|
935
975
|
if (prev === newCode) return;
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
this.
|
|
939
|
-
this.
|
|
940
|
-
|
|
941
|
-
this.applyMinimalEditToModel(this.modifiedModel,
|
|
976
|
+
if (newCode.startsWith(prev) && prev.length < newCode.length) this.appendModified(newCode.slice(prev.length), codeLanguage);
|
|
977
|
+
else {
|
|
978
|
+
this.flushModifiedAppendBufferSync();
|
|
979
|
+
const prevAfterFlush = this.modifiedModel.getValue();
|
|
980
|
+
const prevLine = this.modifiedModel.getLineCount();
|
|
981
|
+
this.applyMinimalEditToModel(this.modifiedModel, prevAfterFlush, newCode);
|
|
942
982
|
const newLine = this.modifiedModel.getLineCount();
|
|
943
983
|
if (newLine !== prevLine) {
|
|
944
984
|
const shouldImmediate = this.shouldPerformImmediateRevealDiff();
|
|
@@ -972,8 +1012,8 @@ var DiffEditorManager = class {
|
|
|
972
1012
|
const lang = processedLanguage(codeLanguage);
|
|
973
1013
|
if (lang && this.originalModel.getLanguageId() !== lang) monaco_shim_exports.editor.setModelLanguage(this.originalModel, lang);
|
|
974
1014
|
}
|
|
975
|
-
this.
|
|
976
|
-
this.
|
|
1015
|
+
this.appendBufferOriginalDiff.push(appendText);
|
|
1016
|
+
this.scheduleFlushAppendBufferDiff();
|
|
977
1017
|
}
|
|
978
1018
|
appendModified(appendText, codeLanguage) {
|
|
979
1019
|
if (!this.diffEditorView || !this.modifiedModel || !appendText) return;
|
|
@@ -981,11 +1021,8 @@ var DiffEditorManager = class {
|
|
|
981
1021
|
const lang = processedLanguage(codeLanguage);
|
|
982
1022
|
if (lang && this.modifiedModel.getLanguageId() !== lang) monaco_shim_exports.editor.setModelLanguage(this.modifiedModel, lang);
|
|
983
1023
|
}
|
|
984
|
-
this.
|
|
985
|
-
|
|
986
|
-
this.appendBufferDiffScheduled = true;
|
|
987
|
-
this.rafScheduler.schedule("appendDiff", () => this.flushAppendBufferDiff());
|
|
988
|
-
}
|
|
1024
|
+
this.appendBufferModifiedDiff.push(appendText);
|
|
1025
|
+
this.scheduleFlushAppendBufferDiff();
|
|
989
1026
|
}
|
|
990
1027
|
setLanguage(language, languages$1) {
|
|
991
1028
|
if (!languages$1.includes(language)) {
|
|
@@ -1009,7 +1046,12 @@ var DiffEditorManager = class {
|
|
|
1009
1046
|
this.pendingDiffUpdate = null;
|
|
1010
1047
|
this.rafScheduler.cancel("appendDiff");
|
|
1011
1048
|
this.appendBufferDiffScheduled = false;
|
|
1012
|
-
this.
|
|
1049
|
+
this.appendBufferOriginalDiff.length = 0;
|
|
1050
|
+
this.appendBufferModifiedDiff.length = 0;
|
|
1051
|
+
if (this.appendFlushThrottleTimerDiff != null) {
|
|
1052
|
+
clearTimeout(this.appendFlushThrottleTimerDiff);
|
|
1053
|
+
this.appendFlushThrottleTimerDiff = null;
|
|
1054
|
+
}
|
|
1013
1055
|
this.rafScheduler.cancel("content-size-change-diff");
|
|
1014
1056
|
this.rafScheduler.cancel("sync-last-known-modified");
|
|
1015
1057
|
if (this.diffScrollWatcher) {
|
|
@@ -1056,6 +1098,14 @@ var DiffEditorManager = class {
|
|
|
1056
1098
|
safeClean() {
|
|
1057
1099
|
this.rafScheduler.cancel("diff");
|
|
1058
1100
|
this.pendingDiffUpdate = null;
|
|
1101
|
+
this.rafScheduler.cancel("appendDiff");
|
|
1102
|
+
this.appendBufferDiffScheduled = false;
|
|
1103
|
+
this.appendBufferOriginalDiff.length = 0;
|
|
1104
|
+
this.appendBufferModifiedDiff.length = 0;
|
|
1105
|
+
if (this.appendFlushThrottleTimerDiff != null) {
|
|
1106
|
+
clearTimeout(this.appendFlushThrottleTimerDiff);
|
|
1107
|
+
this.appendFlushThrottleTimerDiff = null;
|
|
1108
|
+
}
|
|
1059
1109
|
if (this.diffScrollWatcher) {
|
|
1060
1110
|
this.diffScrollWatcher.dispose();
|
|
1061
1111
|
this.diffScrollWatcher = null;
|
|
@@ -1107,6 +1157,8 @@ var DiffEditorManager = class {
|
|
|
1107
1157
|
}
|
|
1108
1158
|
const { original, modified, lang } = this.pendingDiffUpdate;
|
|
1109
1159
|
this.pendingDiffUpdate = null;
|
|
1160
|
+
this.flushOriginalAppendBufferSync();
|
|
1161
|
+
this.flushModifiedAppendBufferSync();
|
|
1110
1162
|
if (lang) {
|
|
1111
1163
|
const plang = processedLanguage(lang);
|
|
1112
1164
|
if (plang) {
|
|
@@ -1124,14 +1176,7 @@ var DiffEditorManager = class {
|
|
|
1124
1176
|
else this.applyMinimalEditToModel(o, prevO, original);
|
|
1125
1177
|
this.lastKnownOriginalCode = original;
|
|
1126
1178
|
}
|
|
1127
|
-
|
|
1128
|
-
const buffered = this.appendBufferDiff.length > 0 ? this.appendBufferDiff.join("") : "";
|
|
1129
|
-
if (this.appendBufferDiff.length > 0) try {
|
|
1130
|
-
prevM = m.getValue() + buffered;
|
|
1131
|
-
this.lastKnownModifiedCode = prevM;
|
|
1132
|
-
} catch {
|
|
1133
|
-
prevM = (this.lastKnownModifiedCode ?? "") + buffered;
|
|
1134
|
-
}
|
|
1179
|
+
const prevM = m.getValue();
|
|
1135
1180
|
const prevMLineCount = m.getLineCount();
|
|
1136
1181
|
if (prevM !== modified) {
|
|
1137
1182
|
if (modified.startsWith(prevM) && prevM.length < modified.length) this.appendToModel(m, modified.slice(prevM.length));
|
|
@@ -1151,17 +1196,33 @@ var DiffEditorManager = class {
|
|
|
1151
1196
|
}
|
|
1152
1197
|
}
|
|
1153
1198
|
}
|
|
1199
|
+
flushModifiedAppendBufferSync() {
|
|
1200
|
+
if (!this.modifiedModel) return;
|
|
1201
|
+
if (this.appendBufferModifiedDiff.length === 0) return;
|
|
1202
|
+
this.rafScheduler.cancel("appendDiff");
|
|
1203
|
+
this.appendBufferDiffScheduled = false;
|
|
1204
|
+
const text = this.appendBufferModifiedDiff.join("");
|
|
1205
|
+
this.appendBufferModifiedDiff.length = 0;
|
|
1206
|
+
if (!text) return;
|
|
1207
|
+
this.appendToModel(this.modifiedModel, text);
|
|
1208
|
+
}
|
|
1154
1209
|
async flushAppendBufferDiff() {
|
|
1155
1210
|
if (!this.diffEditorView) return;
|
|
1156
|
-
if (this.
|
|
1211
|
+
if (this.appendBufferOriginalDiff.length === 0 && this.appendBufferModifiedDiff.length === 0) return;
|
|
1212
|
+
this.lastAppendFlushTimeDiff = Date.now();
|
|
1157
1213
|
this.appendBufferDiffScheduled = false;
|
|
1214
|
+
if (this.originalModel && this.appendBufferOriginalDiff.length > 0) {
|
|
1215
|
+
const oText = this.appendBufferOriginalDiff.join("");
|
|
1216
|
+
this.appendBufferOriginalDiff.length = 0;
|
|
1217
|
+
if (oText) this.appendToModel(this.originalModel, oText);
|
|
1218
|
+
}
|
|
1158
1219
|
const me = this.diffEditorView.getModifiedEditor();
|
|
1159
1220
|
const model = me.getModel();
|
|
1160
1221
|
if (!model) {
|
|
1161
|
-
this.
|
|
1222
|
+
this.appendBufferModifiedDiff.length = 0;
|
|
1162
1223
|
return;
|
|
1163
1224
|
}
|
|
1164
|
-
let parts = this.
|
|
1225
|
+
let parts = this.appendBufferModifiedDiff.splice(0);
|
|
1165
1226
|
const prevLineInit = model.getLineCount();
|
|
1166
1227
|
const totalText = parts.join("");
|
|
1167
1228
|
const totalChars = totalText.length;
|
|
@@ -1236,7 +1297,7 @@ var DiffEditorManager = class {
|
|
|
1236
1297
|
return;
|
|
1237
1298
|
}
|
|
1238
1299
|
const text = totalText;
|
|
1239
|
-
this.
|
|
1300
|
+
this.appendBufferModifiedDiff.length = 0;
|
|
1240
1301
|
prevLine = model.getLineCount();
|
|
1241
1302
|
const lastColumn = model.getLineMaxColumn(prevLine);
|
|
1242
1303
|
const range = new monaco_shim_exports.Range(prevLine, lastColumn, prevLine, lastColumn);
|
|
@@ -1956,15 +2017,17 @@ async function preloadMonacoWorkers() {
|
|
|
1956
2017
|
javascript: workerUrlTs
|
|
1957
2018
|
};
|
|
1958
2019
|
try {
|
|
1959
|
-
await Promise.all(unique.map((u) => fetch(u, {
|
|
1960
|
-
method: "GET",
|
|
1961
|
-
cache: "force-cache"
|
|
1962
|
-
}).catch(() => void 0)));
|
|
1963
2020
|
self.MonacoEnvironment = { getWorker(_, label) {
|
|
1964
2021
|
const url = workerUrlByLabel[label] ?? workerUrlEditor;
|
|
1965
2022
|
return new Worker(url, { type: "module" });
|
|
1966
2023
|
} };
|
|
1967
2024
|
} catch {}
|
|
2025
|
+
try {
|
|
2026
|
+
await Promise.all(unique.map((u) => fetch(u, {
|
|
2027
|
+
method: "GET",
|
|
2028
|
+
cache: "force-cache"
|
|
2029
|
+
}).catch(() => void 0)));
|
|
2030
|
+
} catch {}
|
|
1968
2031
|
}
|
|
1969
2032
|
|
|
1970
2033
|
//#endregion
|
|
@@ -2444,7 +2507,7 @@ function useMonaco(monacoOptions = {}) {
|
|
|
2444
2507
|
try {
|
|
2445
2508
|
monaco_shim_exports.editor.setTheme(initialThemeName);
|
|
2446
2509
|
} catch {}
|
|
2447
|
-
diffMgr = new DiffEditorManager(monacoOptions, maxHeightValue, maxHeightCSS, autoScrollOnUpdate, autoScrollInitial, autoScrollThresholdPx, autoScrollThresholdLines, diffAutoScroll, monacoOptions.revealDebounceMs);
|
|
2510
|
+
diffMgr = new DiffEditorManager(monacoOptions, maxHeightValue, maxHeightCSS, autoScrollOnUpdate, autoScrollInitial, autoScrollThresholdPx, autoScrollThresholdLines, diffAutoScroll, monacoOptions.revealDebounceMs, monacoOptions.diffUpdateThrottleMs);
|
|
2448
2511
|
diffEditorView = await diffMgr.createDiffEditor(container, originalCode, modifiedCode, language, initialThemeName);
|
|
2449
2512
|
if (typeof monacoOptions.onThemeChange === "function") monacoOptions.onThemeChange(initialThemeName);
|
|
2450
2513
|
const models = diffMgr.getDiffModels();
|
package/dist/index.d.cts
CHANGED
|
@@ -69,6 +69,18 @@ interface MonacoOptions extends monaco$1.editor.IStandaloneEditorConstructionOpt
|
|
|
69
69
|
* - Default (library): 50
|
|
70
70
|
*/
|
|
71
71
|
updateThrottleMs?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Time window (ms) used to throttle diff streaming updates in addition to RAF batching.
|
|
74
|
+
* This affects `appendOriginal`/`appendModified` and the fast-path append branches of `updateDiff`.
|
|
75
|
+
*
|
|
76
|
+
* Why: Monaco's diff computation is async and cancels/restarts when models change.
|
|
77
|
+
* If you apply edits every frame (or per token), the diff may only finish once
|
|
78
|
+
* streaming stops, so the highlights appear "at the end".
|
|
79
|
+
*
|
|
80
|
+
* - 0 means only RAF-based coalescing (more responsive, but can starve diff computation).
|
|
81
|
+
* - Default (library): 50
|
|
82
|
+
*/
|
|
83
|
+
diffUpdateThrottleMs?: number;
|
|
72
84
|
/**
|
|
73
85
|
* When attempting the "minimal edit" algorithm, if prev.length + next.length
|
|
74
86
|
* exceeds this number the library will fall back to full `setValue` to avoid
|
package/dist/index.d.ts
CHANGED
|
@@ -68,6 +68,18 @@ interface MonacoOptions extends monaco$1.editor.IStandaloneEditorConstructionOpt
|
|
|
68
68
|
* - Default (library): 50
|
|
69
69
|
*/
|
|
70
70
|
updateThrottleMs?: number;
|
|
71
|
+
/**
|
|
72
|
+
* Time window (ms) used to throttle diff streaming updates in addition to RAF batching.
|
|
73
|
+
* This affects `appendOriginal`/`appendModified` and the fast-path append branches of `updateDiff`.
|
|
74
|
+
*
|
|
75
|
+
* Why: Monaco's diff computation is async and cancels/restarts when models change.
|
|
76
|
+
* If you apply edits every frame (or per token), the diff may only finish once
|
|
77
|
+
* streaming stops, so the highlights appear "at the end".
|
|
78
|
+
*
|
|
79
|
+
* - 0 means only RAF-based coalescing (more responsive, but can starve diff computation).
|
|
80
|
+
* - Default (library): 50
|
|
81
|
+
*/
|
|
82
|
+
diffUpdateThrottleMs?: number;
|
|
71
83
|
/**
|
|
72
84
|
* When attempting the "minimal edit" algorithm, if prev.length + next.length
|
|
73
85
|
* exceeds this number the library will fall back to full `setValue` to avoid
|
package/dist/index.js
CHANGED
|
@@ -488,11 +488,15 @@ var DiffEditorManager = class {
|
|
|
488
488
|
revealBatchOnIdleMsOption;
|
|
489
489
|
scrollWatcherSuppressionMs = 500;
|
|
490
490
|
diffScrollWatcherSuppressionTimer = null;
|
|
491
|
-
|
|
491
|
+
appendBufferOriginalDiff = [];
|
|
492
|
+
appendBufferModifiedDiff = [];
|
|
492
493
|
appendBufferDiffScheduled = false;
|
|
494
|
+
diffUpdateThrottleMs = 50;
|
|
495
|
+
lastAppendFlushTimeDiff = 0;
|
|
496
|
+
appendFlushThrottleTimerDiff = null;
|
|
493
497
|
rafScheduler = createRafScheduler();
|
|
494
498
|
diffHeightManager = null;
|
|
495
|
-
constructor(options, maxHeightValue, maxHeightCSS, autoScrollOnUpdate, autoScrollInitial, autoScrollThresholdPx, autoScrollThresholdLines, diffAutoScroll, revealDebounceMsOption) {
|
|
499
|
+
constructor(options, maxHeightValue, maxHeightCSS, autoScrollOnUpdate, autoScrollInitial, autoScrollThresholdPx, autoScrollThresholdLines, diffAutoScroll, revealDebounceMsOption, diffUpdateThrottleMsOption) {
|
|
496
500
|
this.options = options;
|
|
497
501
|
this.maxHeightValue = maxHeightValue;
|
|
498
502
|
this.maxHeightCSS = maxHeightCSS;
|
|
@@ -503,6 +507,40 @@ var DiffEditorManager = class {
|
|
|
503
507
|
this.diffAutoScroll = diffAutoScroll;
|
|
504
508
|
this.revealDebounceMsOption = revealDebounceMsOption;
|
|
505
509
|
}
|
|
510
|
+
scheduleFlushAppendBufferDiff() {
|
|
511
|
+
if (this.appendBufferDiffScheduled) return;
|
|
512
|
+
this.appendBufferDiffScheduled = true;
|
|
513
|
+
const schedule = () => {
|
|
514
|
+
this.rafScheduler.schedule("appendDiff", () => this.flushAppendBufferDiff());
|
|
515
|
+
};
|
|
516
|
+
const throttle = this.diffUpdateThrottleMs;
|
|
517
|
+
if (!throttle) {
|
|
518
|
+
schedule();
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const now = Date.now();
|
|
522
|
+
const since = now - this.lastAppendFlushTimeDiff;
|
|
523
|
+
if (since >= throttle) {
|
|
524
|
+
schedule();
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
if (this.appendFlushThrottleTimerDiff != null) return;
|
|
528
|
+
const wait = throttle - since;
|
|
529
|
+
this.appendFlushThrottleTimerDiff = setTimeout(() => {
|
|
530
|
+
this.appendFlushThrottleTimerDiff = null;
|
|
531
|
+
schedule();
|
|
532
|
+
}, wait);
|
|
533
|
+
}
|
|
534
|
+
flushOriginalAppendBufferSync() {
|
|
535
|
+
if (!this.originalModel) return;
|
|
536
|
+
if (this.appendBufferOriginalDiff.length === 0) return;
|
|
537
|
+
this.rafScheduler.cancel("appendDiff");
|
|
538
|
+
this.appendBufferDiffScheduled = false;
|
|
539
|
+
const text = this.appendBufferOriginalDiff.join("");
|
|
540
|
+
this.appendBufferOriginalDiff.length = 0;
|
|
541
|
+
if (!text) return;
|
|
542
|
+
this.appendToModel(this.originalModel, text);
|
|
543
|
+
}
|
|
506
544
|
computedHeight() {
|
|
507
545
|
var _originalEditor$getMo, _modifiedEditor$getMo, _originalEditor$getSc, _modifiedEditor$getSc;
|
|
508
546
|
if (!this.diffEditorView) return Math.min(1 * 18 + padding, this.maxHeightValue);
|
|
@@ -750,6 +788,7 @@ var DiffEditorManager = class {
|
|
|
750
788
|
});
|
|
751
789
|
this.lastKnownOriginalCode = originalCode;
|
|
752
790
|
this.lastKnownModifiedCode = modifiedCode;
|
|
791
|
+
this.diffUpdateThrottleMs = this.options.diffUpdateThrottleMs ?? 50;
|
|
753
792
|
this.shouldAutoScrollDiff = !!(this.autoScrollInitial && this.diffAutoScroll);
|
|
754
793
|
if (this.diffScrollWatcher) {
|
|
755
794
|
this.diffScrollWatcher.dispose();
|
|
@@ -866,16 +905,14 @@ var DiffEditorManager = class {
|
|
|
866
905
|
const prevM = this.lastKnownModifiedCode;
|
|
867
906
|
let didImmediate = false;
|
|
868
907
|
if (originalCode !== prevO && originalCode.startsWith(prevO)) {
|
|
869
|
-
this.
|
|
908
|
+
this.appendOriginal(originalCode.slice(prevO.length));
|
|
870
909
|
this.lastKnownOriginalCode = originalCode;
|
|
871
910
|
didImmediate = true;
|
|
872
911
|
}
|
|
873
912
|
if (modifiedCode !== prevM && modifiedCode.startsWith(prevM)) {
|
|
874
|
-
|
|
875
|
-
this.appendToModel(this.modifiedModel, modifiedCode.slice(prevM.length));
|
|
913
|
+
this.appendModified(modifiedCode.slice(prevM.length));
|
|
876
914
|
this.lastKnownModifiedCode = modifiedCode;
|
|
877
915
|
didImmediate = true;
|
|
878
|
-
this.maybeScrollDiffToBottom(this.modifiedModel.getLineCount(), prevLine);
|
|
879
916
|
}
|
|
880
917
|
if (originalCode !== this.lastKnownOriginalCode || modifiedCode !== this.lastKnownModifiedCode) {
|
|
881
918
|
this.pendingDiffUpdate = {
|
|
@@ -893,8 +930,11 @@ var DiffEditorManager = class {
|
|
|
893
930
|
}
|
|
894
931
|
const prev = this.lastKnownOriginalCode ?? this.originalModel.getValue();
|
|
895
932
|
if (prev === newCode) return;
|
|
896
|
-
if (newCode.startsWith(prev) && prev.length < newCode.length) this.
|
|
897
|
-
else
|
|
933
|
+
if (newCode.startsWith(prev) && prev.length < newCode.length) this.appendOriginal(newCode.slice(prev.length), codeLanguage);
|
|
934
|
+
else {
|
|
935
|
+
this.flushOriginalAppendBufferSync();
|
|
936
|
+
this.applyMinimalEditToModel(this.originalModel, prev, newCode);
|
|
937
|
+
}
|
|
898
938
|
this.lastKnownOriginalCode = newCode;
|
|
899
939
|
}
|
|
900
940
|
updateModified(newCode, codeLanguage) {
|
|
@@ -905,12 +945,12 @@ var DiffEditorManager = class {
|
|
|
905
945
|
}
|
|
906
946
|
const prev = this.lastKnownModifiedCode ?? this.modifiedModel.getValue();
|
|
907
947
|
if (prev === newCode) return;
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
this.
|
|
911
|
-
this.
|
|
912
|
-
|
|
913
|
-
this.applyMinimalEditToModel(this.modifiedModel,
|
|
948
|
+
if (newCode.startsWith(prev) && prev.length < newCode.length) this.appendModified(newCode.slice(prev.length), codeLanguage);
|
|
949
|
+
else {
|
|
950
|
+
this.flushModifiedAppendBufferSync();
|
|
951
|
+
const prevAfterFlush = this.modifiedModel.getValue();
|
|
952
|
+
const prevLine = this.modifiedModel.getLineCount();
|
|
953
|
+
this.applyMinimalEditToModel(this.modifiedModel, prevAfterFlush, newCode);
|
|
914
954
|
const newLine = this.modifiedModel.getLineCount();
|
|
915
955
|
if (newLine !== prevLine) {
|
|
916
956
|
const shouldImmediate = this.shouldPerformImmediateRevealDiff();
|
|
@@ -944,8 +984,8 @@ var DiffEditorManager = class {
|
|
|
944
984
|
const lang = processedLanguage(codeLanguage);
|
|
945
985
|
if (lang && this.originalModel.getLanguageId() !== lang) monaco_shim_exports.editor.setModelLanguage(this.originalModel, lang);
|
|
946
986
|
}
|
|
947
|
-
this.
|
|
948
|
-
this.
|
|
987
|
+
this.appendBufferOriginalDiff.push(appendText);
|
|
988
|
+
this.scheduleFlushAppendBufferDiff();
|
|
949
989
|
}
|
|
950
990
|
appendModified(appendText, codeLanguage) {
|
|
951
991
|
if (!this.diffEditorView || !this.modifiedModel || !appendText) return;
|
|
@@ -953,11 +993,8 @@ var DiffEditorManager = class {
|
|
|
953
993
|
const lang = processedLanguage(codeLanguage);
|
|
954
994
|
if (lang && this.modifiedModel.getLanguageId() !== lang) monaco_shim_exports.editor.setModelLanguage(this.modifiedModel, lang);
|
|
955
995
|
}
|
|
956
|
-
this.
|
|
957
|
-
|
|
958
|
-
this.appendBufferDiffScheduled = true;
|
|
959
|
-
this.rafScheduler.schedule("appendDiff", () => this.flushAppendBufferDiff());
|
|
960
|
-
}
|
|
996
|
+
this.appendBufferModifiedDiff.push(appendText);
|
|
997
|
+
this.scheduleFlushAppendBufferDiff();
|
|
961
998
|
}
|
|
962
999
|
setLanguage(language, languages$1) {
|
|
963
1000
|
if (!languages$1.includes(language)) {
|
|
@@ -981,7 +1018,12 @@ var DiffEditorManager = class {
|
|
|
981
1018
|
this.pendingDiffUpdate = null;
|
|
982
1019
|
this.rafScheduler.cancel("appendDiff");
|
|
983
1020
|
this.appendBufferDiffScheduled = false;
|
|
984
|
-
this.
|
|
1021
|
+
this.appendBufferOriginalDiff.length = 0;
|
|
1022
|
+
this.appendBufferModifiedDiff.length = 0;
|
|
1023
|
+
if (this.appendFlushThrottleTimerDiff != null) {
|
|
1024
|
+
clearTimeout(this.appendFlushThrottleTimerDiff);
|
|
1025
|
+
this.appendFlushThrottleTimerDiff = null;
|
|
1026
|
+
}
|
|
985
1027
|
this.rafScheduler.cancel("content-size-change-diff");
|
|
986
1028
|
this.rafScheduler.cancel("sync-last-known-modified");
|
|
987
1029
|
if (this.diffScrollWatcher) {
|
|
@@ -1028,6 +1070,14 @@ var DiffEditorManager = class {
|
|
|
1028
1070
|
safeClean() {
|
|
1029
1071
|
this.rafScheduler.cancel("diff");
|
|
1030
1072
|
this.pendingDiffUpdate = null;
|
|
1073
|
+
this.rafScheduler.cancel("appendDiff");
|
|
1074
|
+
this.appendBufferDiffScheduled = false;
|
|
1075
|
+
this.appendBufferOriginalDiff.length = 0;
|
|
1076
|
+
this.appendBufferModifiedDiff.length = 0;
|
|
1077
|
+
if (this.appendFlushThrottleTimerDiff != null) {
|
|
1078
|
+
clearTimeout(this.appendFlushThrottleTimerDiff);
|
|
1079
|
+
this.appendFlushThrottleTimerDiff = null;
|
|
1080
|
+
}
|
|
1031
1081
|
if (this.diffScrollWatcher) {
|
|
1032
1082
|
this.diffScrollWatcher.dispose();
|
|
1033
1083
|
this.diffScrollWatcher = null;
|
|
@@ -1079,6 +1129,8 @@ var DiffEditorManager = class {
|
|
|
1079
1129
|
}
|
|
1080
1130
|
const { original, modified, lang } = this.pendingDiffUpdate;
|
|
1081
1131
|
this.pendingDiffUpdate = null;
|
|
1132
|
+
this.flushOriginalAppendBufferSync();
|
|
1133
|
+
this.flushModifiedAppendBufferSync();
|
|
1082
1134
|
if (lang) {
|
|
1083
1135
|
const plang = processedLanguage(lang);
|
|
1084
1136
|
if (plang) {
|
|
@@ -1096,14 +1148,7 @@ var DiffEditorManager = class {
|
|
|
1096
1148
|
else this.applyMinimalEditToModel(o, prevO, original);
|
|
1097
1149
|
this.lastKnownOriginalCode = original;
|
|
1098
1150
|
}
|
|
1099
|
-
|
|
1100
|
-
const buffered = this.appendBufferDiff.length > 0 ? this.appendBufferDiff.join("") : "";
|
|
1101
|
-
if (this.appendBufferDiff.length > 0) try {
|
|
1102
|
-
prevM = m.getValue() + buffered;
|
|
1103
|
-
this.lastKnownModifiedCode = prevM;
|
|
1104
|
-
} catch {
|
|
1105
|
-
prevM = (this.lastKnownModifiedCode ?? "") + buffered;
|
|
1106
|
-
}
|
|
1151
|
+
const prevM = m.getValue();
|
|
1107
1152
|
const prevMLineCount = m.getLineCount();
|
|
1108
1153
|
if (prevM !== modified) {
|
|
1109
1154
|
if (modified.startsWith(prevM) && prevM.length < modified.length) this.appendToModel(m, modified.slice(prevM.length));
|
|
@@ -1123,17 +1168,33 @@ var DiffEditorManager = class {
|
|
|
1123
1168
|
}
|
|
1124
1169
|
}
|
|
1125
1170
|
}
|
|
1171
|
+
flushModifiedAppendBufferSync() {
|
|
1172
|
+
if (!this.modifiedModel) return;
|
|
1173
|
+
if (this.appendBufferModifiedDiff.length === 0) return;
|
|
1174
|
+
this.rafScheduler.cancel("appendDiff");
|
|
1175
|
+
this.appendBufferDiffScheduled = false;
|
|
1176
|
+
const text = this.appendBufferModifiedDiff.join("");
|
|
1177
|
+
this.appendBufferModifiedDiff.length = 0;
|
|
1178
|
+
if (!text) return;
|
|
1179
|
+
this.appendToModel(this.modifiedModel, text);
|
|
1180
|
+
}
|
|
1126
1181
|
async flushAppendBufferDiff() {
|
|
1127
1182
|
if (!this.diffEditorView) return;
|
|
1128
|
-
if (this.
|
|
1183
|
+
if (this.appendBufferOriginalDiff.length === 0 && this.appendBufferModifiedDiff.length === 0) return;
|
|
1184
|
+
this.lastAppendFlushTimeDiff = Date.now();
|
|
1129
1185
|
this.appendBufferDiffScheduled = false;
|
|
1186
|
+
if (this.originalModel && this.appendBufferOriginalDiff.length > 0) {
|
|
1187
|
+
const oText = this.appendBufferOriginalDiff.join("");
|
|
1188
|
+
this.appendBufferOriginalDiff.length = 0;
|
|
1189
|
+
if (oText) this.appendToModel(this.originalModel, oText);
|
|
1190
|
+
}
|
|
1130
1191
|
const me = this.diffEditorView.getModifiedEditor();
|
|
1131
1192
|
const model = me.getModel();
|
|
1132
1193
|
if (!model) {
|
|
1133
|
-
this.
|
|
1194
|
+
this.appendBufferModifiedDiff.length = 0;
|
|
1134
1195
|
return;
|
|
1135
1196
|
}
|
|
1136
|
-
let parts = this.
|
|
1197
|
+
let parts = this.appendBufferModifiedDiff.splice(0);
|
|
1137
1198
|
const prevLineInit = model.getLineCount();
|
|
1138
1199
|
const totalText = parts.join("");
|
|
1139
1200
|
const totalChars = totalText.length;
|
|
@@ -1208,7 +1269,7 @@ var DiffEditorManager = class {
|
|
|
1208
1269
|
return;
|
|
1209
1270
|
}
|
|
1210
1271
|
const text = totalText;
|
|
1211
|
-
this.
|
|
1272
|
+
this.appendBufferModifiedDiff.length = 0;
|
|
1212
1273
|
prevLine = model.getLineCount();
|
|
1213
1274
|
const lastColumn = model.getLineMaxColumn(prevLine);
|
|
1214
1275
|
const range = new monaco_shim_exports.Range(prevLine, lastColumn, prevLine, lastColumn);
|
|
@@ -1928,15 +1989,17 @@ async function preloadMonacoWorkers() {
|
|
|
1928
1989
|
javascript: workerUrlTs
|
|
1929
1990
|
};
|
|
1930
1991
|
try {
|
|
1931
|
-
await Promise.all(unique.map((u) => fetch(u, {
|
|
1932
|
-
method: "GET",
|
|
1933
|
-
cache: "force-cache"
|
|
1934
|
-
}).catch(() => void 0)));
|
|
1935
1992
|
self.MonacoEnvironment = { getWorker(_, label) {
|
|
1936
1993
|
const url = workerUrlByLabel[label] ?? workerUrlEditor;
|
|
1937
1994
|
return new Worker(url, { type: "module" });
|
|
1938
1995
|
} };
|
|
1939
1996
|
} catch {}
|
|
1997
|
+
try {
|
|
1998
|
+
await Promise.all(unique.map((u) => fetch(u, {
|
|
1999
|
+
method: "GET",
|
|
2000
|
+
cache: "force-cache"
|
|
2001
|
+
}).catch(() => void 0)));
|
|
2002
|
+
} catch {}
|
|
1940
2003
|
}
|
|
1941
2004
|
|
|
1942
2005
|
//#endregion
|
|
@@ -2416,7 +2479,7 @@ function useMonaco(monacoOptions = {}) {
|
|
|
2416
2479
|
try {
|
|
2417
2480
|
monaco_shim_exports.editor.setTheme(initialThemeName);
|
|
2418
2481
|
} catch {}
|
|
2419
|
-
diffMgr = new DiffEditorManager(monacoOptions, maxHeightValue, maxHeightCSS, autoScrollOnUpdate, autoScrollInitial, autoScrollThresholdPx, autoScrollThresholdLines, diffAutoScroll, monacoOptions.revealDebounceMs);
|
|
2482
|
+
diffMgr = new DiffEditorManager(monacoOptions, maxHeightValue, maxHeightCSS, autoScrollOnUpdate, autoScrollInitial, autoScrollThresholdPx, autoScrollThresholdLines, diffAutoScroll, monacoOptions.revealDebounceMs, monacoOptions.diffUpdateThrottleMs);
|
|
2420
2483
|
diffEditorView = await diffMgr.createDiffEditor(container, originalCode, modifiedCode, language, initialThemeName);
|
|
2421
2484
|
if (typeof monacoOptions.onThemeChange === "function") monacoOptions.onThemeChange(initialThemeName);
|
|
2422
2485
|
const models = diffMgr.getDiffModels();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stream-monaco",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.15",
|
|
5
5
|
"description": "A framework-agnostic library for integrating Monaco Editor with Shiki highlighting, optimized for streaming updates.",
|
|
6
6
|
"author": "Simon He",
|
|
7
7
|
"license": "MIT",
|
|
@@ -92,6 +92,7 @@
|
|
|
92
92
|
"start": "esno src/index.ts",
|
|
93
93
|
"bench": "node scripts/stream-benchmark.mjs",
|
|
94
94
|
"bench:playwright": "node scripts/playwright-bench.mjs",
|
|
95
|
+
"smoke:diff": "node scripts/playwright-diff-smoke.mjs",
|
|
95
96
|
"test": "vitest",
|
|
96
97
|
"typecheck": "tsc --noEmit"
|
|
97
98
|
}
|