stream-monaco 0.0.2 → 0.0.3

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/index.cjs CHANGED
@@ -29,6 +29,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
29
29
 
30
30
  //#endregion
31
31
  const monaco_editor = __toESM(require("monaco-editor"));
32
+ const node_process = __toESM(require("node:process"));
32
33
  const alien_signals = __toESM(require("alien-signals"));
33
34
  const __shikijs_monaco = __toESM(require("@shikijs/monaco"));
34
35
  const shiki = __toESM(require("shiki"));
@@ -227,34 +228,107 @@ __export(monaco_shim_exports, { default: () => monaco });
227
228
  __reExport(monaco_shim_exports, require("monaco-editor"));
228
229
  const monaco = monaco_editor;
229
230
 
231
+ //#endregion
232
+ //#region src/utils/logger.ts
233
+ let seq = 0;
234
+ const ENABLED = (() => {
235
+ try {
236
+ if (typeof window !== "undefined" && window.__STREAM_MONACO_DEBUG__ !== void 0) return Boolean(window.__STREAM_MONACO_DEBUG__);
237
+ try {
238
+ const proc = node_process.default;
239
+ if (proc && proc.env && proc.env.NODE_ENV !== "production") return true;
240
+ } catch {}
241
+ } catch {}
242
+ return false;
243
+ })();
244
+ function log(tag, ...args) {
245
+ if (!ENABLED) return;
246
+ try {
247
+ seq += 1;
248
+ const id = `#${seq}`;
249
+ const ts = typeof performance !== "undefined" && performance.now ? performance.now().toFixed(1) : Date.now();
250
+ console.warn(`${id} [${tag}] @${ts}ms`, ...args);
251
+ } catch (err) {
252
+ try {
253
+ console.warn("[logger] fallback", tag, ...args, err);
254
+ } catch {}
255
+ }
256
+ }
257
+ function error(tag, ...args) {
258
+ if (!ENABLED) return;
259
+ try {
260
+ console.error(`[${tag}]`, ...args);
261
+ } catch (err) {
262
+ try {
263
+ console.error("[logger] fallback error", tag, ...args, err);
264
+ } catch {}
265
+ }
266
+ }
267
+
230
268
  //#endregion
231
269
  //#region src/utils/height.ts
232
270
  function createHeightManager(container, computeNext) {
233
271
  let raf = null;
272
+ let debounceTimer = null;
234
273
  let lastApplied = -1;
235
274
  let suppressed = false;
275
+ const HYSTERESIS_PX = 12;
276
+ const DEBOUNCE_MS = 0;
236
277
  function apply() {
237
278
  const next = computeNext();
279
+ if (next == null) return;
280
+ log("heightManager", "computeNext ->", {
281
+ next,
282
+ lastApplied
283
+ });
284
+ if (!Number.isFinite(next) || next <= 0) {
285
+ log("heightManager", "invalid next height, ignoring", next);
286
+ return;
287
+ }
288
+ if (lastApplied !== -1 && Math.abs(next - lastApplied) <= HYSTERESIS_PX) return;
238
289
  if (next === lastApplied) return;
239
290
  suppressed = true;
240
291
  container.style.height = `${next}px`;
241
292
  lastApplied = next;
293
+ log("heightManager", "applied height ->", next);
242
294
  queueMicrotask(() => {
243
295
  suppressed = false;
244
296
  });
245
297
  }
298
+ function scheduleApply() {
299
+ if (debounceTimer != null) {
300
+ clearTimeout(debounceTimer);
301
+ debounceTimer = null;
302
+ }
303
+ if (DEBOUNCE_MS === 0) {
304
+ if (raf != null) return;
305
+ raf = requestAnimationFrame(() => {
306
+ raf = null;
307
+ apply();
308
+ });
309
+ return;
310
+ }
311
+ debounceTimer = setTimeout(() => {
312
+ debounceTimer = null;
313
+ if (raf != null) return;
314
+ raf = requestAnimationFrame(() => {
315
+ raf = null;
316
+ apply();
317
+ });
318
+ }, DEBOUNCE_MS);
319
+ }
246
320
  function update() {
247
- if (raf != null) return;
248
- raf = requestAnimationFrame(() => {
249
- raf = null;
250
- apply();
251
- });
321
+ scheduleApply();
252
322
  }
253
323
  function dispose() {
254
324
  if (raf != null) {
255
325
  cancelAnimationFrame(raf);
256
326
  raf = null;
257
327
  }
328
+ if (debounceTimer != null) {
329
+ clearTimeout(debounceTimer);
330
+ debounceTimer = null;
331
+ }
258
332
  }
259
333
  function isSuppressed() {
260
334
  return suppressed;
@@ -308,20 +382,58 @@ function createRafScheduler(timeSource) {
308
382
  //#region src/utils/scroll.ts
309
383
  function createScrollWatcherForEditor(ed, opts) {
310
384
  var _ed$getScrollTop, _ed$onDidScrollChange;
385
+ const DEBUG = (() => {
386
+ try {
387
+ if (typeof window !== "undefined" && window.__STREAM_MONACO_DEBUG__ !== void 0) return Boolean(window.__STREAM_MONACO_DEBUG__);
388
+ try {
389
+ const proc = node_process.default;
390
+ if (proc && proc.env && proc.env.NODE_ENV === "production") return false;
391
+ } catch {}
392
+ } catch {}
393
+ return true;
394
+ })();
311
395
  const initial = ((_ed$getScrollTop = ed.getScrollTop) === null || _ed$getScrollTop === void 0 ? void 0 : _ed$getScrollTop.call(ed)) ?? 0;
312
396
  opts.setLast(initial);
313
- const disp = ((_ed$onDidScrollChange = ed.onDidScrollChange) === null || _ed$onDidScrollChange === void 0 ? void 0 : _ed$onDidScrollChange.call(ed, (e) => {
397
+ if (DEBUG) log("scrollWatcher", "initial scrollTop=", initial);
398
+ let suppressedExternally = false;
399
+ const THRESHOLD_PX = 6;
400
+ const listener = (e) => {
314
401
  var _ed$getScrollTop2;
402
+ if (suppressedExternally) {
403
+ if (DEBUG) log("scrollWatcher", "suppressedExternally, ignoring event");
404
+ return;
405
+ }
315
406
  const currentTop = e && typeof e.scrollTop === "number" ? e.scrollTop : ((_ed$getScrollTop2 = ed.getScrollTop) === null || _ed$getScrollTop2 === void 0 ? void 0 : _ed$getScrollTop2.call(ed)) ?? 0;
316
407
  const delta = currentTop - opts.getLast();
317
408
  opts.setLast(currentTop);
409
+ if (Math.abs(delta) < THRESHOLD_PX) {
410
+ if (DEBUG) log("scrollWatcher", "small delta ignored", delta);
411
+ return;
412
+ }
413
+ if (DEBUG) log("scrollWatcher", "delta=", delta, "currentTop=", currentTop);
318
414
  if (delta < 0) {
415
+ if (DEBUG) log("scrollWatcher", "pause detected delta=", delta);
319
416
  opts.onPause();
320
417
  return;
321
418
  }
419
+ if (DEBUG) log("scrollWatcher", "maybe resume delta=", delta);
322
420
  opts.onMaybeResume();
323
- })) ?? null;
324
- return disp;
421
+ };
422
+ const disp = ((_ed$onDidScrollChange = ed.onDidScrollChange) === null || _ed$onDidScrollChange === void 0 ? void 0 : _ed$onDidScrollChange.call(ed, listener)) ?? null;
423
+ const api = {
424
+ dispose() {
425
+ try {
426
+ if (disp && typeof disp.dispose === "function") disp.dispose();
427
+ else if (typeof disp === "function") disp();
428
+ } catch {}
429
+ if (DEBUG) log("scrollWatcher", "dispose");
430
+ },
431
+ setSuppressed(v) {
432
+ suppressedExternally = !!v;
433
+ if (DEBUG) log("scrollWatcher", "setSuppressed =>", suppressedExternally);
434
+ }
435
+ };
436
+ return api;
325
437
  }
326
438
 
327
439
  //#endregion
@@ -875,12 +987,14 @@ var EditorManager = class {
875
987
  _hasScrollBar = false;
876
988
  shouldAutoScroll = true;
877
989
  scrollWatcher = null;
990
+ scrollWatcherSuppressionTimer = null;
878
991
  lastScrollTop = 0;
879
992
  cachedScrollHeight = null;
880
993
  cachedLineHeight = null;
881
994
  cachedComputedHeight = null;
882
995
  cachedLineCount = null;
883
996
  lastKnownCodeDirty = false;
997
+ debug = false;
884
998
  measureViewport() {
885
999
  var _this$editorView$getL, _this$editorView, _this$editorView$getS, _this$editorView2, _this$editorView$getS2, _this$editorView3;
886
1000
  if (!this.editorView) return null;
@@ -908,8 +1022,10 @@ var EditorManager = class {
908
1022
  revealDebounceId = null;
909
1023
  revealDebounceMs = defaultRevealDebounceMs;
910
1024
  revealIdleTimerId = null;
1025
+ revealTicket = 0;
911
1026
  revealStrategyOption;
912
1027
  revealBatchOnIdleMsOption;
1028
+ scrollWatcherSuppressionMs = 500;
913
1029
  constructor(options, maxHeightValue, maxHeightCSS, autoScrollOnUpdate, autoScrollInitial, autoScrollThresholdPx, autoScrollThresholdLines, revealDebounceMsOption) {
914
1030
  this.options = options;
915
1031
  this.maxHeightValue = maxHeightValue;
@@ -920,6 +1036,21 @@ var EditorManager = class {
920
1036
  this.autoScrollThresholdLines = autoScrollThresholdLines;
921
1037
  this.revealDebounceMsOption = revealDebounceMsOption;
922
1038
  }
1039
+ initDebugFlag() {
1040
+ if (typeof window !== "undefined" && window.__STREAM_MONACO_DEBUG__ !== void 0) {
1041
+ this.debug = Boolean(window.__STREAM_MONACO_DEBUG__);
1042
+ return;
1043
+ }
1044
+ if (this.options && this.options.debug !== void 0) {
1045
+ this.debug = Boolean(this.options.debug);
1046
+ return;
1047
+ }
1048
+ this.debug = false;
1049
+ }
1050
+ dlog(...args) {
1051
+ if (!this.debug) return;
1052
+ log("EditorManager", ...args);
1053
+ }
923
1054
  hasVerticalScrollbar() {
924
1055
  if (!this.editorView) return false;
925
1056
  if (this._hasScrollBar) return true;
@@ -941,19 +1072,40 @@ var EditorManager = class {
941
1072
  const lineCount = this.cachedLineCount ?? ((_editorView$getModel = editorView.getModel()) === null || _editorView$getModel === void 0 ? void 0 : _editorView$getModel.getLineCount()) ?? 1;
942
1073
  const lineHeight = editorView.getOption(monaco_shim_exports.editor.EditorOption.lineHeight);
943
1074
  const height = Math.min(lineCount * lineHeight + padding, this.maxHeightValue);
1075
+ try {
1076
+ log("EditorManager.computedHeight", {
1077
+ lineCount,
1078
+ lineHeight,
1079
+ computed: height,
1080
+ maxHeightValue: this.maxHeightValue
1081
+ });
1082
+ } catch {}
944
1083
  return height;
945
1084
  }
946
1085
  maybeScrollToBottom(targetLine) {
947
1086
  this.rafScheduler.schedule("maybe-scroll", () => {
948
- if (!(this.autoScrollOnUpdate && this.shouldAutoScroll && this.hasVerticalScrollbar())) return;
1087
+ const hasVS = this.hasVerticalScrollbar();
1088
+ this.dlog("maybeScrollToBottom called", {
1089
+ autoScrollOnUpdate: this.autoScrollOnUpdate,
1090
+ shouldAutoScroll: this.shouldAutoScroll,
1091
+ hasVerticalScrollbar: hasVS,
1092
+ targetLine
1093
+ });
1094
+ if (!(this.autoScrollOnUpdate && this.shouldAutoScroll && this.hasVerticalScrollbar())) {
1095
+ this.dlog("maybeScrollToBottom skipped (auto-scroll conditions not met)");
1096
+ return;
1097
+ }
949
1098
  const model = this.editorView.getModel();
950
1099
  const line = targetLine ?? (model === null || model === void 0 ? void 0 : model.getLineCount()) ?? 1;
951
1100
  const batchMs = this.revealBatchOnIdleMsOption ?? this.options.revealBatchOnIdleMs ?? defaultRevealBatchOnIdleMs;
952
1101
  if (typeof batchMs === "number" && batchMs > 0) {
953
1102
  if (this.revealIdleTimerId != null) clearTimeout(this.revealIdleTimerId);
1103
+ const ticket = ++this.revealTicket;
1104
+ this.dlog("scheduled idle reveal ticket=", ticket, "line=", line, "batchMs=", batchMs);
954
1105
  this.revealIdleTimerId = setTimeout(() => {
955
1106
  this.revealIdleTimerId = null;
956
- this.performReveal(line);
1107
+ this.dlog("idle reveal timer firing, ticket=", ticket, "line=", line);
1108
+ this.performReveal(line, ticket);
957
1109
  }, batchMs);
958
1110
  return;
959
1111
  }
@@ -964,14 +1116,23 @@ var EditorManager = class {
964
1116
  const ms = typeof this.revealDebounceMs === "number" && this.revealDebounceMs > 0 ? this.revealDebounceMs : typeof this.revealDebounceMsOption === "number" && this.revealDebounceMsOption > 0 ? this.revealDebounceMsOption : this.revealDebounceMs;
965
1117
  this.revealDebounceId = setTimeout(() => {
966
1118
  this.revealDebounceId = null;
967
- this.performReveal(line);
1119
+ const ticket = ++this.revealTicket;
1120
+ this.dlog("scheduled debounce reveal ticket=", ticket, "line=", line, "ms=", ms);
1121
+ this.performReveal(line, ticket);
968
1122
  }, ms);
969
1123
  });
970
1124
  }
971
- performReveal(line) {
1125
+ performReveal(line, ticket) {
972
1126
  this.rafScheduler.schedule("reveal", () => {
973
1127
  var _editor;
1128
+ if (ticket !== this.revealTicket) {
1129
+ this.dlog("performReveal skipped, stale ticket", ticket, "current", this.revealTicket);
1130
+ return;
1131
+ }
1132
+ this.dlog("performReveal executing, ticket=", ticket, "line=", line);
1133
+ this.lastPerformedRevealTicket = ticket;
974
1134
  const strategy = this.revealStrategyOption ?? this.options.revealStrategy ?? "centerIfOutside";
1135
+ this.dlog("performReveal strategy=", strategy);
975
1136
  const ScrollType = monaco_shim_exports.ScrollType || ((_editor = monaco_shim_exports.editor) === null || _editor === void 0 ? void 0 : _editor.ScrollType);
976
1137
  const smooth = ScrollType && typeof ScrollType.Smooth !== "undefined" ? ScrollType.Smooth : void 0;
977
1138
  try {
@@ -988,11 +1149,60 @@ var EditorManager = class {
988
1149
  }
989
1150
  });
990
1151
  }
1152
+ performImmediateReveal(line, ticket) {
1153
+ this.dlog("performImmediateReveal line=", line, "ticket=", ticket);
1154
+ try {
1155
+ var _editor2;
1156
+ if (!this.editorView) return;
1157
+ if (ticket !== this.revealTicket) {
1158
+ this.dlog("performImmediateReveal skipped, stale ticket", ticket, "current", this.revealTicket);
1159
+ return;
1160
+ }
1161
+ this.lastPerformedRevealTicket = ticket;
1162
+ const ScrollType = monaco_shim_exports.ScrollType || ((_editor2 = monaco_shim_exports.editor) === null || _editor2 === void 0 ? void 0 : _editor2.ScrollType);
1163
+ const immediate = ScrollType && typeof ScrollType.Immediate !== "undefined" ? ScrollType.Immediate : void 0;
1164
+ if (typeof immediate !== "undefined") this.editorView.revealLine(line, immediate);
1165
+ else this.editorView.revealLine(line);
1166
+ } catch {}
1167
+ try {
1168
+ this.measureViewport();
1169
+ } catch {}
1170
+ }
1171
+ forceReveal(line) {
1172
+ try {
1173
+ var _editor3;
1174
+ if (!this.editorView) return;
1175
+ const ScrollType = monaco_shim_exports.ScrollType || ((_editor3 = monaco_shim_exports.editor) === null || _editor3 === void 0 ? void 0 : _editor3.ScrollType);
1176
+ const immediate = ScrollType && typeof ScrollType.Immediate !== "undefined" ? ScrollType.Immediate : void 0;
1177
+ if (typeof immediate !== "undefined") this.editorView.revealLine(line, immediate);
1178
+ else this.editorView.revealLine(line);
1179
+ } catch {}
1180
+ try {
1181
+ this.measureViewport();
1182
+ } catch {}
1183
+ try {
1184
+ var _this$editorView4, _this$editorView4$get;
1185
+ this.shouldAutoScroll = true;
1186
+ this.lastScrollTop = ((_this$editorView4 = this.editorView) === null || _this$editorView4 === void 0 || (_this$editorView4$get = _this$editorView4.getScrollTop) === null || _this$editorView4$get === void 0 ? void 0 : _this$editorView4$get.call(_this$editorView4)) ?? this.lastScrollTop;
1187
+ } catch {}
1188
+ }
1189
+ isOverflowAuto() {
1190
+ try {
1191
+ return !!this.lastContainer && this.lastContainer.style.overflow === "auto";
1192
+ } catch {
1193
+ return false;
1194
+ }
1195
+ }
1196
+ shouldPerformImmediateReveal() {
1197
+ return this.autoScrollOnUpdate && this.shouldAutoScroll && this.hasVerticalScrollbar() && this.isOverflowAuto();
1198
+ }
991
1199
  async createEditor(container, code, language, currentTheme) {
992
- var _this$editorView$getS3, _this$editorView4, _this$editorView$getO, _this$editorView5, _this$editorView$getM, _this$editorView$onDi, _this$editorView6;
1200
+ var _this$editorView$getS3, _this$editorView5, _this$editorView$getO, _this$editorView6, _this$editorView$getM, _this$editorView$onDi, _this$editorView7;
993
1201
  this.cleanup();
994
1202
  this.lastContainer = container;
995
- container.style.overflow = "auto";
1203
+ this.initDebugFlag();
1204
+ this.dlog("createEditor container, maxHeight", this.maxHeightValue);
1205
+ container.style.overflow = "hidden";
996
1206
  container.style.maxHeight = this.maxHeightCSS;
997
1207
  this.editorView = monaco_shim_exports.editor.create(container, {
998
1208
  value: code,
@@ -1023,22 +1233,51 @@ var EditorManager = class {
1023
1233
  }
1024
1234
  if (this.revealIdleTimerId != null) clearTimeout(this.revealIdleTimerId);
1025
1235
  this.revealIdleTimerId = null;
1026
- this.editorHeightManager = createHeightManager(container, () => this.computedHeight(this.editorView));
1236
+ const MIN_VISIBLE_HEIGHT = Math.min(120, this.maxHeightValue);
1237
+ container.style.minHeight = `${MIN_VISIBLE_HEIGHT}px`;
1238
+ this.editorHeightManager = createHeightManager(container, () => {
1239
+ const computed$1 = this.computedHeight(this.editorView);
1240
+ const clamped = Math.min(computed$1, this.maxHeightValue);
1241
+ return Math.max(clamped, MIN_VISIBLE_HEIGHT);
1242
+ });
1027
1243
  this.editorHeightManager.update();
1028
- this.cachedScrollHeight = ((_this$editorView$getS3 = (_this$editorView4 = this.editorView).getScrollHeight) === null || _this$editorView$getS3 === void 0 ? void 0 : _this$editorView$getS3.call(_this$editorView4)) ?? null;
1029
- this.cachedLineHeight = ((_this$editorView$getO = (_this$editorView5 = this.editorView).getOption) === null || _this$editorView$getO === void 0 ? void 0 : _this$editorView$getO.call(_this$editorView5, monaco_shim_exports.editor.EditorOption.lineHeight)) ?? null;
1244
+ const initialComputed = this.computedHeight(this.editorView);
1245
+ if (initialComputed >= this.maxHeightValue - 1) {
1246
+ container.style.height = `${this.maxHeightValue}px`;
1247
+ container.style.overflow = "auto";
1248
+ this.dlog("applied immediate maxHeight on createEditor", this.maxHeightValue);
1249
+ }
1250
+ this.cachedScrollHeight = ((_this$editorView$getS3 = (_this$editorView5 = this.editorView).getScrollHeight) === null || _this$editorView$getS3 === void 0 ? void 0 : _this$editorView$getS3.call(_this$editorView5)) ?? null;
1251
+ this.cachedLineHeight = ((_this$editorView$getO = (_this$editorView6 = this.editorView).getOption) === null || _this$editorView$getO === void 0 ? void 0 : _this$editorView$getO.call(_this$editorView6, monaco_shim_exports.editor.EditorOption.lineHeight)) ?? null;
1030
1252
  this.cachedComputedHeight = this.computedHeight(this.editorView);
1031
1253
  this.cachedLineCount = ((_this$editorView$getM = this.editorView.getModel()) === null || _this$editorView$getM === void 0 ? void 0 : _this$editorView$getM.getLineCount()) ?? null;
1032
- (_this$editorView$onDi = (_this$editorView6 = this.editorView).onDidContentSizeChange) === null || _this$editorView$onDi === void 0 || _this$editorView$onDi.call(_this$editorView6, () => {
1254
+ (_this$editorView$onDi = (_this$editorView7 = this.editorView).onDidContentSizeChange) === null || _this$editorView$onDi === void 0 || _this$editorView$onDi.call(_this$editorView7, () => {
1033
1255
  this._hasScrollBar = false;
1034
1256
  this.rafScheduler.schedule("content-size-change", () => {
1035
1257
  try {
1036
- var _this$editorView7, _this$editorHeightMan, _this$editorHeightMan2;
1037
- this.measureViewport();
1038
- this.cachedLineCount = ((_this$editorView7 = this.editorView) === null || _this$editorView7 === void 0 || (_this$editorView7 = _this$editorView7.getModel()) === null || _this$editorView7 === void 0 ? void 0 : _this$editorView7.getLineCount()) ?? this.cachedLineCount;
1039
- if ((_this$editorHeightMan = this.editorHeightManager) === null || _this$editorHeightMan === void 0 ? void 0 : _this$editorHeightMan.isSuppressed()) return;
1258
+ var _this$editorView8, _this$editorHeightMan, _this$editorHeightMan2;
1259
+ this.dlog("content-size-change frame");
1260
+ const m = this.measureViewport();
1261
+ this.dlog("content-size-change measure", m);
1262
+ this.cachedLineCount = ((_this$editorView8 = this.editorView) === null || _this$editorView8 === void 0 || (_this$editorView8 = _this$editorView8.getModel()) === null || _this$editorView8 === void 0 ? void 0 : _this$editorView8.getLineCount()) ?? this.cachedLineCount;
1263
+ if ((_this$editorHeightMan = this.editorHeightManager) === null || _this$editorHeightMan === void 0 ? void 0 : _this$editorHeightMan.isSuppressed()) {
1264
+ this.dlog("content-size-change skipped height update (suppressed)");
1265
+ return;
1266
+ }
1267
+ this.dlog("content-size-change calling heightManager.update");
1040
1268
  (_this$editorHeightMan2 = this.editorHeightManager) === null || _this$editorHeightMan2 === void 0 || _this$editorHeightMan2.update();
1041
- } catch {}
1269
+ const computed$1 = this.computedHeight(this.editorView);
1270
+ if (this.lastContainer) {
1271
+ const prevOverflow = this.lastContainer.style.overflow;
1272
+ const newOverflow = computed$1 >= this.maxHeightValue - 1 ? "auto" : "hidden";
1273
+ if (prevOverflow !== newOverflow) {
1274
+ this.lastContainer.style.overflow = newOverflow;
1275
+ if (newOverflow === "auto" && this.shouldAutoScroll) this.maybeScrollToBottom();
1276
+ }
1277
+ }
1278
+ } catch (err) {
1279
+ error("EditorManager", "content-size-change error", err);
1280
+ }
1042
1281
  });
1043
1282
  });
1044
1283
  this.editorView.onDidChangeModelContent(() => {
@@ -1079,6 +1318,65 @@ var EditorManager = class {
1079
1318
  this.lastKnownCodeDirty = false;
1080
1319
  }
1081
1320
  }
1321
+ suppressScrollWatcher(ms) {
1322
+ try {
1323
+ if (!this.scrollWatcher || typeof this.scrollWatcher.setSuppressed !== "function") return;
1324
+ this.dlog("suppressScrollWatcher", ms);
1325
+ if (this.scrollWatcherSuppressionTimer != null) {
1326
+ clearTimeout(this.scrollWatcherSuppressionTimer);
1327
+ this.scrollWatcherSuppressionTimer = null;
1328
+ }
1329
+ this.scrollWatcher.setSuppressed(true);
1330
+ this.scrollWatcherSuppressionTimer = setTimeout(() => {
1331
+ try {
1332
+ if (this.scrollWatcher && typeof this.scrollWatcher.setSuppressed === "function") {
1333
+ this.scrollWatcher.setSuppressed(false);
1334
+ this.dlog("suppressScrollWatcher cleared");
1335
+ }
1336
+ } catch {}
1337
+ this.scrollWatcherSuppressionTimer = null;
1338
+ }, ms);
1339
+ } catch {}
1340
+ }
1341
+ scheduleImmediateRevealAfterLayout(line) {
1342
+ const ticket = ++this.revealTicket;
1343
+ this.dlog("scheduleImmediateRevealAfterLayout ticket=", ticket, "line=", line);
1344
+ this.rafScheduler.schedule("immediate-reveal", async () => {
1345
+ try {
1346
+ const target = this.editorView && this.editorHeightManager ? Math.min(this.computedHeight(this.editorView), this.maxHeightValue) : -1;
1347
+ if (target !== -1 && this.editorHeightManager) await this.waitForHeightApplied(target, 500);
1348
+ else await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(() => r())));
1349
+ this.dlog("running delayed immediate reveal", "ticket=", ticket, "line=", line);
1350
+ this.performImmediateReveal(line, ticket);
1351
+ } catch (err) {
1352
+ error("EditorManager", "scheduleImmediateRevealAfterLayout error", err);
1353
+ }
1354
+ });
1355
+ }
1356
+ waitForHeightApplied(target, timeoutMs = 500) {
1357
+ return new Promise((resolve) => {
1358
+ const start = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
1359
+ const check = () => {
1360
+ try {
1361
+ var _this$editorHeightMan3, _this$editorHeightMan4;
1362
+ const last = ((_this$editorHeightMan3 = this.editorHeightManager) === null || _this$editorHeightMan3 === void 0 || (_this$editorHeightMan4 = _this$editorHeightMan3.getLastApplied) === null || _this$editorHeightMan4 === void 0 ? void 0 : _this$editorHeightMan4.call(_this$editorHeightMan3)) ?? -1;
1363
+ if (last !== -1 && Math.abs(last - target) <= 12) {
1364
+ this.dlog("waitForHeightApplied satisfied", last, "target=", target);
1365
+ resolve();
1366
+ return;
1367
+ }
1368
+ const now = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
1369
+ if (now - start > timeoutMs) {
1370
+ log("EditorManager", "waitForHeightApplied timeout", last, "target=", target);
1371
+ resolve();
1372
+ return;
1373
+ }
1374
+ } catch {}
1375
+ requestAnimationFrame(check);
1376
+ };
1377
+ check();
1378
+ });
1379
+ }
1082
1380
  updateCode(newCode, codeLanguage) {
1083
1381
  this.pendingUpdate = {
1084
1382
  code: newCode,
@@ -1101,7 +1399,18 @@ var EditorManager = class {
1101
1399
  this.lastKnownCode = newCode;
1102
1400
  const newLineCount$1 = model.getLineCount();
1103
1401
  this.cachedLineCount = newLineCount$1;
1104
- if (newLineCount$1 !== prevLineCount$1) this.maybeScrollToBottom(newLineCount$1);
1402
+ if (newLineCount$1 !== prevLineCount$1) {
1403
+ const shouldImmediate = this.shouldPerformImmediateReveal();
1404
+ if (shouldImmediate) this.suppressScrollWatcher(this.scrollWatcherSuppressionMs);
1405
+ try {
1406
+ const computed$1 = this.computedHeight(this.editorView);
1407
+ if (computed$1 >= this.maxHeightValue - 1 && this.lastContainer) this.lastContainer.style.height = `${this.maxHeightValue}px`;
1408
+ } catch {}
1409
+ if (shouldImmediate) try {
1410
+ this.forceReveal(newLineCount$1);
1411
+ } catch {}
1412
+ else this.maybeScrollToBottom(newLineCount$1);
1413
+ }
1105
1414
  return;
1106
1415
  }
1107
1416
  const prevCode = this.appendBuffer.length > 0 ? this.editorView.getValue() : this.lastKnownCode ?? this.editorView.getValue();
@@ -1117,7 +1426,12 @@ var EditorManager = class {
1117
1426
  this.lastKnownCode = newCode;
1118
1427
  const newLineCount = model.getLineCount();
1119
1428
  this.cachedLineCount = newLineCount;
1120
- if (newLineCount !== prevLineCount) this.maybeScrollToBottom(newLineCount);
1429
+ if (newLineCount !== prevLineCount) {
1430
+ const shouldImmediate = this.shouldPerformImmediateReveal();
1431
+ if (shouldImmediate) this.suppressScrollWatcher(this.scrollWatcherSuppressionMs);
1432
+ if (shouldImmediate) this.scheduleImmediateRevealAfterLayout(newLineCount);
1433
+ else this.maybeScrollToBottom(newLineCount);
1434
+ }
1121
1435
  }
1122
1436
  appendCode(appendText, codeLanguage) {
1123
1437
  if (!this.editorView) return;
@@ -1195,7 +1509,16 @@ var EditorManager = class {
1195
1509
  const newLineCount = model.getLineCount();
1196
1510
  if (lastLine !== newLineCount) {
1197
1511
  this.cachedLineCount = newLineCount;
1198
- this.maybeScrollToBottom(newLineCount);
1512
+ const shouldImmediate = this.shouldPerformImmediateReveal();
1513
+ if (shouldImmediate) this.suppressScrollWatcher(this.scrollWatcherSuppressionMs);
1514
+ try {
1515
+ const computed$1 = this.computedHeight(this.editorView);
1516
+ if (computed$1 >= this.maxHeightValue - 1 && this.lastContainer) this.lastContainer.style.height = `${this.maxHeightValue}px`;
1517
+ } catch {}
1518
+ if (shouldImmediate) try {
1519
+ this.forceReveal(newLineCount);
1520
+ } catch {}
1521
+ else this.maybeScrollToBottom(newLineCount);
1199
1522
  }
1200
1523
  }
1201
1524
  setLanguage(language, languages$1) {
@@ -1213,16 +1536,33 @@ var EditorManager = class {
1213
1536
  this.rafScheduler.cancel("update");
1214
1537
  this.rafScheduler.cancel("sync-last-known");
1215
1538
  this.rafScheduler.cancel("content-size-change");
1539
+ this.rafScheduler.cancel("maybe-scroll");
1540
+ this.rafScheduler.cancel("reveal");
1541
+ this.rafScheduler.cancel("immediate-reveal");
1542
+ this.rafScheduler.cancel("maybe-resume");
1216
1543
  this.pendingUpdate = null;
1217
1544
  this.rafScheduler.cancel("append");
1218
1545
  this.appendBufferScheduled = false;
1219
1546
  this.appendBuffer.length = 0;
1547
+ if (this.revealDebounceId != null) {
1548
+ clearTimeout(this.revealDebounceId);
1549
+ this.revealDebounceId = null;
1550
+ }
1551
+ if (this.revealIdleTimerId != null) {
1552
+ clearTimeout(this.revealIdleTimerId);
1553
+ this.revealIdleTimerId = null;
1554
+ }
1555
+ if (this.scrollWatcherSuppressionTimer != null) {
1556
+ clearTimeout(this.scrollWatcherSuppressionTimer);
1557
+ this.scrollWatcherSuppressionTimer = null;
1558
+ }
1220
1559
  if (this.editorView) {
1221
1560
  this.editorView.dispose();
1222
1561
  this.editorView = null;
1223
1562
  }
1224
1563
  this.lastKnownCode = null;
1225
1564
  if (this.lastContainer) {
1565
+ this.lastContainer.style.minHeight = "";
1226
1566
  this.lastContainer.innerHTML = "";
1227
1567
  this.lastContainer = null;
1228
1568
  }
@@ -1240,13 +1580,27 @@ var EditorManager = class {
1240
1580
  this.pendingUpdate = null;
1241
1581
  this.rafScheduler.cancel("sync-last-known");
1242
1582
  if (this.scrollWatcher) {
1243
- this.scrollWatcher.dispose();
1583
+ try {
1584
+ this.scrollWatcher.dispose();
1585
+ } catch {}
1244
1586
  this.scrollWatcher = null;
1245
1587
  }
1246
1588
  if (this.revealDebounceId != null) {
1247
1589
  clearTimeout(this.revealDebounceId);
1248
1590
  this.revealDebounceId = null;
1249
1591
  }
1592
+ if (this.revealIdleTimerId != null) {
1593
+ clearTimeout(this.revealIdleTimerId);
1594
+ this.revealIdleTimerId = null;
1595
+ }
1596
+ if (this.scrollWatcherSuppressionTimer != null) {
1597
+ clearTimeout(this.scrollWatcherSuppressionTimer);
1598
+ this.scrollWatcherSuppressionTimer = null;
1599
+ }
1600
+ this.rafScheduler.cancel("maybe-scroll");
1601
+ this.rafScheduler.cancel("reveal");
1602
+ this.rafScheduler.cancel("immediate-reveal");
1603
+ this.rafScheduler.cancel("maybe-resume");
1250
1604
  this._hasScrollBar = false;
1251
1605
  this.shouldAutoScroll = !!this.autoScrollInitial;
1252
1606
  this.lastScrollTop = 0;
@@ -1553,6 +1907,7 @@ let RevealStrategy = /* @__PURE__ */ function(RevealStrategy$1) {
1553
1907
  * getEditorView: () => monaco.editor.IStandaloneCodeEditor | null,
1554
1908
  * getDiffEditorView: () => monaco.editor.IStandaloneDiffEditor | null,
1555
1909
  * getDiffModels: () => { original: monaco.editor.ITextModel | null, modified: monaco.editor.ITextModel | null },
1910
+ * getCode: () => string | { original: string, modified: string } | null,
1556
1911
  * }} 返回对象包含以下方法和属性:
1557
1912
  *
1558
1913
  * @property {Function} createEditor - 创建并挂载 Monaco 编辑器到指定容器
@@ -1572,6 +1927,7 @@ let RevealStrategy = /* @__PURE__ */ function(RevealStrategy$1) {
1572
1927
  * @property {Function} getEditorView - 获取当前编辑器实例
1573
1928
  * @property {Function} getDiffEditorView - 获取当前 Diff 编辑器实例
1574
1929
  * @property {Function} getDiffModels - 获取 Diff 的 original/modified 两个模型
1930
+ * @property {Function} getCode - 获取当前编辑器或 Diff 编辑器中的代码内容
1575
1931
  *
1576
1932
  * @throws {Error} 当主题数组不是数组或长度小于2时抛出错误
1577
1933
  *
@@ -2078,7 +2434,26 @@ function useMonaco(monacoOptions = {}) {
2078
2434
  return monaco_shim_exports;
2079
2435
  },
2080
2436
  setUpdateThrottleMs,
2081
- getUpdateThrottleMs
2437
+ getUpdateThrottleMs,
2438
+ getCode() {
2439
+ if (editorView) try {
2440
+ var _editorView$getModel;
2441
+ return ((_editorView$getModel = editorView.getModel()) === null || _editorView$getModel === void 0 ? void 0 : _editorView$getModel.getValue()) ?? null;
2442
+ } catch {
2443
+ return null;
2444
+ }
2445
+ if (diffEditorView || originalModel && modifiedModel) try {
2446
+ const original = (originalModel === null || originalModel === void 0 ? void 0 : originalModel.getValue()) ?? "";
2447
+ const modified = (modifiedModel === null || modifiedModel === void 0 ? void 0 : modifiedModel.getValue()) ?? "";
2448
+ return {
2449
+ original,
2450
+ modified
2451
+ };
2452
+ } catch {
2453
+ return null;
2454
+ }
2455
+ return null;
2456
+ }
2082
2457
  };
2083
2458
  }
2084
2459
 
package/dist/index.d.cts CHANGED
@@ -210,6 +210,7 @@ declare function registerMonacoThemes(themes: (ThemeInput | string | SpecialThem
210
210
  * getEditorView: () => monaco.editor.IStandaloneCodeEditor | null,
211
211
  * getDiffEditorView: () => monaco.editor.IStandaloneDiffEditor | null,
212
212
  * getDiffModels: () => { original: monaco.editor.ITextModel | null, modified: monaco.editor.ITextModel | null },
213
+ * getCode: () => string | { original: string, modified: string } | null,
213
214
  * }} 返回对象包含以下方法和属性:
214
215
  *
215
216
  * @property {Function} createEditor - 创建并挂载 Monaco 编辑器到指定容器
@@ -229,6 +230,7 @@ declare function registerMonacoThemes(themes: (ThemeInput | string | SpecialThem
229
230
  * @property {Function} getEditorView - 获取当前编辑器实例
230
231
  * @property {Function} getDiffEditorView - 获取当前 Diff 编辑器实例
231
232
  * @property {Function} getDiffModels - 获取 Diff 的 original/modified 两个模型
233
+ * @property {Function} getCode - 获取当前编辑器或 Diff 编辑器中的代码内容
232
234
  *
233
235
  * @throws {Error} 当主题数组不是数组或长度小于2时抛出错误
234
236
  *
@@ -277,6 +279,10 @@ declare function useMonaco(monacoOptions?: MonacoOptions): {
277
279
  getMonacoInstance(): typeof monaco_shim_d_exports;
278
280
  setUpdateThrottleMs: (ms: number) => void;
279
281
  getUpdateThrottleMs: () => number;
282
+ getCode(): string | {
283
+ original: string;
284
+ modified: string;
285
+ } | null;
280
286
  };
281
287
  //#endregion
282
288
  export { MonacoDiffEditorInstance, MonacoEditorInstance, MonacoLanguage, MonacoOptions, MonacoTheme, RevealStrategy, ShikiHighlighter, clearHighlighterCache, defaultRevealDebounceMs, detectLanguage, getOrCreateHighlighter, isDark, preloadMonacoWorkers, registerMonacoThemes, useMonaco };