@lvce-editor/editor-worker 19.72.3 → 19.72.5

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.
@@ -5445,7 +5445,7 @@ const mergeConflictsEqual$1 = (oldState, newState) => {
5445
5445
  return conflict.startRowIndex === other.startRowIndex && conflict.endRowIndex === other.endRowIndex;
5446
5446
  });
5447
5447
  };
5448
- const updateDerivedState = async (oldState, newState) => {
5448
+ const updateDerivedState = async (oldState, newState, deferGutterDecorations = false) => {
5449
5449
  const horizontalState = oldState.initial || oldState.lines !== newState.lines || oldState.width !== newState.width || oldState.charWidth !== newState.charWidth || oldState.fontFamily !== newState.fontFamily || oldState.fontSize !== newState.fontSize || oldState.fontWeight !== newState.fontWeight || oldState.isMonospaceFont !== newState.isMonospaceFont || oldState.letterSpacing !== newState.letterSpacing || oldState.tabSize !== newState.tabSize || oldState.lineNumbers !== newState.lineNumbers || oldState.breakPoints !== newState.breakPoints || oldState.gutterDecorations !== newState.gutterDecorations || oldState.lightBulbRowIndex !== newState.lightBulbRowIndex ? await updateHorizontalLayout(newState) : newState;
5450
5450
  const layoutState = oldState.lines !== newState.lines && 'foldingRanges' in newState ? updateLayout(horizontalState, []) : horizontalState;
5451
5451
  const nextState = mergeConflictsEqual$1(oldState, layoutState) ? layoutState : {
@@ -5513,7 +5513,7 @@ const updateDerivedState = async (oldState, newState) => {
5513
5513
  lightBulbRowIndex: await getLightBulbRowIndex(finalState)
5514
5514
  };
5515
5515
  }
5516
- if (oldState.lines !== nextState.lines || oldState.uri !== nextState.uri) {
5516
+ if (!deferGutterDecorations && (oldState.lines !== nextState.lines || oldState.uri !== nextState.uri)) {
5517
5517
  finalState = {
5518
5518
  ...finalState,
5519
5519
  gutterDecorations: await getEditorGutterDecorations(finalState)
@@ -5627,7 +5627,7 @@ const FocusFindWidgetToggleReplace = 42;
5627
5627
  const SourceActions = 38;
5628
5628
  const FocusCodeGenerator = 52;
5629
5629
 
5630
- const createEditor2 = (id, uri, x, y, width, height, platform, assetDir, _languageId, _tokenizePath, _useCache, applicationId) => {
5630
+ const createEditor2 = (id, uri, x, y, width, height, platform, assetDir, _languageId, _tokenizePath, _useCache, applicationId, editorFileCacheEnabled = false) => {
5631
5631
  number(id);
5632
5632
  const editor = {
5633
5633
  ...(applicationId !== undefined && {
@@ -5654,6 +5654,7 @@ const createEditor2 = (id, uri, x, y, width, height, platform, assetDir, _langua
5654
5654
  differences: [],
5655
5655
  documentSymbols: [],
5656
5656
  dragAndDropEnabled: true,
5657
+ editorFileCacheEnabled,
5657
5658
  embeds: [],
5658
5659
  endOfLine: 'lf',
5659
5660
  endOfLineDecorations: [],
@@ -6259,7 +6260,7 @@ const run = async (uid, token, save) => {
6259
6260
  }
6260
6261
  await save(token);
6261
6262
  };
6262
- const schedule = (uid, save) => {
6263
+ const schedule$1 = (uid, save) => {
6263
6264
  dispose$4(uid);
6264
6265
  const token = ++state$7.nextToken;
6265
6266
  const timeout = setTimeout(run, autoSaveDelay, uid, token, save);
@@ -7900,6 +7901,70 @@ const editorDiagnosticEffect = {
7900
7901
  isActive: (oldEditor, newEditor) => !oldEditor.initial && !newEditor.loadError && newEditor.diagnosticsEnabled && (oldEditor.lines !== newEditor.lines || oldEditor.languageId !== newEditor.languageId)
7901
7902
  };
7902
7903
 
7904
+ const refreshes = new WeakMap();
7905
+ const isCurrent = (editor, snapshot) => Boolean(editor && editor.lifecycle === snapshot.lifecycle && !editor.lifecycle?.disposed && editor.lines === snapshot.lines && editor.gutterDecorations === snapshot.gutterDecorations && editor.uri === snapshot.uri && editor.languageId === snapshot.languageId && editor.applicationId === snapshot.applicationId);
7906
+ const refresh = async request => {
7907
+ try {
7908
+ while (request.pending) {
7909
+ const snapshot = request.pending;
7910
+ request.pending = undefined;
7911
+ if (snapshot.lifecycle?.disposed) {
7912
+ continue;
7913
+ }
7914
+ const gutterDecorations = await getEditorGutterDecorations(snapshot);
7915
+ const changed = await enqueue(snapshot.uid, async () => {
7916
+ const current = get$8(snapshot.uid)?.newState;
7917
+ if (!isCurrent(current, snapshot) || current.gutterDecorations.length === gutterDecorations.length && gutterDecorations.every((item, index) => item.rowIndex === current.gutterDecorations[index].rowIndex && item.type === current.gutterDecorations[index].type)) {
7918
+ return false;
7919
+ }
7920
+ const next = await updateDerivedState(current, {
7921
+ ...current,
7922
+ gutterDecorations
7923
+ });
7924
+ // Derived state may await layout RPCs while an asynchronous render consumes the baseline.
7925
+ const latest = get$8(snapshot.uid);
7926
+ if (!isCurrent(latest?.newState, snapshot)) {
7927
+ return false;
7928
+ }
7929
+ set$a(snapshot.uid, latest.oldState, next);
7930
+ return true;
7931
+ });
7932
+ if (changed) {
7933
+ await invoke$d('Editor.renderPending', snapshot.uid);
7934
+ }
7935
+ }
7936
+ } catch (error) {
7937
+ console.warn('Failed to refresh gutter decorations:', error);
7938
+ } finally {
7939
+ request.running = false;
7940
+ if (request.pending) {
7941
+ request.running = true;
7942
+ void refresh(request);
7943
+ }
7944
+ }
7945
+ };
7946
+ const schedule = editor => {
7947
+ const {
7948
+ lifecycle
7949
+ } = editor;
7950
+ if (!lifecycle || lifecycle.disposed) {
7951
+ return;
7952
+ }
7953
+ let request = refreshes.get(lifecycle);
7954
+ if (!request) {
7955
+ request = {
7956
+ pending: undefined,
7957
+ running: false
7958
+ };
7959
+ refreshes.set(lifecycle, request);
7960
+ }
7961
+ request.pending = editor;
7962
+ if (!request.running) {
7963
+ request.running = true;
7964
+ void refresh(request);
7965
+ }
7966
+ };
7967
+
7903
7968
  const cursorUndoLimit = 100;
7904
7969
  const selectionsEqual = (left, right) => {
7905
7970
  if (left === right) {
@@ -7983,7 +8048,8 @@ const wrapCommand$1 = (fn, preservesTypingCoalescing = false, returnState = true
7983
8048
  if (state === newEditor) {
7984
8049
  return returnState ? newEditor : undefined;
7985
8050
  }
7986
- const newEditorWithDerivedState = await updateDerivedState(state, newEditor);
8051
+ const deferGutterDecorations = !initial && uri === newEditor.uri && lines !== newEditor.lines && Boolean(newEditor.lifecycle);
8052
+ const newEditorWithDerivedState = await updateDerivedState(state, newEditor, deferGutterDecorations);
7987
8053
  // Another command can commit before the renderer consumes this edit.
7988
8054
  // Keep its last rendered baseline, including renders completed while we awaited derived state.
7989
8055
  const renderedState = get$8(uid)?.oldState ?? oldInstance.oldState;
@@ -7993,6 +8059,9 @@ const wrapCommand$1 = (fn, preservesTypingCoalescing = false, returnState = true
7993
8059
  void editorDiagnosticEffect.apply(newEditorWithDerivedState);
7994
8060
  }
7995
8061
  const finalEditor = newEditorWithDerivedState;
8062
+ if (deferGutterDecorations) {
8063
+ schedule(finalEditor);
8064
+ }
7996
8065
  await notifyEditorStatusChange(state, finalEditor);
7997
8066
  if (!initial && uri === finalEditor.uri && (endOfLine !== finalEditor.endOfLine || insertSpaces !== finalEditor.insertSpaces || lines !== finalEditor.lines || modified !== finalEditor.modified || redoStack !== finalEditor.redoStack || undoStack !== finalEditor.undoStack)) {
7998
8067
  for (const key of getKeys$2()) {
@@ -8015,15 +8084,18 @@ const wrapCommand$1 = (fn, preservesTypingCoalescing = false, returnState = true
8015
8084
  redoStack: finalEditor.redoStack,
8016
8085
  undoStack: finalEditor.undoStack,
8017
8086
  visualDecorations: finalEditor.visualDecorations
8018
- });
8087
+ }, deferGutterDecorations);
8019
8088
  set$a(otherUid, instance.oldState, synchronizedEditor);
8089
+ if (deferGutterDecorations) {
8090
+ schedule(synchronizedEditor);
8091
+ }
8020
8092
  if (editorDiagnosticEffect.isActive(editor, synchronizedEditor)) {
8021
8093
  void editorDiagnosticEffect.apply(synchronizedEditor);
8022
8094
  }
8023
8095
  }
8024
8096
  }
8025
8097
  if (lines !== finalEditor.lines && !isUntitledFile(finalEditor.uri)) {
8026
- schedule(uid, token => saveAfterDelay(uid, token));
8098
+ schedule$1(uid, token => saveAfterDelay(uid, token));
8027
8099
  } else if (modified && !finalEditor.modified) {
8028
8100
  dispose$4(uid);
8029
8101
  }
@@ -16671,11 +16743,78 @@ const intialize = async (syntaxHighlightingEnabled, syncIncremental) => {
16671
16743
  };
16672
16744
 
16673
16745
  const largeFileContentLength = 10 * 1024 * 1024;
16746
+ const editorFileCacheMaxBytes = 500_000;
16674
16747
  const pendingFileReads = new Map();
16675
- const readFile = (applicationId, uri, forceReload) => {
16748
+ const getFileStatFingerprint = stat => {
16749
+ if (!stat || typeof stat !== 'object' || !Number.isFinite(stat.size)) {
16750
+ return '';
16751
+ }
16752
+ const modifiedTime = stat.mtimeMs ?? stat.mtime;
16753
+ if (typeof modifiedTime !== 'number' && typeof modifiedTime !== 'string') {
16754
+ return '';
16755
+ }
16756
+ const fingerprint = [stat.type, stat.size, modifiedTime];
16757
+ const changedTime = stat.ctimeMs ?? stat.ctime;
16758
+ if (typeof changedTime === 'number' || typeof changedTime === 'string') {
16759
+ fingerprint.push(changedTime);
16760
+ }
16761
+ if (typeof stat.etag === 'string') {
16762
+ fingerprint.push(stat.etag);
16763
+ }
16764
+ return JSON.stringify(fingerprint);
16765
+ };
16766
+ const isExcludedFromFileCache = uri => {
16767
+ const path = uri.split(/[?#]/, 1)[0];
16768
+ const fileName = path.slice(path.lastIndexOf('/') + 1);
16769
+ return fileName === '.env' || fileName.startsWith('.env.');
16770
+ };
16771
+ const removeCachedEditorFile = (applicationId, uri) => {
16772
+ void invoke$9(undefined, 'CacheStorage.removeEditorFileCache', applicationId || '', uri).catch(() => {});
16773
+ };
16774
+ const readFileWithCache = async (applicationId, uri, forceReload, useCache) => {
16775
+ if (!useCache) {
16776
+ return readFile$1(applicationId, uri);
16777
+ }
16676
16778
  if (forceReload) {
16779
+ removeCachedEditorFile(applicationId, uri);
16677
16780
  return readFile$1(applicationId, uri);
16678
16781
  }
16782
+ if (isExcludedFromFileCache(uri)) {
16783
+ removeCachedEditorFile(applicationId, uri);
16784
+ return readFile$1(applicationId, uri);
16785
+ }
16786
+ let fingerprint = '';
16787
+ try {
16788
+ const stat = await invoke$9(applicationId, 'FileSystem.statWithMetadata', uri);
16789
+ if (stat?.size <= editorFileCacheMaxBytes) {
16790
+ fingerprint = getFileStatFingerprint(stat);
16791
+ }
16792
+ } catch {
16793
+ // Filesystems without stat metadata continue to use normal reads.
16794
+ }
16795
+ if (!fingerprint) {
16796
+ removeCachedEditorFile(applicationId, uri);
16797
+ }
16798
+ if (fingerprint) {
16799
+ try {
16800
+ const cached = await invoke$9(undefined, 'CacheStorage.getEditorFileCache', applicationId || '', uri, fingerprint);
16801
+ if (typeof cached === 'string') {
16802
+ return cached;
16803
+ }
16804
+ } catch {
16805
+ // Cache Storage failures must not prevent opening a file.
16806
+ }
16807
+ }
16808
+ const content = await readFile$1(applicationId, uri);
16809
+ if (fingerprint && new TextEncoder().encode(content).byteLength <= editorFileCacheMaxBytes) {
16810
+ void invoke$9(undefined, 'CacheStorage.setEditorFileCache', applicationId || '', uri, fingerprint, content).catch(() => {});
16811
+ }
16812
+ return content;
16813
+ };
16814
+ const readFile = (applicationId, uri, forceReload, useCache) => {
16815
+ if (forceReload) {
16816
+ return readFileWithCache(applicationId, uri, forceReload, useCache);
16817
+ }
16679
16818
  let applicationReads = pendingFileReads.get(applicationId);
16680
16819
  if (!applicationReads) {
16681
16820
  applicationReads = new Map();
@@ -16697,7 +16836,7 @@ const readFile = (applicationId, uri, forceReload) => {
16697
16836
  };
16698
16837
  fileRead = (async () => {
16699
16838
  try {
16700
- return await readFile$1(applicationId, uri);
16839
+ return await readFileWithCache(applicationId, uri, forceReload, useCache);
16701
16840
  } finally {
16702
16841
  removePendingRead();
16703
16842
  }
@@ -16856,7 +16995,7 @@ const loadContent = async (state, savedState, largeFile = false, focus = true, f
16856
16995
  let endOfLine = existingEditor?.endOfLine || 'lf';
16857
16996
  try {
16858
16997
  if (!existingEditor) {
16859
- content = await readFile(state.applicationId, uri, forceReload);
16998
+ content = await readFile(state.applicationId, uri, forceReload, state.editorFileCacheEnabled === true);
16860
16999
  endOfLine = getEndOfLine(content);
16861
17000
  content = normalizeLineEndings(content);
16862
17001
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/editor-worker",
3
- "version": "19.72.3",
3
+ "version": "19.72.5",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git@github.com:lvce-editor/editor-worker.git"