@lvce-editor/editor-worker 19.71.1 → 19.71.2
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/editorWorkerMain.js +346 -343
- package/package.json +1 -1
package/dist/editorWorkerMain.js
CHANGED
|
@@ -7155,112 +7155,6 @@ const applyEdit = async (editor, changes, selectionChanges) => {
|
|
|
7155
7155
|
return scheduleDocumentAndCursorsSelections(editor, changes, selectionChanges);
|
|
7156
7156
|
};
|
|
7157
7157
|
|
|
7158
|
-
// TODO maybe use a separate worker for bulk edits and bulk edit history
|
|
7159
|
-
|
|
7160
|
-
const sortEditsDescending = edits => {
|
|
7161
|
-
return edits.toSorted((a, b) => b.offset - a.offset);
|
|
7162
|
-
};
|
|
7163
|
-
const applyEditsToText = (text, edits) => {
|
|
7164
|
-
let newText = text;
|
|
7165
|
-
for (const edit of sortEditsDescending(edits)) {
|
|
7166
|
-
newText = newText.slice(0, edit.offset) + edit.inserted + newText.slice(edit.offset + edit.deleted);
|
|
7167
|
-
}
|
|
7168
|
-
return newText;
|
|
7169
|
-
};
|
|
7170
|
-
const getTextChanges = (editor, edits) => {
|
|
7171
|
-
const textChanges = [];
|
|
7172
|
-
for (const edit of sortEditsDescending(edits)) {
|
|
7173
|
-
const startPosition = positionAt(editor, edit.offset);
|
|
7174
|
-
const endPosition = positionAt(editor, edit.offset + edit.deleted);
|
|
7175
|
-
const deleted = getSelectionText(editor, {
|
|
7176
|
-
end: endPosition,
|
|
7177
|
-
start: startPosition
|
|
7178
|
-
});
|
|
7179
|
-
const textChange = {
|
|
7180
|
-
deleted,
|
|
7181
|
-
end: endPosition,
|
|
7182
|
-
inserted: [edit.inserted],
|
|
7183
|
-
origin: Rename,
|
|
7184
|
-
start: startPosition
|
|
7185
|
-
};
|
|
7186
|
-
textChanges.push(textChange);
|
|
7187
|
-
}
|
|
7188
|
-
return textChanges;
|
|
7189
|
-
};
|
|
7190
|
-
const groupEditsByUri = changes => {
|
|
7191
|
-
const editsByUri = new Map();
|
|
7192
|
-
for (const change of changes) {
|
|
7193
|
-
const edits = editsByUri.get(change.uri);
|
|
7194
|
-
if (edits) {
|
|
7195
|
-
edits.push(...change.edits);
|
|
7196
|
-
} else {
|
|
7197
|
-
editsByUri.set(change.uri, [...change.edits]);
|
|
7198
|
-
}
|
|
7199
|
-
}
|
|
7200
|
-
return editsByUri;
|
|
7201
|
-
};
|
|
7202
|
-
const getOpenEditor = (currentEditor, uri) => {
|
|
7203
|
-
if (currentEditor.uri === uri) {
|
|
7204
|
-
return currentEditor;
|
|
7205
|
-
}
|
|
7206
|
-
for (const key of getKeys$2()) {
|
|
7207
|
-
const editor = get$8(Number(key))?.newState;
|
|
7208
|
-
if (editor && !editor.initial && editor.uri === uri && editor.applicationId === currentEditor.applicationId) {
|
|
7209
|
-
return editor;
|
|
7210
|
-
}
|
|
7211
|
-
}
|
|
7212
|
-
return undefined;
|
|
7213
|
-
};
|
|
7214
|
-
const applyWorkspaceEdit = async (editor, changes) => {
|
|
7215
|
-
object(editor);
|
|
7216
|
-
array(changes);
|
|
7217
|
-
let currentEditor = editor;
|
|
7218
|
-
const editsByUri = groupEditsByUri(changes);
|
|
7219
|
-
for (const [uri, edits] of editsByUri) {
|
|
7220
|
-
const openEditor = getOpenEditor(currentEditor, uri);
|
|
7221
|
-
if (openEditor) {
|
|
7222
|
-
const textChanges = getTextChanges(openEditor, edits);
|
|
7223
|
-
const updatedEditor = await scheduleDocumentAndCursorsSelections(openEditor, textChanges);
|
|
7224
|
-
if (openEditor.uid === currentEditor.uid) {
|
|
7225
|
-
currentEditor = updatedEditor;
|
|
7226
|
-
}
|
|
7227
|
-
continue;
|
|
7228
|
-
}
|
|
7229
|
-
const text = await readFile(editor.applicationId, uri);
|
|
7230
|
-
const newText = applyEditsToText(text, edits);
|
|
7231
|
-
await invoke$9(editor.applicationId, 'FileSystem.writeFile', uri, newText);
|
|
7232
|
-
}
|
|
7233
|
-
return currentEditor;
|
|
7234
|
-
};
|
|
7235
|
-
|
|
7236
|
-
const isPersistentWidget = widgetId => {
|
|
7237
|
-
switch (widgetId) {
|
|
7238
|
-
case Find:
|
|
7239
|
-
return true;
|
|
7240
|
-
default:
|
|
7241
|
-
return false;
|
|
7242
|
-
}
|
|
7243
|
-
};
|
|
7244
|
-
|
|
7245
|
-
// TODO widgets should have a persistence property:
|
|
7246
|
-
// 1 = close by click (e.g. completion, hover, source-actions)
|
|
7247
|
-
// 2 = stay open on click (e.g. find)
|
|
7248
|
-
const closeWidgetsMaybe = widgets => {
|
|
7249
|
-
if (widgets.length === 0) {
|
|
7250
|
-
return widgets;
|
|
7251
|
-
}
|
|
7252
|
-
return widgets.filter(widget => isPersistentWidget(widget.id));
|
|
7253
|
-
};
|
|
7254
|
-
|
|
7255
|
-
const hasWidget = (widgets, id) => {
|
|
7256
|
-
for (const widget of widgets) {
|
|
7257
|
-
if (widget.id === id) {
|
|
7258
|
-
return true;
|
|
7259
|
-
}
|
|
7260
|
-
}
|
|
7261
|
-
return false;
|
|
7262
|
-
};
|
|
7263
|
-
|
|
7264
7158
|
const getFormattingEdits = async editor => {
|
|
7265
7159
|
if (editor.largeFile) {
|
|
7266
7160
|
return [];
|
|
@@ -7636,91 +7530,362 @@ const showFilePicker = async platform => {
|
|
|
7636
7530
|
if (canceled) {
|
|
7637
7531
|
return '';
|
|
7638
7532
|
}
|
|
7639
|
-
return filePath;
|
|
7533
|
+
return filePath;
|
|
7534
|
+
};
|
|
7535
|
+
|
|
7536
|
+
const saveUntitledFile = async (uri, content, platform, applicationId) => {
|
|
7537
|
+
const filePath = await showFilePicker(platform);
|
|
7538
|
+
if (!filePath) {
|
|
7539
|
+
return;
|
|
7540
|
+
}
|
|
7541
|
+
await invoke$9(applicationId, 'FileSystem.writeFile', filePath, content);
|
|
7542
|
+
await invoke$9(applicationId, 'Layout.handleWorkspaceRefresh');
|
|
7543
|
+
return filePath;
|
|
7544
|
+
};
|
|
7545
|
+
|
|
7546
|
+
const isPermissionDeniedError = error => {
|
|
7547
|
+
const errorCode = 'code' in error ? error.code : undefined;
|
|
7548
|
+
return errorCode === 'EACCES' || error.message.includes('EACCES:');
|
|
7549
|
+
};
|
|
7550
|
+
const showSaveErrorDialog = async error => {
|
|
7551
|
+
if (isPermissionDeniedError(error)) {
|
|
7552
|
+
await invoke$j('ElectronDialog.showMessageBox', {
|
|
7553
|
+
buttons: ['OK'],
|
|
7554
|
+
defaultId: 0,
|
|
7555
|
+
message: "You don't have permission to save changes to this file.",
|
|
7556
|
+
title: 'Unable to Save File',
|
|
7557
|
+
type: 'error'
|
|
7558
|
+
});
|
|
7559
|
+
return;
|
|
7560
|
+
}
|
|
7561
|
+
await invoke$j('ElectronDialog.showMessageBox', {
|
|
7562
|
+
buttons: ['OK'],
|
|
7563
|
+
defaultId: 0,
|
|
7564
|
+
detail: error.message,
|
|
7565
|
+
message: 'Saving the file failed.',
|
|
7566
|
+
title: 'Failed to Save File',
|
|
7567
|
+
type: 'error'
|
|
7568
|
+
});
|
|
7569
|
+
};
|
|
7570
|
+
|
|
7571
|
+
const save$1 = async (editor, skipFormatting = false) => {
|
|
7572
|
+
try {
|
|
7573
|
+
const {
|
|
7574
|
+
applicationId,
|
|
7575
|
+
platform,
|
|
7576
|
+
uri
|
|
7577
|
+
} = editor;
|
|
7578
|
+
if (!isUntitledFile(uri) && (await isReadonlyFile(uri, applicationId))) {
|
|
7579
|
+
return editor;
|
|
7580
|
+
}
|
|
7581
|
+
const newEditor = await getNewEditor(editor, skipFormatting);
|
|
7582
|
+
const content = applyLineEndings(getText$1(newEditor), newEditor.endOfLine);
|
|
7583
|
+
if (isUntitledFile(uri)) {
|
|
7584
|
+
const pickedFilePath = await saveUntitledFile(uri, content, platform, applicationId);
|
|
7585
|
+
if (pickedFilePath) {
|
|
7586
|
+
if (newEditor.modified) {
|
|
7587
|
+
await notifyTabModifiedStatusChange(uri, false, applicationId);
|
|
7588
|
+
}
|
|
7589
|
+
return {
|
|
7590
|
+
...newEditor,
|
|
7591
|
+
modified: false,
|
|
7592
|
+
uri: pickedFilePath
|
|
7593
|
+
};
|
|
7594
|
+
}
|
|
7595
|
+
return newEditor;
|
|
7596
|
+
}
|
|
7597
|
+
await saveNormalFile(uri, content, applicationId);
|
|
7598
|
+
if (newEditor.modified) {
|
|
7599
|
+
await notifyTabModifiedStatusChange(uri, false, applicationId);
|
|
7600
|
+
}
|
|
7601
|
+
return {
|
|
7602
|
+
...newEditor,
|
|
7603
|
+
modified: false
|
|
7604
|
+
};
|
|
7605
|
+
} catch (error) {
|
|
7606
|
+
// @ts-ignore
|
|
7607
|
+
const betterError = new VError(error, `Failed to save file "${editor.uri}"`);
|
|
7608
|
+
await handleError$1(betterError);
|
|
7609
|
+
if (editor.platform === Electron) {
|
|
7610
|
+
try {
|
|
7611
|
+
await showSaveErrorDialog(betterError);
|
|
7612
|
+
} catch (dialogError) {
|
|
7613
|
+
await handleError$1(dialogError);
|
|
7614
|
+
}
|
|
7615
|
+
}
|
|
7616
|
+
return editor;
|
|
7617
|
+
}
|
|
7618
|
+
};
|
|
7619
|
+
|
|
7620
|
+
const editorDiagnosticEffect = {
|
|
7621
|
+
// TODO set effects delay / diagnostic delay
|
|
7622
|
+
apply(editor) {
|
|
7623
|
+
return updateDiagnostics(editor);
|
|
7624
|
+
},
|
|
7625
|
+
isActive: (oldEditor, newEditor) => !oldEditor.initial && !newEditor.loadError && newEditor.diagnosticsEnabled && (oldEditor.lines !== newEditor.lines || oldEditor.languageId !== newEditor.languageId)
|
|
7626
|
+
};
|
|
7627
|
+
|
|
7628
|
+
const cursorUndoLimit = 100;
|
|
7629
|
+
const selectionsEqual = (left, right) => {
|
|
7630
|
+
if (left === right) {
|
|
7631
|
+
return true;
|
|
7632
|
+
}
|
|
7633
|
+
if (left.length !== right.length) {
|
|
7634
|
+
return false;
|
|
7635
|
+
}
|
|
7636
|
+
for (let i = 0; i < left.length; i++) {
|
|
7637
|
+
if (left[i] !== right[i]) {
|
|
7638
|
+
return false;
|
|
7639
|
+
}
|
|
7640
|
+
}
|
|
7641
|
+
return true;
|
|
7642
|
+
};
|
|
7643
|
+
const saveAfterDelay = async (uid, token) => {
|
|
7644
|
+
if (!get$8(uid)) {
|
|
7645
|
+
consume(uid, token);
|
|
7646
|
+
return;
|
|
7647
|
+
}
|
|
7648
|
+
let didSave = false;
|
|
7649
|
+
const save = wrapCommand$1(async editor => {
|
|
7650
|
+
if (!isLatest(uid, token)) {
|
|
7651
|
+
return editor;
|
|
7652
|
+
}
|
|
7653
|
+
consume(uid, token);
|
|
7654
|
+
const autoSave = await get$3('files.autoSave');
|
|
7655
|
+
if (autoSave !== 'afterDelay') {
|
|
7656
|
+
return editor;
|
|
7657
|
+
}
|
|
7658
|
+
const savedEditor = await save$1(editor);
|
|
7659
|
+
didSave = savedEditor !== editor;
|
|
7660
|
+
return savedEditor;
|
|
7661
|
+
});
|
|
7662
|
+
await save(uid);
|
|
7663
|
+
if (didSave) {
|
|
7664
|
+
await invoke$d('Editor.renderPending', uid);
|
|
7665
|
+
}
|
|
7666
|
+
};
|
|
7667
|
+
|
|
7668
|
+
// TODO wrap commands globally, not per editor
|
|
7669
|
+
// TODO only store editor state in editor worker, not in renderer worker also
|
|
7670
|
+
|
|
7671
|
+
const wrapCommand$1 = (fn, preservesTypingCoalescing = false, returnState = true) => async (uid, ...args) => {
|
|
7672
|
+
return enqueue(uid, async () => {
|
|
7673
|
+
const oldInstance = get$8(uid);
|
|
7674
|
+
if (!oldInstance) {
|
|
7675
|
+
return undefined;
|
|
7676
|
+
}
|
|
7677
|
+
const state = oldInstance.newState;
|
|
7678
|
+
const {
|
|
7679
|
+
cursorUndoStack,
|
|
7680
|
+
endOfLine,
|
|
7681
|
+
initial,
|
|
7682
|
+
insertSpaces,
|
|
7683
|
+
isSelecting,
|
|
7684
|
+
lines,
|
|
7685
|
+
modified,
|
|
7686
|
+
redoStack,
|
|
7687
|
+
selections,
|
|
7688
|
+
undoStack,
|
|
7689
|
+
uri
|
|
7690
|
+
} = state;
|
|
7691
|
+
const commandResult = await fn(state, ...args);
|
|
7692
|
+
let newEditor = !preservesTypingCoalescing && commandResult.canCoalesceTyping ? {
|
|
7693
|
+
...commandResult,
|
|
7694
|
+
canCoalesceTyping: false
|
|
7695
|
+
} : commandResult;
|
|
7696
|
+
if (lines !== newEditor.lines && newEditor.cursorUndoStack?.length) {
|
|
7697
|
+
newEditor = {
|
|
7698
|
+
...newEditor,
|
|
7699
|
+
cursorUndoStack: []
|
|
7700
|
+
};
|
|
7701
|
+
} else if (selections && newEditor.selections && !isSelecting && newEditor.cursorUndoStack === cursorUndoStack && (!selectionsEqual(selections, newEditor.selections) || newEditor.isSelecting)) {
|
|
7702
|
+
const previousCursorUndoStack = cursorUndoStack || [];
|
|
7703
|
+
newEditor = {
|
|
7704
|
+
...newEditor,
|
|
7705
|
+
cursorUndoStack: [...previousCursorUndoStack.slice(1 - cursorUndoLimit), new Uint32Array(selections)]
|
|
7706
|
+
};
|
|
7707
|
+
}
|
|
7708
|
+
if (state === newEditor) {
|
|
7709
|
+
return returnState ? newEditor : undefined;
|
|
7710
|
+
}
|
|
7711
|
+
const newEditorWithDerivedState = await updateDerivedState(state, newEditor);
|
|
7712
|
+
set$a(uid, state, newEditorWithDerivedState);
|
|
7713
|
+
await dispose$3();
|
|
7714
|
+
if (editorDiagnosticEffect.isActive(state, newEditorWithDerivedState)) {
|
|
7715
|
+
void editorDiagnosticEffect.apply(newEditorWithDerivedState);
|
|
7716
|
+
}
|
|
7717
|
+
const finalEditor = newEditorWithDerivedState;
|
|
7718
|
+
await notifyEditorStatusChange(state, finalEditor);
|
|
7719
|
+
if (!initial && uri === finalEditor.uri && (endOfLine !== finalEditor.endOfLine || insertSpaces !== finalEditor.insertSpaces || lines !== finalEditor.lines || modified !== finalEditor.modified || redoStack !== finalEditor.redoStack || undoStack !== finalEditor.undoStack)) {
|
|
7720
|
+
for (const key of getKeys$2()) {
|
|
7721
|
+
const otherUid = Number(key);
|
|
7722
|
+
const instance = get$8(otherUid);
|
|
7723
|
+
const editor = instance?.newState;
|
|
7724
|
+
if (otherUid === uid || !instance || !editor || editor.initial || editor.uri !== finalEditor.uri || editor.applicationId !== finalEditor.applicationId) {
|
|
7725
|
+
continue;
|
|
7726
|
+
}
|
|
7727
|
+
const synchronizedEditor = await updateDerivedState(editor, {
|
|
7728
|
+
...editor,
|
|
7729
|
+
decorations: finalEditor.decorations,
|
|
7730
|
+
diagnostics: finalEditor.diagnostics,
|
|
7731
|
+
endOfLine: finalEditor.endOfLine,
|
|
7732
|
+
incrementalEdits: emptyIncrementalEdits,
|
|
7733
|
+
insertSpaces: finalEditor.insertSpaces,
|
|
7734
|
+
invalidStartIndex: Math.min(editor.invalidStartIndex, finalEditor.invalidStartIndex),
|
|
7735
|
+
lines: finalEditor.lines,
|
|
7736
|
+
modified: finalEditor.modified,
|
|
7737
|
+
redoStack: finalEditor.redoStack,
|
|
7738
|
+
undoStack: finalEditor.undoStack,
|
|
7739
|
+
visualDecorations: finalEditor.visualDecorations
|
|
7740
|
+
});
|
|
7741
|
+
set$a(otherUid, instance.oldState, synchronizedEditor);
|
|
7742
|
+
if (editorDiagnosticEffect.isActive(editor, synchronizedEditor)) {
|
|
7743
|
+
void editorDiagnosticEffect.apply(synchronizedEditor);
|
|
7744
|
+
}
|
|
7745
|
+
}
|
|
7746
|
+
}
|
|
7747
|
+
if (lines !== finalEditor.lines && !isUntitledFile(finalEditor.uri)) {
|
|
7748
|
+
schedule(uid, token => saveAfterDelay(uid, token));
|
|
7749
|
+
} else if (modified && !finalEditor.modified) {
|
|
7750
|
+
dispose$4(uid);
|
|
7751
|
+
}
|
|
7752
|
+
return returnState ? finalEditor : undefined;
|
|
7753
|
+
});
|
|
7754
|
+
};
|
|
7755
|
+
const wrapFocusCommand$1 = (fn, returnState = true) => {
|
|
7756
|
+
const command = wrapCommand$1((editor, widgetRevision) => {
|
|
7757
|
+
if (editor.widgetRevision !== widgetRevision && editor.focus !== FocusEditorText$1) {
|
|
7758
|
+
return editor;
|
|
7759
|
+
}
|
|
7760
|
+
return fn(editor);
|
|
7761
|
+
}, false, returnState);
|
|
7762
|
+
return uid => {
|
|
7763
|
+
// DOM focus events can arrive while a queued command is still opening a widget.
|
|
7764
|
+
const widgetRevision = get$8(uid)?.newState.widgetRevision;
|
|
7765
|
+
return command(uid, widgetRevision);
|
|
7766
|
+
};
|
|
7767
|
+
};
|
|
7768
|
+
|
|
7769
|
+
// Optional provider work must not hold the editing queue while another worker responds.
|
|
7770
|
+
const wrapDeferredCommand$1 = (fn, returnState = true) => {
|
|
7771
|
+
const apply = wrapCommand$1((editor, snapshot, result) => editor === snapshot ? result : editor, false, returnState);
|
|
7772
|
+
return async (uid, ...args) => {
|
|
7773
|
+
const snapshot = await enqueue(uid, async () => get$8(uid)?.newState);
|
|
7774
|
+
if (!snapshot) {
|
|
7775
|
+
return undefined;
|
|
7776
|
+
}
|
|
7777
|
+
const result = await fn(snapshot, ...args);
|
|
7778
|
+
return apply(uid, snapshot, result);
|
|
7779
|
+
};
|
|
7780
|
+
};
|
|
7781
|
+
|
|
7782
|
+
// TODO maybe use a separate worker for bulk edits and bulk edit history
|
|
7783
|
+
|
|
7784
|
+
const sortEditsDescending = edits => {
|
|
7785
|
+
return edits.toSorted((a, b) => b.offset - a.offset);
|
|
7786
|
+
};
|
|
7787
|
+
const applyEditsToText = (text, edits) => {
|
|
7788
|
+
let newText = text;
|
|
7789
|
+
for (const edit of sortEditsDescending(edits)) {
|
|
7790
|
+
newText = newText.slice(0, edit.offset) + edit.inserted + newText.slice(edit.offset + edit.deleted);
|
|
7791
|
+
}
|
|
7792
|
+
return newText;
|
|
7793
|
+
};
|
|
7794
|
+
const getTextChanges = (editor, edits) => {
|
|
7795
|
+
const textChanges = [];
|
|
7796
|
+
for (const edit of sortEditsDescending(edits)) {
|
|
7797
|
+
const startPosition = positionAt(editor, edit.offset);
|
|
7798
|
+
const endPosition = positionAt(editor, edit.offset + edit.deleted);
|
|
7799
|
+
const deleted = getSelectionText(editor, {
|
|
7800
|
+
end: endPosition,
|
|
7801
|
+
start: startPosition
|
|
7802
|
+
});
|
|
7803
|
+
const textChange = {
|
|
7804
|
+
deleted,
|
|
7805
|
+
end: endPosition,
|
|
7806
|
+
inserted: [edit.inserted],
|
|
7807
|
+
origin: Rename,
|
|
7808
|
+
start: startPosition
|
|
7809
|
+
};
|
|
7810
|
+
textChanges.push(textChange);
|
|
7811
|
+
}
|
|
7812
|
+
return textChanges;
|
|
7813
|
+
};
|
|
7814
|
+
const groupEditsByUri = changes => {
|
|
7815
|
+
const editsByUri = new Map();
|
|
7816
|
+
for (const change of changes) {
|
|
7817
|
+
const edits = editsByUri.get(change.uri);
|
|
7818
|
+
if (edits) {
|
|
7819
|
+
edits.push(...change.edits);
|
|
7820
|
+
} else {
|
|
7821
|
+
editsByUri.set(change.uri, [...change.edits]);
|
|
7822
|
+
}
|
|
7823
|
+
}
|
|
7824
|
+
return editsByUri;
|
|
7825
|
+
};
|
|
7826
|
+
const getOpenEditor = (currentEditor, uri) => {
|
|
7827
|
+
if (currentEditor.uri === uri) {
|
|
7828
|
+
return currentEditor;
|
|
7829
|
+
}
|
|
7830
|
+
for (const key of getKeys$2()) {
|
|
7831
|
+
const editor = get$8(Number(key))?.newState;
|
|
7832
|
+
if (editor && !editor.initial && editor.uri === uri && editor.applicationId === currentEditor.applicationId) {
|
|
7833
|
+
return editor;
|
|
7834
|
+
}
|
|
7835
|
+
}
|
|
7836
|
+
return undefined;
|
|
7837
|
+
};
|
|
7838
|
+
const updateOpenEditor = wrapCommand$1(scheduleDocumentAndCursorsSelections);
|
|
7839
|
+
const applyWorkspaceEdit = async (editor, changes) => {
|
|
7840
|
+
object(editor);
|
|
7841
|
+
array(changes);
|
|
7842
|
+
let currentEditor = editor;
|
|
7843
|
+
const editsByUri = groupEditsByUri(changes);
|
|
7844
|
+
for (const [uri, edits] of editsByUri) {
|
|
7845
|
+
const openEditor = getOpenEditor(currentEditor, uri);
|
|
7846
|
+
if (openEditor) {
|
|
7847
|
+
const textChanges = getTextChanges(openEditor, edits);
|
|
7848
|
+
if (openEditor.uid === currentEditor.uid) {
|
|
7849
|
+
currentEditor = await scheduleDocumentAndCursorsSelections(openEditor, textChanges);
|
|
7850
|
+
} else {
|
|
7851
|
+
await updateOpenEditor(openEditor.uid, textChanges);
|
|
7852
|
+
await invoke$5('Editor.renderPending', openEditor.uid);
|
|
7853
|
+
}
|
|
7854
|
+
continue;
|
|
7855
|
+
}
|
|
7856
|
+
const text = await readFile(editor.applicationId, uri);
|
|
7857
|
+
const newText = applyEditsToText(text, edits);
|
|
7858
|
+
await invoke$9(editor.applicationId, 'FileSystem.writeFile', uri, newText);
|
|
7859
|
+
}
|
|
7860
|
+
return currentEditor;
|
|
7640
7861
|
};
|
|
7641
7862
|
|
|
7642
|
-
const
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7863
|
+
const isPersistentWidget = widgetId => {
|
|
7864
|
+
switch (widgetId) {
|
|
7865
|
+
case Find:
|
|
7866
|
+
return true;
|
|
7867
|
+
default:
|
|
7868
|
+
return false;
|
|
7646
7869
|
}
|
|
7647
|
-
await invoke$9(applicationId, 'FileSystem.writeFile', filePath, content);
|
|
7648
|
-
await invoke$9(applicationId, 'Layout.handleWorkspaceRefresh');
|
|
7649
|
-
return filePath;
|
|
7650
7870
|
};
|
|
7651
7871
|
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
await invoke$j('ElectronDialog.showMessageBox', {
|
|
7659
|
-
buttons: ['OK'],
|
|
7660
|
-
defaultId: 0,
|
|
7661
|
-
message: "You don't have permission to save changes to this file.",
|
|
7662
|
-
title: 'Unable to Save File',
|
|
7663
|
-
type: 'error'
|
|
7664
|
-
});
|
|
7665
|
-
return;
|
|
7872
|
+
// TODO widgets should have a persistence property:
|
|
7873
|
+
// 1 = close by click (e.g. completion, hover, source-actions)
|
|
7874
|
+
// 2 = stay open on click (e.g. find)
|
|
7875
|
+
const closeWidgetsMaybe = widgets => {
|
|
7876
|
+
if (widgets.length === 0) {
|
|
7877
|
+
return widgets;
|
|
7666
7878
|
}
|
|
7667
|
-
|
|
7668
|
-
buttons: ['OK'],
|
|
7669
|
-
defaultId: 0,
|
|
7670
|
-
detail: error.message,
|
|
7671
|
-
message: 'Saving the file failed.',
|
|
7672
|
-
title: 'Failed to Save File',
|
|
7673
|
-
type: 'error'
|
|
7674
|
-
});
|
|
7879
|
+
return widgets.filter(widget => isPersistentWidget(widget.id));
|
|
7675
7880
|
};
|
|
7676
7881
|
|
|
7677
|
-
const
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
platform,
|
|
7682
|
-
uri
|
|
7683
|
-
} = editor;
|
|
7684
|
-
if (!isUntitledFile(uri) && (await isReadonlyFile(uri, applicationId))) {
|
|
7685
|
-
return editor;
|
|
7686
|
-
}
|
|
7687
|
-
const newEditor = await getNewEditor(editor, skipFormatting);
|
|
7688
|
-
const content = applyLineEndings(getText$1(newEditor), newEditor.endOfLine);
|
|
7689
|
-
if (isUntitledFile(uri)) {
|
|
7690
|
-
const pickedFilePath = await saveUntitledFile(uri, content, platform, applicationId);
|
|
7691
|
-
if (pickedFilePath) {
|
|
7692
|
-
if (newEditor.modified) {
|
|
7693
|
-
await notifyTabModifiedStatusChange(uri, false, applicationId);
|
|
7694
|
-
}
|
|
7695
|
-
return {
|
|
7696
|
-
...newEditor,
|
|
7697
|
-
modified: false,
|
|
7698
|
-
uri: pickedFilePath
|
|
7699
|
-
};
|
|
7700
|
-
}
|
|
7701
|
-
return newEditor;
|
|
7702
|
-
}
|
|
7703
|
-
await saveNormalFile(uri, content, applicationId);
|
|
7704
|
-
if (newEditor.modified) {
|
|
7705
|
-
await notifyTabModifiedStatusChange(uri, false, applicationId);
|
|
7706
|
-
}
|
|
7707
|
-
return {
|
|
7708
|
-
...newEditor,
|
|
7709
|
-
modified: false
|
|
7710
|
-
};
|
|
7711
|
-
} catch (error) {
|
|
7712
|
-
// @ts-ignore
|
|
7713
|
-
const betterError = new VError(error, `Failed to save file "${editor.uri}"`);
|
|
7714
|
-
await handleError$1(betterError);
|
|
7715
|
-
if (editor.platform === Electron) {
|
|
7716
|
-
try {
|
|
7717
|
-
await showSaveErrorDialog(betterError);
|
|
7718
|
-
} catch (dialogError) {
|
|
7719
|
-
await handleError$1(dialogError);
|
|
7720
|
-
}
|
|
7882
|
+
const hasWidget = (widgets, id) => {
|
|
7883
|
+
for (const widget of widgets) {
|
|
7884
|
+
if (widget.id === id) {
|
|
7885
|
+
return true;
|
|
7721
7886
|
}
|
|
7722
|
-
return editor;
|
|
7723
7887
|
}
|
|
7888
|
+
return false;
|
|
7724
7889
|
};
|
|
7725
7890
|
|
|
7726
7891
|
const handleBlur$1 = async editor => {
|
|
@@ -18060,168 +18225,6 @@ const revealProblem = (editor, rowIndex, columnIndex) => {
|
|
|
18060
18225
|
};
|
|
18061
18226
|
};
|
|
18062
18227
|
|
|
18063
|
-
const editorDiagnosticEffect = {
|
|
18064
|
-
// TODO set effects delay / diagnostic delay
|
|
18065
|
-
apply(editor) {
|
|
18066
|
-
return updateDiagnostics(editor);
|
|
18067
|
-
},
|
|
18068
|
-
isActive: (oldEditor, newEditor) => !oldEditor.initial && !newEditor.loadError && newEditor.diagnosticsEnabled && (oldEditor.lines !== newEditor.lines || oldEditor.languageId !== newEditor.languageId)
|
|
18069
|
-
};
|
|
18070
|
-
|
|
18071
|
-
const cursorUndoLimit = 100;
|
|
18072
|
-
const selectionsEqual = (left, right) => {
|
|
18073
|
-
if (left === right) {
|
|
18074
|
-
return true;
|
|
18075
|
-
}
|
|
18076
|
-
if (left.length !== right.length) {
|
|
18077
|
-
return false;
|
|
18078
|
-
}
|
|
18079
|
-
for (let i = 0; i < left.length; i++) {
|
|
18080
|
-
if (left[i] !== right[i]) {
|
|
18081
|
-
return false;
|
|
18082
|
-
}
|
|
18083
|
-
}
|
|
18084
|
-
return true;
|
|
18085
|
-
};
|
|
18086
|
-
const saveAfterDelay = async (uid, token) => {
|
|
18087
|
-
if (!get$8(uid)) {
|
|
18088
|
-
consume(uid, token);
|
|
18089
|
-
return;
|
|
18090
|
-
}
|
|
18091
|
-
let didSave = false;
|
|
18092
|
-
const save = wrapCommand$1(async editor => {
|
|
18093
|
-
if (!isLatest(uid, token)) {
|
|
18094
|
-
return editor;
|
|
18095
|
-
}
|
|
18096
|
-
consume(uid, token);
|
|
18097
|
-
const autoSave = await get$3('files.autoSave');
|
|
18098
|
-
if (autoSave !== 'afterDelay') {
|
|
18099
|
-
return editor;
|
|
18100
|
-
}
|
|
18101
|
-
const savedEditor = await save$1(editor);
|
|
18102
|
-
didSave = savedEditor !== editor;
|
|
18103
|
-
return savedEditor;
|
|
18104
|
-
});
|
|
18105
|
-
await save(uid);
|
|
18106
|
-
if (didSave) {
|
|
18107
|
-
await invoke$d('Editor.renderPending', uid);
|
|
18108
|
-
}
|
|
18109
|
-
};
|
|
18110
|
-
|
|
18111
|
-
// TODO wrap commands globally, not per editor
|
|
18112
|
-
// TODO only store editor state in editor worker, not in renderer worker also
|
|
18113
|
-
|
|
18114
|
-
const wrapCommand$1 = (fn, preservesTypingCoalescing = false, returnState = true) => async (uid, ...args) => {
|
|
18115
|
-
return enqueue(uid, async () => {
|
|
18116
|
-
const oldInstance = get$8(uid);
|
|
18117
|
-
if (!oldInstance) {
|
|
18118
|
-
return undefined;
|
|
18119
|
-
}
|
|
18120
|
-
const state = oldInstance.newState;
|
|
18121
|
-
const {
|
|
18122
|
-
cursorUndoStack,
|
|
18123
|
-
endOfLine,
|
|
18124
|
-
initial,
|
|
18125
|
-
insertSpaces,
|
|
18126
|
-
isSelecting,
|
|
18127
|
-
lines,
|
|
18128
|
-
modified,
|
|
18129
|
-
redoStack,
|
|
18130
|
-
selections,
|
|
18131
|
-
undoStack,
|
|
18132
|
-
uri
|
|
18133
|
-
} = state;
|
|
18134
|
-
const commandResult = await fn(state, ...args);
|
|
18135
|
-
let newEditor = !preservesTypingCoalescing && commandResult.canCoalesceTyping ? {
|
|
18136
|
-
...commandResult,
|
|
18137
|
-
canCoalesceTyping: false
|
|
18138
|
-
} : commandResult;
|
|
18139
|
-
if (lines !== newEditor.lines && newEditor.cursorUndoStack?.length) {
|
|
18140
|
-
newEditor = {
|
|
18141
|
-
...newEditor,
|
|
18142
|
-
cursorUndoStack: []
|
|
18143
|
-
};
|
|
18144
|
-
} else if (selections && newEditor.selections && !isSelecting && newEditor.cursorUndoStack === cursorUndoStack && (!selectionsEqual(selections, newEditor.selections) || newEditor.isSelecting)) {
|
|
18145
|
-
const previousCursorUndoStack = cursorUndoStack || [];
|
|
18146
|
-
newEditor = {
|
|
18147
|
-
...newEditor,
|
|
18148
|
-
cursorUndoStack: [...previousCursorUndoStack.slice(1 - cursorUndoLimit), new Uint32Array(selections)]
|
|
18149
|
-
};
|
|
18150
|
-
}
|
|
18151
|
-
if (state === newEditor) {
|
|
18152
|
-
return returnState ? newEditor : undefined;
|
|
18153
|
-
}
|
|
18154
|
-
const newEditorWithDerivedState = await updateDerivedState(state, newEditor);
|
|
18155
|
-
set$a(uid, state, newEditorWithDerivedState);
|
|
18156
|
-
await dispose$3();
|
|
18157
|
-
if (editorDiagnosticEffect.isActive(state, newEditorWithDerivedState)) {
|
|
18158
|
-
void editorDiagnosticEffect.apply(newEditorWithDerivedState);
|
|
18159
|
-
}
|
|
18160
|
-
const finalEditor = newEditorWithDerivedState;
|
|
18161
|
-
await notifyEditorStatusChange(state, finalEditor);
|
|
18162
|
-
if (!initial && uri === finalEditor.uri && (endOfLine !== finalEditor.endOfLine || insertSpaces !== finalEditor.insertSpaces || lines !== finalEditor.lines || modified !== finalEditor.modified || redoStack !== finalEditor.redoStack || undoStack !== finalEditor.undoStack)) {
|
|
18163
|
-
for (const key of getKeys$2()) {
|
|
18164
|
-
const otherUid = Number(key);
|
|
18165
|
-
const instance = get$8(otherUid);
|
|
18166
|
-
const editor = instance?.newState;
|
|
18167
|
-
if (otherUid === uid || !instance || !editor || editor.initial || editor.uri !== finalEditor.uri || editor.applicationId !== finalEditor.applicationId) {
|
|
18168
|
-
continue;
|
|
18169
|
-
}
|
|
18170
|
-
const synchronizedEditor = await updateDerivedState(editor, {
|
|
18171
|
-
...editor,
|
|
18172
|
-
decorations: finalEditor.decorations,
|
|
18173
|
-
diagnostics: finalEditor.diagnostics,
|
|
18174
|
-
endOfLine: finalEditor.endOfLine,
|
|
18175
|
-
incrementalEdits: emptyIncrementalEdits,
|
|
18176
|
-
insertSpaces: finalEditor.insertSpaces,
|
|
18177
|
-
invalidStartIndex: Math.min(editor.invalidStartIndex, finalEditor.invalidStartIndex),
|
|
18178
|
-
lines: finalEditor.lines,
|
|
18179
|
-
modified: finalEditor.modified,
|
|
18180
|
-
redoStack: finalEditor.redoStack,
|
|
18181
|
-
undoStack: finalEditor.undoStack,
|
|
18182
|
-
visualDecorations: finalEditor.visualDecorations
|
|
18183
|
-
});
|
|
18184
|
-
set$a(otherUid, instance.oldState, synchronizedEditor);
|
|
18185
|
-
if (editorDiagnosticEffect.isActive(editor, synchronizedEditor)) {
|
|
18186
|
-
void editorDiagnosticEffect.apply(synchronizedEditor);
|
|
18187
|
-
}
|
|
18188
|
-
}
|
|
18189
|
-
}
|
|
18190
|
-
if (lines !== finalEditor.lines && !isUntitledFile(finalEditor.uri)) {
|
|
18191
|
-
schedule(uid, token => saveAfterDelay(uid, token));
|
|
18192
|
-
} else if (modified && !finalEditor.modified) {
|
|
18193
|
-
dispose$4(uid);
|
|
18194
|
-
}
|
|
18195
|
-
return returnState ? finalEditor : undefined;
|
|
18196
|
-
});
|
|
18197
|
-
};
|
|
18198
|
-
const wrapFocusCommand$1 = (fn, returnState = true) => {
|
|
18199
|
-
const command = wrapCommand$1((editor, widgetRevision) => {
|
|
18200
|
-
if (editor.widgetRevision !== widgetRevision && editor.focus !== FocusEditorText$1) {
|
|
18201
|
-
return editor;
|
|
18202
|
-
}
|
|
18203
|
-
return fn(editor);
|
|
18204
|
-
}, false, returnState);
|
|
18205
|
-
return uid => {
|
|
18206
|
-
// DOM focus events can arrive while a queued command is still opening a widget.
|
|
18207
|
-
const widgetRevision = get$8(uid)?.newState.widgetRevision;
|
|
18208
|
-
return command(uid, widgetRevision);
|
|
18209
|
-
};
|
|
18210
|
-
};
|
|
18211
|
-
|
|
18212
|
-
// Optional provider work must not hold the editing queue while another worker responds.
|
|
18213
|
-
const wrapDeferredCommand$1 = (fn, returnState = true) => {
|
|
18214
|
-
const apply = wrapCommand$1((editor, snapshot, result) => editor === snapshot ? result : editor, false, returnState);
|
|
18215
|
-
return async (uid, ...args) => {
|
|
18216
|
-
const snapshot = await enqueue(uid, async () => get$8(uid)?.newState);
|
|
18217
|
-
if (!snapshot) {
|
|
18218
|
-
return undefined;
|
|
18219
|
-
}
|
|
18220
|
-
const result = await fn(snapshot, ...args);
|
|
18221
|
-
return apply(uid, snapshot, result);
|
|
18222
|
-
};
|
|
18223
|
-
};
|
|
18224
|
-
|
|
18225
18228
|
const save = async (uid, skipFormatting = false) => {
|
|
18226
18229
|
let savedFrom;
|
|
18227
18230
|
const saveContent = wrapCommand$1(async editor => {
|