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.d.ts CHANGED
@@ -209,6 +209,7 @@ declare function registerMonacoThemes(themes: (ThemeInput | string | SpecialThem
209
209
  * getEditorView: () => monaco.editor.IStandaloneCodeEditor | null,
210
210
  * getDiffEditorView: () => monaco.editor.IStandaloneDiffEditor | null,
211
211
  * getDiffModels: () => { original: monaco.editor.ITextModel | null, modified: monaco.editor.ITextModel | null },
212
+ * getCode: () => string | { original: string, modified: string } | null,
212
213
  * }} 返回对象包含以下方法和属性:
213
214
  *
214
215
  * @property {Function} createEditor - 创建并挂载 Monaco 编辑器到指定容器
@@ -228,6 +229,7 @@ declare function registerMonacoThemes(themes: (ThemeInput | string | SpecialThem
228
229
  * @property {Function} getEditorView - 获取当前编辑器实例
229
230
  * @property {Function} getDiffEditorView - 获取当前 Diff 编辑器实例
230
231
  * @property {Function} getDiffModels - 获取 Diff 的 original/modified 两个模型
232
+ * @property {Function} getCode - 获取当前编辑器或 Diff 编辑器中的代码内容
231
233
  *
232
234
  * @throws {Error} 当主题数组不是数组或长度小于2时抛出错误
233
235
  *
@@ -276,6 +278,10 @@ declare function useMonaco(monacoOptions?: MonacoOptions): {
276
278
  getMonacoInstance(): typeof monaco_shim_d_exports;
277
279
  setUpdateThrottleMs: (ms: number) => void;
278
280
  getUpdateThrottleMs: () => number;
281
+ getCode(): string | {
282
+ original: string;
283
+ modified: string;
284
+ } | null;
279
285
  };
280
286
  //#endregion
281
287
  export { MonacoDiffEditorInstance, MonacoEditorInstance, MonacoLanguage, MonacoOptions, MonacoTheme, RevealStrategy, ShikiHighlighter, clearHighlighterCache, defaultRevealDebounceMs, detectLanguage, getOrCreateHighlighter, isDark, preloadMonacoWorkers, registerMonacoThemes, useMonaco };
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { __export, __reExport } from "./chunk-CHLpw0oG.js";
2
2
  import * as _monaco from "monaco-editor";
3
+ import nodeProcess from "node:process";
3
4
  import { computed, effect, signal } from "alien-signals";
4
5
  import { shikiToMonaco } from "@shikijs/monaco";
5
6
  import { createHighlighter } from "shiki";
@@ -199,34 +200,107 @@ import * as import_monaco_editor from "monaco-editor";
199
200
  __reExport(monaco_shim_exports, import_monaco_editor);
200
201
  const monaco = _monaco;
201
202
 
203
+ //#endregion
204
+ //#region src/utils/logger.ts
205
+ let seq = 0;
206
+ const ENABLED = (() => {
207
+ try {
208
+ if (typeof window !== "undefined" && window.__STREAM_MONACO_DEBUG__ !== void 0) return Boolean(window.__STREAM_MONACO_DEBUG__);
209
+ try {
210
+ const proc = nodeProcess;
211
+ if (proc && proc.env && proc.env.NODE_ENV !== "production") return true;
212
+ } catch {}
213
+ } catch {}
214
+ return false;
215
+ })();
216
+ function log(tag, ...args) {
217
+ if (!ENABLED) return;
218
+ try {
219
+ seq += 1;
220
+ const id = `#${seq}`;
221
+ const ts = typeof performance !== "undefined" && performance.now ? performance.now().toFixed(1) : Date.now();
222
+ console.warn(`${id} [${tag}] @${ts}ms`, ...args);
223
+ } catch (err) {
224
+ try {
225
+ console.warn("[logger] fallback", tag, ...args, err);
226
+ } catch {}
227
+ }
228
+ }
229
+ function error(tag, ...args) {
230
+ if (!ENABLED) return;
231
+ try {
232
+ console.error(`[${tag}]`, ...args);
233
+ } catch (err) {
234
+ try {
235
+ console.error("[logger] fallback error", tag, ...args, err);
236
+ } catch {}
237
+ }
238
+ }
239
+
202
240
  //#endregion
203
241
  //#region src/utils/height.ts
204
242
  function createHeightManager(container, computeNext) {
205
243
  let raf = null;
244
+ let debounceTimer = null;
206
245
  let lastApplied = -1;
207
246
  let suppressed = false;
247
+ const HYSTERESIS_PX = 12;
248
+ const DEBOUNCE_MS = 0;
208
249
  function apply() {
209
250
  const next = computeNext();
251
+ if (next == null) return;
252
+ log("heightManager", "computeNext ->", {
253
+ next,
254
+ lastApplied
255
+ });
256
+ if (!Number.isFinite(next) || next <= 0) {
257
+ log("heightManager", "invalid next height, ignoring", next);
258
+ return;
259
+ }
260
+ if (lastApplied !== -1 && Math.abs(next - lastApplied) <= HYSTERESIS_PX) return;
210
261
  if (next === lastApplied) return;
211
262
  suppressed = true;
212
263
  container.style.height = `${next}px`;
213
264
  lastApplied = next;
265
+ log("heightManager", "applied height ->", next);
214
266
  queueMicrotask(() => {
215
267
  suppressed = false;
216
268
  });
217
269
  }
270
+ function scheduleApply() {
271
+ if (debounceTimer != null) {
272
+ clearTimeout(debounceTimer);
273
+ debounceTimer = null;
274
+ }
275
+ if (DEBOUNCE_MS === 0) {
276
+ if (raf != null) return;
277
+ raf = requestAnimationFrame(() => {
278
+ raf = null;
279
+ apply();
280
+ });
281
+ return;
282
+ }
283
+ debounceTimer = setTimeout(() => {
284
+ debounceTimer = null;
285
+ if (raf != null) return;
286
+ raf = requestAnimationFrame(() => {
287
+ raf = null;
288
+ apply();
289
+ });
290
+ }, DEBOUNCE_MS);
291
+ }
218
292
  function update() {
219
- if (raf != null) return;
220
- raf = requestAnimationFrame(() => {
221
- raf = null;
222
- apply();
223
- });
293
+ scheduleApply();
224
294
  }
225
295
  function dispose() {
226
296
  if (raf != null) {
227
297
  cancelAnimationFrame(raf);
228
298
  raf = null;
229
299
  }
300
+ if (debounceTimer != null) {
301
+ clearTimeout(debounceTimer);
302
+ debounceTimer = null;
303
+ }
230
304
  }
231
305
  function isSuppressed() {
232
306
  return suppressed;
@@ -280,20 +354,58 @@ function createRafScheduler(timeSource) {
280
354
  //#region src/utils/scroll.ts
281
355
  function createScrollWatcherForEditor(ed, opts) {
282
356
  var _ed$getScrollTop, _ed$onDidScrollChange;
357
+ const DEBUG = (() => {
358
+ try {
359
+ if (typeof window !== "undefined" && window.__STREAM_MONACO_DEBUG__ !== void 0) return Boolean(window.__STREAM_MONACO_DEBUG__);
360
+ try {
361
+ const proc = nodeProcess;
362
+ if (proc && proc.env && proc.env.NODE_ENV === "production") return false;
363
+ } catch {}
364
+ } catch {}
365
+ return true;
366
+ })();
283
367
  const initial = ((_ed$getScrollTop = ed.getScrollTop) === null || _ed$getScrollTop === void 0 ? void 0 : _ed$getScrollTop.call(ed)) ?? 0;
284
368
  opts.setLast(initial);
285
- const disp = ((_ed$onDidScrollChange = ed.onDidScrollChange) === null || _ed$onDidScrollChange === void 0 ? void 0 : _ed$onDidScrollChange.call(ed, (e) => {
369
+ if (DEBUG) log("scrollWatcher", "initial scrollTop=", initial);
370
+ let suppressedExternally = false;
371
+ const THRESHOLD_PX = 6;
372
+ const listener = (e) => {
286
373
  var _ed$getScrollTop2;
374
+ if (suppressedExternally) {
375
+ if (DEBUG) log("scrollWatcher", "suppressedExternally, ignoring event");
376
+ return;
377
+ }
287
378
  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;
288
379
  const delta = currentTop - opts.getLast();
289
380
  opts.setLast(currentTop);
381
+ if (Math.abs(delta) < THRESHOLD_PX) {
382
+ if (DEBUG) log("scrollWatcher", "small delta ignored", delta);
383
+ return;
384
+ }
385
+ if (DEBUG) log("scrollWatcher", "delta=", delta, "currentTop=", currentTop);
290
386
  if (delta < 0) {
387
+ if (DEBUG) log("scrollWatcher", "pause detected delta=", delta);
291
388
  opts.onPause();
292
389
  return;
293
390
  }
391
+ if (DEBUG) log("scrollWatcher", "maybe resume delta=", delta);
294
392
  opts.onMaybeResume();
295
- })) ?? null;
296
- return disp;
393
+ };
394
+ const disp = ((_ed$onDidScrollChange = ed.onDidScrollChange) === null || _ed$onDidScrollChange === void 0 ? void 0 : _ed$onDidScrollChange.call(ed, listener)) ?? null;
395
+ const api = {
396
+ dispose() {
397
+ try {
398
+ if (disp && typeof disp.dispose === "function") disp.dispose();
399
+ else if (typeof disp === "function") disp();
400
+ } catch {}
401
+ if (DEBUG) log("scrollWatcher", "dispose");
402
+ },
403
+ setSuppressed(v) {
404
+ suppressedExternally = !!v;
405
+ if (DEBUG) log("scrollWatcher", "setSuppressed =>", suppressedExternally);
406
+ }
407
+ };
408
+ return api;
297
409
  }
298
410
 
299
411
  //#endregion
@@ -847,12 +959,14 @@ var EditorManager = class {
847
959
  _hasScrollBar = false;
848
960
  shouldAutoScroll = true;
849
961
  scrollWatcher = null;
962
+ scrollWatcherSuppressionTimer = null;
850
963
  lastScrollTop = 0;
851
964
  cachedScrollHeight = null;
852
965
  cachedLineHeight = null;
853
966
  cachedComputedHeight = null;
854
967
  cachedLineCount = null;
855
968
  lastKnownCodeDirty = false;
969
+ debug = false;
856
970
  measureViewport() {
857
971
  var _this$editorView$getL, _this$editorView, _this$editorView$getS, _this$editorView2, _this$editorView$getS2, _this$editorView3;
858
972
  if (!this.editorView) return null;
@@ -880,8 +994,10 @@ var EditorManager = class {
880
994
  revealDebounceId = null;
881
995
  revealDebounceMs = defaultRevealDebounceMs;
882
996
  revealIdleTimerId = null;
997
+ revealTicket = 0;
883
998
  revealStrategyOption;
884
999
  revealBatchOnIdleMsOption;
1000
+ scrollWatcherSuppressionMs = 500;
885
1001
  constructor(options, maxHeightValue, maxHeightCSS, autoScrollOnUpdate, autoScrollInitial, autoScrollThresholdPx, autoScrollThresholdLines, revealDebounceMsOption) {
886
1002
  this.options = options;
887
1003
  this.maxHeightValue = maxHeightValue;
@@ -892,6 +1008,21 @@ var EditorManager = class {
892
1008
  this.autoScrollThresholdLines = autoScrollThresholdLines;
893
1009
  this.revealDebounceMsOption = revealDebounceMsOption;
894
1010
  }
1011
+ initDebugFlag() {
1012
+ if (typeof window !== "undefined" && window.__STREAM_MONACO_DEBUG__ !== void 0) {
1013
+ this.debug = Boolean(window.__STREAM_MONACO_DEBUG__);
1014
+ return;
1015
+ }
1016
+ if (this.options && this.options.debug !== void 0) {
1017
+ this.debug = Boolean(this.options.debug);
1018
+ return;
1019
+ }
1020
+ this.debug = false;
1021
+ }
1022
+ dlog(...args) {
1023
+ if (!this.debug) return;
1024
+ log("EditorManager", ...args);
1025
+ }
895
1026
  hasVerticalScrollbar() {
896
1027
  if (!this.editorView) return false;
897
1028
  if (this._hasScrollBar) return true;
@@ -913,19 +1044,40 @@ var EditorManager = class {
913
1044
  const lineCount = this.cachedLineCount ?? ((_editorView$getModel = editorView.getModel()) === null || _editorView$getModel === void 0 ? void 0 : _editorView$getModel.getLineCount()) ?? 1;
914
1045
  const lineHeight = editorView.getOption(monaco_shim_exports.editor.EditorOption.lineHeight);
915
1046
  const height = Math.min(lineCount * lineHeight + padding, this.maxHeightValue);
1047
+ try {
1048
+ log("EditorManager.computedHeight", {
1049
+ lineCount,
1050
+ lineHeight,
1051
+ computed: height,
1052
+ maxHeightValue: this.maxHeightValue
1053
+ });
1054
+ } catch {}
916
1055
  return height;
917
1056
  }
918
1057
  maybeScrollToBottom(targetLine) {
919
1058
  this.rafScheduler.schedule("maybe-scroll", () => {
920
- if (!(this.autoScrollOnUpdate && this.shouldAutoScroll && this.hasVerticalScrollbar())) return;
1059
+ const hasVS = this.hasVerticalScrollbar();
1060
+ this.dlog("maybeScrollToBottom called", {
1061
+ autoScrollOnUpdate: this.autoScrollOnUpdate,
1062
+ shouldAutoScroll: this.shouldAutoScroll,
1063
+ hasVerticalScrollbar: hasVS,
1064
+ targetLine
1065
+ });
1066
+ if (!(this.autoScrollOnUpdate && this.shouldAutoScroll && this.hasVerticalScrollbar())) {
1067
+ this.dlog("maybeScrollToBottom skipped (auto-scroll conditions not met)");
1068
+ return;
1069
+ }
921
1070
  const model = this.editorView.getModel();
922
1071
  const line = targetLine ?? (model === null || model === void 0 ? void 0 : model.getLineCount()) ?? 1;
923
1072
  const batchMs = this.revealBatchOnIdleMsOption ?? this.options.revealBatchOnIdleMs ?? defaultRevealBatchOnIdleMs;
924
1073
  if (typeof batchMs === "number" && batchMs > 0) {
925
1074
  if (this.revealIdleTimerId != null) clearTimeout(this.revealIdleTimerId);
1075
+ const ticket = ++this.revealTicket;
1076
+ this.dlog("scheduled idle reveal ticket=", ticket, "line=", line, "batchMs=", batchMs);
926
1077
  this.revealIdleTimerId = setTimeout(() => {
927
1078
  this.revealIdleTimerId = null;
928
- this.performReveal(line);
1079
+ this.dlog("idle reveal timer firing, ticket=", ticket, "line=", line);
1080
+ this.performReveal(line, ticket);
929
1081
  }, batchMs);
930
1082
  return;
931
1083
  }
@@ -936,14 +1088,23 @@ var EditorManager = class {
936
1088
  const ms = typeof this.revealDebounceMs === "number" && this.revealDebounceMs > 0 ? this.revealDebounceMs : typeof this.revealDebounceMsOption === "number" && this.revealDebounceMsOption > 0 ? this.revealDebounceMsOption : this.revealDebounceMs;
937
1089
  this.revealDebounceId = setTimeout(() => {
938
1090
  this.revealDebounceId = null;
939
- this.performReveal(line);
1091
+ const ticket = ++this.revealTicket;
1092
+ this.dlog("scheduled debounce reveal ticket=", ticket, "line=", line, "ms=", ms);
1093
+ this.performReveal(line, ticket);
940
1094
  }, ms);
941
1095
  });
942
1096
  }
943
- performReveal(line) {
1097
+ performReveal(line, ticket) {
944
1098
  this.rafScheduler.schedule("reveal", () => {
945
1099
  var _editor;
1100
+ if (ticket !== this.revealTicket) {
1101
+ this.dlog("performReveal skipped, stale ticket", ticket, "current", this.revealTicket);
1102
+ return;
1103
+ }
1104
+ this.dlog("performReveal executing, ticket=", ticket, "line=", line);
1105
+ this.lastPerformedRevealTicket = ticket;
946
1106
  const strategy = this.revealStrategyOption ?? this.options.revealStrategy ?? "centerIfOutside";
1107
+ this.dlog("performReveal strategy=", strategy);
947
1108
  const ScrollType = monaco_shim_exports.ScrollType || ((_editor = monaco_shim_exports.editor) === null || _editor === void 0 ? void 0 : _editor.ScrollType);
948
1109
  const smooth = ScrollType && typeof ScrollType.Smooth !== "undefined" ? ScrollType.Smooth : void 0;
949
1110
  try {
@@ -960,11 +1121,60 @@ var EditorManager = class {
960
1121
  }
961
1122
  });
962
1123
  }
1124
+ performImmediateReveal(line, ticket) {
1125
+ this.dlog("performImmediateReveal line=", line, "ticket=", ticket);
1126
+ try {
1127
+ var _editor2;
1128
+ if (!this.editorView) return;
1129
+ if (ticket !== this.revealTicket) {
1130
+ this.dlog("performImmediateReveal skipped, stale ticket", ticket, "current", this.revealTicket);
1131
+ return;
1132
+ }
1133
+ this.lastPerformedRevealTicket = ticket;
1134
+ const ScrollType = monaco_shim_exports.ScrollType || ((_editor2 = monaco_shim_exports.editor) === null || _editor2 === void 0 ? void 0 : _editor2.ScrollType);
1135
+ const immediate = ScrollType && typeof ScrollType.Immediate !== "undefined" ? ScrollType.Immediate : void 0;
1136
+ if (typeof immediate !== "undefined") this.editorView.revealLine(line, immediate);
1137
+ else this.editorView.revealLine(line);
1138
+ } catch {}
1139
+ try {
1140
+ this.measureViewport();
1141
+ } catch {}
1142
+ }
1143
+ forceReveal(line) {
1144
+ try {
1145
+ var _editor3;
1146
+ if (!this.editorView) return;
1147
+ const ScrollType = monaco_shim_exports.ScrollType || ((_editor3 = monaco_shim_exports.editor) === null || _editor3 === void 0 ? void 0 : _editor3.ScrollType);
1148
+ const immediate = ScrollType && typeof ScrollType.Immediate !== "undefined" ? ScrollType.Immediate : void 0;
1149
+ if (typeof immediate !== "undefined") this.editorView.revealLine(line, immediate);
1150
+ else this.editorView.revealLine(line);
1151
+ } catch {}
1152
+ try {
1153
+ this.measureViewport();
1154
+ } catch {}
1155
+ try {
1156
+ var _this$editorView4, _this$editorView4$get;
1157
+ this.shouldAutoScroll = true;
1158
+ 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;
1159
+ } catch {}
1160
+ }
1161
+ isOverflowAuto() {
1162
+ try {
1163
+ return !!this.lastContainer && this.lastContainer.style.overflow === "auto";
1164
+ } catch {
1165
+ return false;
1166
+ }
1167
+ }
1168
+ shouldPerformImmediateReveal() {
1169
+ return this.autoScrollOnUpdate && this.shouldAutoScroll && this.hasVerticalScrollbar() && this.isOverflowAuto();
1170
+ }
963
1171
  async createEditor(container, code, language, currentTheme) {
964
- var _this$editorView$getS3, _this$editorView4, _this$editorView$getO, _this$editorView5, _this$editorView$getM, _this$editorView$onDi, _this$editorView6;
1172
+ var _this$editorView$getS3, _this$editorView5, _this$editorView$getO, _this$editorView6, _this$editorView$getM, _this$editorView$onDi, _this$editorView7;
965
1173
  this.cleanup();
966
1174
  this.lastContainer = container;
967
- container.style.overflow = "auto";
1175
+ this.initDebugFlag();
1176
+ this.dlog("createEditor container, maxHeight", this.maxHeightValue);
1177
+ container.style.overflow = "hidden";
968
1178
  container.style.maxHeight = this.maxHeightCSS;
969
1179
  this.editorView = monaco_shim_exports.editor.create(container, {
970
1180
  value: code,
@@ -995,22 +1205,51 @@ var EditorManager = class {
995
1205
  }
996
1206
  if (this.revealIdleTimerId != null) clearTimeout(this.revealIdleTimerId);
997
1207
  this.revealIdleTimerId = null;
998
- this.editorHeightManager = createHeightManager(container, () => this.computedHeight(this.editorView));
1208
+ const MIN_VISIBLE_HEIGHT = Math.min(120, this.maxHeightValue);
1209
+ container.style.minHeight = `${MIN_VISIBLE_HEIGHT}px`;
1210
+ this.editorHeightManager = createHeightManager(container, () => {
1211
+ const computed$2 = this.computedHeight(this.editorView);
1212
+ const clamped = Math.min(computed$2, this.maxHeightValue);
1213
+ return Math.max(clamped, MIN_VISIBLE_HEIGHT);
1214
+ });
999
1215
  this.editorHeightManager.update();
1000
- 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;
1001
- 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;
1216
+ const initialComputed = this.computedHeight(this.editorView);
1217
+ if (initialComputed >= this.maxHeightValue - 1) {
1218
+ container.style.height = `${this.maxHeightValue}px`;
1219
+ container.style.overflow = "auto";
1220
+ this.dlog("applied immediate maxHeight on createEditor", this.maxHeightValue);
1221
+ }
1222
+ 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;
1223
+ 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;
1002
1224
  this.cachedComputedHeight = this.computedHeight(this.editorView);
1003
1225
  this.cachedLineCount = ((_this$editorView$getM = this.editorView.getModel()) === null || _this$editorView$getM === void 0 ? void 0 : _this$editorView$getM.getLineCount()) ?? null;
1004
- (_this$editorView$onDi = (_this$editorView6 = this.editorView).onDidContentSizeChange) === null || _this$editorView$onDi === void 0 || _this$editorView$onDi.call(_this$editorView6, () => {
1226
+ (_this$editorView$onDi = (_this$editorView7 = this.editorView).onDidContentSizeChange) === null || _this$editorView$onDi === void 0 || _this$editorView$onDi.call(_this$editorView7, () => {
1005
1227
  this._hasScrollBar = false;
1006
1228
  this.rafScheduler.schedule("content-size-change", () => {
1007
1229
  try {
1008
- var _this$editorView7, _this$editorHeightMan, _this$editorHeightMan2;
1009
- this.measureViewport();
1010
- 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;
1011
- if ((_this$editorHeightMan = this.editorHeightManager) === null || _this$editorHeightMan === void 0 ? void 0 : _this$editorHeightMan.isSuppressed()) return;
1230
+ var _this$editorView8, _this$editorHeightMan, _this$editorHeightMan2;
1231
+ this.dlog("content-size-change frame");
1232
+ const m = this.measureViewport();
1233
+ this.dlog("content-size-change measure", m);
1234
+ 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;
1235
+ if ((_this$editorHeightMan = this.editorHeightManager) === null || _this$editorHeightMan === void 0 ? void 0 : _this$editorHeightMan.isSuppressed()) {
1236
+ this.dlog("content-size-change skipped height update (suppressed)");
1237
+ return;
1238
+ }
1239
+ this.dlog("content-size-change calling heightManager.update");
1012
1240
  (_this$editorHeightMan2 = this.editorHeightManager) === null || _this$editorHeightMan2 === void 0 || _this$editorHeightMan2.update();
1013
- } catch {}
1241
+ const computed$2 = this.computedHeight(this.editorView);
1242
+ if (this.lastContainer) {
1243
+ const prevOverflow = this.lastContainer.style.overflow;
1244
+ const newOverflow = computed$2 >= this.maxHeightValue - 1 ? "auto" : "hidden";
1245
+ if (prevOverflow !== newOverflow) {
1246
+ this.lastContainer.style.overflow = newOverflow;
1247
+ if (newOverflow === "auto" && this.shouldAutoScroll) this.maybeScrollToBottom();
1248
+ }
1249
+ }
1250
+ } catch (err) {
1251
+ error("EditorManager", "content-size-change error", err);
1252
+ }
1014
1253
  });
1015
1254
  });
1016
1255
  this.editorView.onDidChangeModelContent(() => {
@@ -1051,6 +1290,65 @@ var EditorManager = class {
1051
1290
  this.lastKnownCodeDirty = false;
1052
1291
  }
1053
1292
  }
1293
+ suppressScrollWatcher(ms) {
1294
+ try {
1295
+ if (!this.scrollWatcher || typeof this.scrollWatcher.setSuppressed !== "function") return;
1296
+ this.dlog("suppressScrollWatcher", ms);
1297
+ if (this.scrollWatcherSuppressionTimer != null) {
1298
+ clearTimeout(this.scrollWatcherSuppressionTimer);
1299
+ this.scrollWatcherSuppressionTimer = null;
1300
+ }
1301
+ this.scrollWatcher.setSuppressed(true);
1302
+ this.scrollWatcherSuppressionTimer = setTimeout(() => {
1303
+ try {
1304
+ if (this.scrollWatcher && typeof this.scrollWatcher.setSuppressed === "function") {
1305
+ this.scrollWatcher.setSuppressed(false);
1306
+ this.dlog("suppressScrollWatcher cleared");
1307
+ }
1308
+ } catch {}
1309
+ this.scrollWatcherSuppressionTimer = null;
1310
+ }, ms);
1311
+ } catch {}
1312
+ }
1313
+ scheduleImmediateRevealAfterLayout(line) {
1314
+ const ticket = ++this.revealTicket;
1315
+ this.dlog("scheduleImmediateRevealAfterLayout ticket=", ticket, "line=", line);
1316
+ this.rafScheduler.schedule("immediate-reveal", async () => {
1317
+ try {
1318
+ const target = this.editorView && this.editorHeightManager ? Math.min(this.computedHeight(this.editorView), this.maxHeightValue) : -1;
1319
+ if (target !== -1 && this.editorHeightManager) await this.waitForHeightApplied(target, 500);
1320
+ else await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(() => r())));
1321
+ this.dlog("running delayed immediate reveal", "ticket=", ticket, "line=", line);
1322
+ this.performImmediateReveal(line, ticket);
1323
+ } catch (err) {
1324
+ error("EditorManager", "scheduleImmediateRevealAfterLayout error", err);
1325
+ }
1326
+ });
1327
+ }
1328
+ waitForHeightApplied(target, timeoutMs = 500) {
1329
+ return new Promise((resolve) => {
1330
+ const start = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
1331
+ const check = () => {
1332
+ try {
1333
+ var _this$editorHeightMan3, _this$editorHeightMan4;
1334
+ 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;
1335
+ if (last !== -1 && Math.abs(last - target) <= 12) {
1336
+ this.dlog("waitForHeightApplied satisfied", last, "target=", target);
1337
+ resolve();
1338
+ return;
1339
+ }
1340
+ const now = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
1341
+ if (now - start > timeoutMs) {
1342
+ log("EditorManager", "waitForHeightApplied timeout", last, "target=", target);
1343
+ resolve();
1344
+ return;
1345
+ }
1346
+ } catch {}
1347
+ requestAnimationFrame(check);
1348
+ };
1349
+ check();
1350
+ });
1351
+ }
1054
1352
  updateCode(newCode, codeLanguage) {
1055
1353
  this.pendingUpdate = {
1056
1354
  code: newCode,
@@ -1073,7 +1371,18 @@ var EditorManager = class {
1073
1371
  this.lastKnownCode = newCode;
1074
1372
  const newLineCount$1 = model.getLineCount();
1075
1373
  this.cachedLineCount = newLineCount$1;
1076
- if (newLineCount$1 !== prevLineCount$1) this.maybeScrollToBottom(newLineCount$1);
1374
+ if (newLineCount$1 !== prevLineCount$1) {
1375
+ const shouldImmediate = this.shouldPerformImmediateReveal();
1376
+ if (shouldImmediate) this.suppressScrollWatcher(this.scrollWatcherSuppressionMs);
1377
+ try {
1378
+ const computed$2 = this.computedHeight(this.editorView);
1379
+ if (computed$2 >= this.maxHeightValue - 1 && this.lastContainer) this.lastContainer.style.height = `${this.maxHeightValue}px`;
1380
+ } catch {}
1381
+ if (shouldImmediate) try {
1382
+ this.forceReveal(newLineCount$1);
1383
+ } catch {}
1384
+ else this.maybeScrollToBottom(newLineCount$1);
1385
+ }
1077
1386
  return;
1078
1387
  }
1079
1388
  const prevCode = this.appendBuffer.length > 0 ? this.editorView.getValue() : this.lastKnownCode ?? this.editorView.getValue();
@@ -1089,7 +1398,12 @@ var EditorManager = class {
1089
1398
  this.lastKnownCode = newCode;
1090
1399
  const newLineCount = model.getLineCount();
1091
1400
  this.cachedLineCount = newLineCount;
1092
- if (newLineCount !== prevLineCount) this.maybeScrollToBottom(newLineCount);
1401
+ if (newLineCount !== prevLineCount) {
1402
+ const shouldImmediate = this.shouldPerformImmediateReveal();
1403
+ if (shouldImmediate) this.suppressScrollWatcher(this.scrollWatcherSuppressionMs);
1404
+ if (shouldImmediate) this.scheduleImmediateRevealAfterLayout(newLineCount);
1405
+ else this.maybeScrollToBottom(newLineCount);
1406
+ }
1093
1407
  }
1094
1408
  appendCode(appendText, codeLanguage) {
1095
1409
  if (!this.editorView) return;
@@ -1167,7 +1481,16 @@ var EditorManager = class {
1167
1481
  const newLineCount = model.getLineCount();
1168
1482
  if (lastLine !== newLineCount) {
1169
1483
  this.cachedLineCount = newLineCount;
1170
- this.maybeScrollToBottom(newLineCount);
1484
+ const shouldImmediate = this.shouldPerformImmediateReveal();
1485
+ if (shouldImmediate) this.suppressScrollWatcher(this.scrollWatcherSuppressionMs);
1486
+ try {
1487
+ const computed$2 = this.computedHeight(this.editorView);
1488
+ if (computed$2 >= this.maxHeightValue - 1 && this.lastContainer) this.lastContainer.style.height = `${this.maxHeightValue}px`;
1489
+ } catch {}
1490
+ if (shouldImmediate) try {
1491
+ this.forceReveal(newLineCount);
1492
+ } catch {}
1493
+ else this.maybeScrollToBottom(newLineCount);
1171
1494
  }
1172
1495
  }
1173
1496
  setLanguage(language, languages$1) {
@@ -1185,16 +1508,33 @@ var EditorManager = class {
1185
1508
  this.rafScheduler.cancel("update");
1186
1509
  this.rafScheduler.cancel("sync-last-known");
1187
1510
  this.rafScheduler.cancel("content-size-change");
1511
+ this.rafScheduler.cancel("maybe-scroll");
1512
+ this.rafScheduler.cancel("reveal");
1513
+ this.rafScheduler.cancel("immediate-reveal");
1514
+ this.rafScheduler.cancel("maybe-resume");
1188
1515
  this.pendingUpdate = null;
1189
1516
  this.rafScheduler.cancel("append");
1190
1517
  this.appendBufferScheduled = false;
1191
1518
  this.appendBuffer.length = 0;
1519
+ if (this.revealDebounceId != null) {
1520
+ clearTimeout(this.revealDebounceId);
1521
+ this.revealDebounceId = null;
1522
+ }
1523
+ if (this.revealIdleTimerId != null) {
1524
+ clearTimeout(this.revealIdleTimerId);
1525
+ this.revealIdleTimerId = null;
1526
+ }
1527
+ if (this.scrollWatcherSuppressionTimer != null) {
1528
+ clearTimeout(this.scrollWatcherSuppressionTimer);
1529
+ this.scrollWatcherSuppressionTimer = null;
1530
+ }
1192
1531
  if (this.editorView) {
1193
1532
  this.editorView.dispose();
1194
1533
  this.editorView = null;
1195
1534
  }
1196
1535
  this.lastKnownCode = null;
1197
1536
  if (this.lastContainer) {
1537
+ this.lastContainer.style.minHeight = "";
1198
1538
  this.lastContainer.innerHTML = "";
1199
1539
  this.lastContainer = null;
1200
1540
  }
@@ -1212,13 +1552,27 @@ var EditorManager = class {
1212
1552
  this.pendingUpdate = null;
1213
1553
  this.rafScheduler.cancel("sync-last-known");
1214
1554
  if (this.scrollWatcher) {
1215
- this.scrollWatcher.dispose();
1555
+ try {
1556
+ this.scrollWatcher.dispose();
1557
+ } catch {}
1216
1558
  this.scrollWatcher = null;
1217
1559
  }
1218
1560
  if (this.revealDebounceId != null) {
1219
1561
  clearTimeout(this.revealDebounceId);
1220
1562
  this.revealDebounceId = null;
1221
1563
  }
1564
+ if (this.revealIdleTimerId != null) {
1565
+ clearTimeout(this.revealIdleTimerId);
1566
+ this.revealIdleTimerId = null;
1567
+ }
1568
+ if (this.scrollWatcherSuppressionTimer != null) {
1569
+ clearTimeout(this.scrollWatcherSuppressionTimer);
1570
+ this.scrollWatcherSuppressionTimer = null;
1571
+ }
1572
+ this.rafScheduler.cancel("maybe-scroll");
1573
+ this.rafScheduler.cancel("reveal");
1574
+ this.rafScheduler.cancel("immediate-reveal");
1575
+ this.rafScheduler.cancel("maybe-resume");
1222
1576
  this._hasScrollBar = false;
1223
1577
  this.shouldAutoScroll = !!this.autoScrollInitial;
1224
1578
  this.lastScrollTop = 0;
@@ -1525,6 +1879,7 @@ let RevealStrategy = /* @__PURE__ */ function(RevealStrategy$1) {
1525
1879
  * getEditorView: () => monaco.editor.IStandaloneCodeEditor | null,
1526
1880
  * getDiffEditorView: () => monaco.editor.IStandaloneDiffEditor | null,
1527
1881
  * getDiffModels: () => { original: monaco.editor.ITextModel | null, modified: monaco.editor.ITextModel | null },
1882
+ * getCode: () => string | { original: string, modified: string } | null,
1528
1883
  * }} 返回对象包含以下方法和属性:
1529
1884
  *
1530
1885
  * @property {Function} createEditor - 创建并挂载 Monaco 编辑器到指定容器
@@ -1544,6 +1899,7 @@ let RevealStrategy = /* @__PURE__ */ function(RevealStrategy$1) {
1544
1899
  * @property {Function} getEditorView - 获取当前编辑器实例
1545
1900
  * @property {Function} getDiffEditorView - 获取当前 Diff 编辑器实例
1546
1901
  * @property {Function} getDiffModels - 获取 Diff 的 original/modified 两个模型
1902
+ * @property {Function} getCode - 获取当前编辑器或 Diff 编辑器中的代码内容
1547
1903
  *
1548
1904
  * @throws {Error} 当主题数组不是数组或长度小于2时抛出错误
1549
1905
  *
@@ -2050,7 +2406,26 @@ function useMonaco(monacoOptions = {}) {
2050
2406
  return monaco_shim_exports;
2051
2407
  },
2052
2408
  setUpdateThrottleMs,
2053
- getUpdateThrottleMs
2409
+ getUpdateThrottleMs,
2410
+ getCode() {
2411
+ if (editorView) try {
2412
+ var _editorView$getModel;
2413
+ return ((_editorView$getModel = editorView.getModel()) === null || _editorView$getModel === void 0 ? void 0 : _editorView$getModel.getValue()) ?? null;
2414
+ } catch {
2415
+ return null;
2416
+ }
2417
+ if (diffEditorView || originalModel && modifiedModel) try {
2418
+ const original = (originalModel === null || originalModel === void 0 ? void 0 : originalModel.getValue()) ?? "";
2419
+ const modified = (modifiedModel === null || modifiedModel === void 0 ? void 0 : modifiedModel.getValue()) ?? "";
2420
+ return {
2421
+ original,
2422
+ modified
2423
+ };
2424
+ } catch {
2425
+ return null;
2426
+ }
2427
+ return null;
2428
+ }
2054
2429
  };
2055
2430
  }
2056
2431
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "stream-monaco",
3
3
  "type": "module",
4
- "version": "0.0.2",
4
+ "version": "0.0.3",
5
5
  "packageManager": "pnpm@10.18.3",
6
6
  "description": "A framework-agnostic library for integrating Monaco Editor with Shiki highlighting, optimized for streaming updates.",
7
7
  "author": "Simon He",