@adecore/editor-react 0.39.0 → 0.40.1
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/CallHierarchyPanel.js +30 -55
- package/dist/CodeAuthorsCard.js +0 -1
- package/dist/CompletionPopup.js +150 -181
- package/dist/DiffView.d.ts +1 -1
- package/dist/DiffView.js +2 -29
- package/dist/PickPopup.js +54 -80
- package/dist/SplitDiffView.js +27 -57
- package/dist/SymbolPicker.js +2 -8
- package/dist/code-actions-model.js +2 -9
- package/dist/code-actions.js +10 -11
- package/dist/code-vision.js +2 -1
- package/dist/completion-model.js +2 -2
- package/dist/completion.js +13 -34
- package/dist/definition-link.d.ts +1 -0
- package/dist/definition-link.js +22 -18
- package/dist/diagnostics-model.d.ts +1 -0
- package/dist/diagnostics-model.js +3 -1
- package/dist/diagnostics.js +1 -2
- package/dist/diff-syntax.d.ts +1 -0
- package/dist/diff-syntax.js +31 -0
- package/dist/doc-comment-model.d.ts +1 -0
- package/dist/doc-comment-model.js +1 -1
- package/dist/folding.js +2 -3
- package/dist/format-on-type.js +6 -10
- package/dist/hover-content.d.ts +0 -2
- package/dist/hover-content.js +1 -9
- package/dist/inlay-hints.d.ts +0 -1
- package/dist/inlay-hints.js +11 -41
- package/dist/navigation.js +4 -14
- package/dist/peek.js +2 -12
- package/dist/popup-focus.d.ts +3 -1
- package/dist/popup-focus.js +33 -0
- package/dist/recent-choices.d.ts +0 -1
- package/dist/recent-choices.js +0 -4
- package/dist/rendered-docs.d.ts +1 -0
- package/dist/rendered-docs.js +15 -28
- package/dist/snippet-field-transforms.d.ts +5 -0
- package/dist/snippet-field-transforms.js +27 -16
- package/dist/snippet-session.js +8 -20
- package/dist/symbol-links.js +3 -10
- package/dist/symbol-picker-model.d.ts +1 -0
- package/dist/symbol-picker-model.js +7 -0
- package/dist/unique.d.ts +10 -0
- package/dist/unique.js +15 -0
- package/package.json +9 -9
- package/src/AnchoredPopup.tsx +2 -0
- package/src/BaselineStatus.tsx +1 -0
- package/src/CallHierarchyPanel.tsx +16 -6
- package/src/ChangeReview.tsx +7 -0
- package/src/CodeAuthorsCard.tsx +2 -5
- package/src/CompletionPopup.tsx +21 -15
- package/src/DiffView.tsx +53 -30
- package/src/EditorContextMenu.tsx +7 -0
- package/src/EditorView.tsx +28 -0
- package/src/FindReplace.tsx +8 -0
- package/src/HoverCard.tsx +8 -0
- package/src/HoverSections.tsx +11 -0
- package/src/LanguagePopups.tsx +1 -0
- package/src/PanelResizeHandle.tsx +8 -0
- package/src/PathText.tsx +1 -0
- package/src/PeekPanel.tsx +13 -0
- package/src/PickPopup.tsx +7 -6
- package/src/RenameCard.tsx +13 -0
- package/src/RenderedDocs.tsx +11 -0
- package/src/SplitDiffView.tsx +91 -56
- package/src/SymbolPicker.tsx +10 -18
- package/src/call-hierarchy-model.ts +10 -0
- package/src/call-hierarchy.ts +82 -0
- package/src/code-actions-model.ts +21 -9
- package/src/code-actions.ts +83 -7
- package/src/code-authors.ts +20 -0
- package/src/code-vision-model.ts +37 -0
- package/src/code-vision.ts +47 -3
- package/src/completion-call.ts +19 -0
- package/src/completion-model.ts +58 -2
- package/src/completion.ts +156 -30
- package/src/conflict-model.ts +4 -0
- package/src/context-menu-rows.ts +1 -0
- package/src/context-menu.ts +7 -0
- package/src/definition-link.ts +42 -18
- package/src/diagnostics-model.ts +19 -1
- package/src/diagnostics.ts +31 -2
- package/src/diff-expansion.ts +9 -0
- package/src/diff-overlays.tsx +8 -0
- package/src/diff-syntax.ts +54 -0
- package/src/diff-wordmarks.ts +8 -0
- package/src/doc-comment-model.ts +51 -1
- package/src/editor-language.ts +11 -0
- package/src/find-query.ts +7 -0
- package/src/folding.ts +10 -3
- package/src/format-on-type.ts +23 -10
- package/src/highlight-layers.ts +3 -0
- package/src/highlights.ts +18 -0
- package/src/history.ts +11 -0
- package/src/holder.ts +3 -0
- package/src/hover-content.ts +34 -17
- package/src/hover.ts +57 -0
- package/src/index.ts +4 -0
- package/src/inlay-hints.ts +86 -47
- package/src/key-priority.ts +2 -0
- package/src/line-edits.ts +8 -0
- package/src/models.ts +6 -0
- package/src/navigation-history.ts +5 -0
- package/src/navigation.ts +28 -13
- package/src/panel-size.ts +7 -0
- package/src/patch-decorations.ts +39 -0
- package/src/patch-layout.ts +47 -0
- package/src/peek-model.ts +21 -0
- package/src/peek.ts +49 -13
- package/src/pick.ts +35 -0
- package/src/popup-focus.ts +11 -1
- package/src/popup-placement.ts +5 -0
- package/src/popups.ts +2 -6
- package/src/project-language.ts +33 -0
- package/src/project-problems.ts +11 -0
- package/src/proposal-model.ts +40 -0
- package/src/recent-choices.ts +3 -5
- package/src/refresher.ts +3 -0
- package/src/rename-model.ts +28 -0
- package/src/rename.ts +56 -0
- package/src/rendered-docs.ts +89 -19
- package/src/review-group.ts +4 -0
- package/src/row-host.ts +12 -0
- package/src/selection-ranges.ts +6 -0
- package/src/semantic-delta.ts +7 -0
- package/src/semantic-model.ts +11 -0
- package/src/semantic-tokens.ts +37 -0
- package/src/shortcut-keys.ts +3 -0
- package/src/signature-model.ts +7 -0
- package/src/signature.ts +27 -0
- package/src/snippet-field-transforms.ts +48 -13
- package/src/snippet-indent.ts +10 -0
- package/src/snippet-range-order.ts +5 -0
- package/src/snippet-session.ts +173 -31
- package/src/snippet-transform-client.ts +14 -0
- package/src/snippet-transform-format.ts +98 -0
- package/src/snippet-transform-protocol.ts +5 -0
- package/src/snippet-transform-queue.ts +53 -0
- package/src/snippet-transform-worker.ts +14 -0
- package/src/snippet-variables.ts +9 -0
- package/src/snippet.ts +107 -0
- package/src/split-alignment.ts +10 -0
- package/src/split-scroll.ts +8 -0
- package/src/symbol-links.ts +9 -12
- package/src/symbol-picker-model.ts +25 -0
- package/src/symbol-picker.ts +9 -0
- package/src/symbols.ts +21 -0
- package/src/testing.ts +7 -0
- package/src/timers.ts +5 -0
- package/src/unique.ts +23 -0
- package/src/use-problem-counts.ts +4 -0
- package/src/view-state.ts +9 -0
- package/src/word-diff.ts +5 -0
- package/src/workspace-edit.ts +84 -0
package/src/workspace-edit.ts
CHANGED
|
@@ -71,20 +71,25 @@ function refused(failureReason: string): ApplyWorkspaceEditResult {
|
|
|
71
71
|
/* The text edits of an edit per document, as the entries a document has in it, whatever else the edit does. */
|
|
72
72
|
export function textEntriesOf(edit: WorkspaceEdit): Map<string, TextEdit[][]> {
|
|
73
73
|
const entries = new Map<string, TextEdit[][]>();
|
|
74
|
+
|
|
74
75
|
const add = (uri: string, edits: TextEdit[]): void => {
|
|
75
76
|
entries.set(uri, [...(entries.get(uri) ?? []), edits]);
|
|
76
77
|
};
|
|
78
|
+
|
|
77
79
|
if (edit.documentChanges === undefined) {
|
|
78
80
|
for (const [uri, edits] of Object.entries(edit.changes ?? {})) {
|
|
79
81
|
add(uri, edits);
|
|
80
82
|
}
|
|
83
|
+
|
|
81
84
|
return entries;
|
|
82
85
|
}
|
|
86
|
+
|
|
83
87
|
for (const change of edit.documentChanges) {
|
|
84
88
|
if ('textDocument' in change) {
|
|
85
89
|
add(change.textDocument.uri, change.edits);
|
|
86
90
|
}
|
|
87
91
|
}
|
|
92
|
+
|
|
88
93
|
return entries;
|
|
89
94
|
}
|
|
90
95
|
|
|
@@ -101,12 +106,15 @@ export function renamesOf(edit: WorkspaceEdit): RenameFile[] {
|
|
|
101
106
|
/* Every file an edit makes, moves or deletes, in the order it says. */
|
|
102
107
|
export function resourceOperationsOf(edit: WorkspaceEdit): ResourceOperationView[] {
|
|
103
108
|
const operations: ResourceOperationView[] = [];
|
|
109
|
+
|
|
104
110
|
for (const change of edit.documentChanges ?? []) {
|
|
105
111
|
if ('textDocument' in change) {
|
|
106
112
|
continue;
|
|
107
113
|
}
|
|
114
|
+
|
|
108
115
|
operations.push(change.kind === 'rename' ? { kind: 'rename', uri: change.oldUri, newUri: change.newUri } : { kind: change.kind, uri: change.uri });
|
|
109
116
|
}
|
|
117
|
+
|
|
110
118
|
return operations;
|
|
111
119
|
}
|
|
112
120
|
|
|
@@ -125,15 +133,19 @@ interface Reads {
|
|
|
125
133
|
/* The resource operations a project has a way to carry out; pass it as the session's `resourceOperations` so servers only ask for what can be done. */
|
|
126
134
|
export function supportedResourceOperations(files: ProjectFiles | null | undefined): ResourceOperationKind[] {
|
|
127
135
|
const operations: ResourceOperationKind[] = [];
|
|
136
|
+
|
|
128
137
|
if (files?.create !== undefined) {
|
|
129
138
|
operations.push('create');
|
|
130
139
|
}
|
|
140
|
+
|
|
131
141
|
if (files?.rename !== undefined) {
|
|
132
142
|
operations.push('rename');
|
|
133
143
|
}
|
|
144
|
+
|
|
134
145
|
if (files?.delete !== undefined) {
|
|
135
146
|
operations.push('delete');
|
|
136
147
|
}
|
|
148
|
+
|
|
137
149
|
return operations;
|
|
138
150
|
}
|
|
139
151
|
|
|
@@ -144,8 +156,10 @@ function within(uri: string, folder: string): boolean {
|
|
|
144
156
|
/* Where a deleted URI stood before the renames that ran ahead of it, and what was moved into it: the places unsaved work can be. */
|
|
145
157
|
function placesOf(uri: string, renames: readonly RenameFile[]): string[] {
|
|
146
158
|
const found = new Set([uri]);
|
|
159
|
+
|
|
147
160
|
for (let i = renames.length - 1; i >= 0; i--) {
|
|
148
161
|
const { oldUri, newUri } = renames[i]!;
|
|
162
|
+
|
|
149
163
|
for (const place of [...found]) {
|
|
150
164
|
if (place === newUri || within(place, newUri)) {
|
|
151
165
|
found.add(oldUri + place.slice(newUri.length));
|
|
@@ -154,22 +168,28 @@ function placesOf(uri: string, renames: readonly RenameFile[]): string[] {
|
|
|
154
168
|
}
|
|
155
169
|
}
|
|
156
170
|
}
|
|
171
|
+
|
|
157
172
|
return [...found];
|
|
158
173
|
}
|
|
159
174
|
|
|
160
175
|
/* Whether deleting or replacing loses work nobody saved at any of the places. Without `isUnsaved` that is an editor on, or under, a place. A `recursive` one may be a folder. */
|
|
161
176
|
function losesWork(recursive: boolean, places: readonly string[], host: WorkspaceEditHost): boolean {
|
|
162
177
|
const files = host.files!;
|
|
178
|
+
|
|
163
179
|
if (files.isUnsaved !== undefined) {
|
|
164
180
|
return places.some((place) => {
|
|
165
181
|
const path = fileUriToPath(place);
|
|
182
|
+
|
|
166
183
|
return path !== null && files.isUnsaved!(path);
|
|
167
184
|
});
|
|
168
185
|
}
|
|
186
|
+
|
|
169
187
|
if (host.openUris === undefined && recursive) {
|
|
170
188
|
return true;
|
|
171
189
|
}
|
|
190
|
+
|
|
172
191
|
const open = host.openUris?.() ?? [];
|
|
192
|
+
|
|
173
193
|
return places.some((place) => host.editorOf(place) !== undefined || open.some((uri) => uri === place || within(uri, place)));
|
|
174
194
|
}
|
|
175
195
|
|
|
@@ -186,62 +206,81 @@ function overwriteProblem(
|
|
|
186
206
|
reads: Reads
|
|
187
207
|
): string | null {
|
|
188
208
|
const path = fileUriToPath(target)!;
|
|
209
|
+
|
|
189
210
|
if (host.files?.supportsOverwrite !== true) {
|
|
190
211
|
return `${path} already exists`;
|
|
191
212
|
}
|
|
213
|
+
|
|
192
214
|
// A target no text was read from may be a folder, with unsaved work anywhere under it.
|
|
193
215
|
const isText = step.kind === 'create' || reads.open.has(target) || reads.disks.has(target);
|
|
216
|
+
|
|
194
217
|
if (losesWork(!isText, places, host)) {
|
|
195
218
|
return `${path} has changes that are not saved`;
|
|
196
219
|
}
|
|
220
|
+
|
|
197
221
|
const editor = host.editorOf(target);
|
|
222
|
+
|
|
198
223
|
return editor !== undefined && step.kind === 'create' && readOnlyAt(host, target, editor) ? `${path} is read only` : null;
|
|
199
224
|
}
|
|
200
225
|
|
|
201
226
|
/* Checks a plan against what only the host can see: paths, overwrites, unsaved work and the editors it touches. Null when it fits. */
|
|
202
227
|
function problemWith(steps: readonly WorkspaceEditStep[], host: WorkspaceEditHost, reads: Reads): string | null {
|
|
203
228
|
const renames: RenameFile[] = [];
|
|
229
|
+
|
|
204
230
|
for (const step of steps) {
|
|
205
231
|
if (step.kind === 'edits') {
|
|
206
232
|
if (step.open && readOnlyAt(host, step.readUri, host.editorOf(step.readUri))) {
|
|
207
233
|
return `${step.uri} is read only`;
|
|
208
234
|
}
|
|
235
|
+
|
|
209
236
|
continue;
|
|
210
237
|
}
|
|
238
|
+
|
|
211
239
|
const uris = step.kind === 'rename' ? [step.oldUri, step.newUri] : [step.uri];
|
|
212
240
|
const paths = uris.map((uri) => fileUriToPath(uri));
|
|
241
|
+
|
|
213
242
|
if (paths.includes(null)) {
|
|
214
243
|
return `${uris[0]} cannot be changed from here`;
|
|
215
244
|
}
|
|
245
|
+
|
|
216
246
|
if ((step.kind === 'create' || step.kind === 'rename') && step.overwrite) {
|
|
217
247
|
const target = step.kind === 'create' ? step.uri : step.newUri;
|
|
218
248
|
const refusal = overwriteProblem(step, target, placesOf(target, renames), host, reads);
|
|
249
|
+
|
|
219
250
|
if (refusal !== null) {
|
|
220
251
|
return refusal;
|
|
221
252
|
}
|
|
222
253
|
}
|
|
254
|
+
|
|
223
255
|
if (step.kind === 'rename') {
|
|
224
256
|
renames.push({ kind: 'rename', oldUri: step.oldUri, newUri: step.newUri });
|
|
225
257
|
}
|
|
258
|
+
|
|
226
259
|
if (step.kind === 'delete' && losesWork(step.recursive, placesOf(step.uri, renames), host)) {
|
|
227
260
|
return `${paths[0]} has changes that are not saved`;
|
|
228
261
|
}
|
|
229
262
|
}
|
|
263
|
+
|
|
230
264
|
for (const [uri, planned] of reads.open) {
|
|
231
265
|
const editor = host.editorOf(uri);
|
|
266
|
+
|
|
232
267
|
if (editor === undefined || editor.getText() !== planned.text) {
|
|
233
268
|
return `${uri} changed while the edit was being prepared`;
|
|
234
269
|
}
|
|
270
|
+
|
|
235
271
|
const version = host.versionOf?.(uri) ?? null;
|
|
272
|
+
|
|
236
273
|
if (planned.version !== null && version !== planned.version) {
|
|
237
274
|
return `${uri} changed while the edit was being prepared`;
|
|
238
275
|
}
|
|
239
276
|
}
|
|
277
|
+
|
|
240
278
|
for (const uri of reads.disks.keys()) {
|
|
241
279
|
if (host.editorOf(uri) !== undefined) {
|
|
242
280
|
return `${uri} was opened while the edit was being prepared`;
|
|
243
281
|
}
|
|
244
282
|
}
|
|
283
|
+
|
|
245
284
|
return null;
|
|
246
285
|
}
|
|
247
286
|
|
|
@@ -266,23 +305,30 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, host: WorkspaceEdi
|
|
|
266
305
|
const reads: Reads = { open: new Map(), disks: new Map() };
|
|
267
306
|
const files = host.files;
|
|
268
307
|
let steps: readonly WorkspaceEditStep[];
|
|
308
|
+
|
|
269
309
|
try {
|
|
270
310
|
({ steps } = await planWorkspaceOperations(edit, {
|
|
271
311
|
operations: supportedResourceOperations(files),
|
|
272
312
|
read: async (uri) => {
|
|
273
313
|
const editor = host.editorOf(uri);
|
|
314
|
+
|
|
274
315
|
if (editor !== undefined) {
|
|
275
316
|
const text = editor.getText();
|
|
276
317
|
const version = host.versionOf?.(uri) ?? null;
|
|
277
318
|
reads.open.set(uri, { text, version });
|
|
319
|
+
|
|
278
320
|
return { text, version, open: true };
|
|
279
321
|
}
|
|
322
|
+
|
|
280
323
|
const path = fileUriToPath(uri);
|
|
281
324
|
const disk = path === null || files === null ? null : await files.read(path);
|
|
325
|
+
|
|
282
326
|
if (disk === null) {
|
|
283
327
|
return null;
|
|
284
328
|
}
|
|
329
|
+
|
|
285
330
|
reads.disks.set(uri, disk);
|
|
331
|
+
|
|
286
332
|
return { text: disk.text, version: null, open: false };
|
|
287
333
|
},
|
|
288
334
|
...(files?.exists === undefined
|
|
@@ -290,6 +336,7 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, host: WorkspaceEdi
|
|
|
290
336
|
: {
|
|
291
337
|
exists: async (uri: string) => {
|
|
292
338
|
const path = fileUriToPath(uri);
|
|
339
|
+
|
|
293
340
|
return path !== null && (await files.exists!(path));
|
|
294
341
|
}
|
|
295
342
|
}),
|
|
@@ -298,6 +345,7 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, host: WorkspaceEdi
|
|
|
298
345
|
: {
|
|
299
346
|
isFolder: async (uri: string) => {
|
|
300
347
|
const path = fileUriToPath(uri);
|
|
348
|
+
|
|
301
349
|
return path === null || (await files.isFolder!(path));
|
|
302
350
|
}
|
|
303
351
|
})
|
|
@@ -305,21 +353,28 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, host: WorkspaceEdi
|
|
|
305
353
|
} catch (error) {
|
|
306
354
|
return refused(messageOf(error));
|
|
307
355
|
}
|
|
356
|
+
|
|
308
357
|
const problem = problemWith(steps, host, reads);
|
|
358
|
+
|
|
309
359
|
if (problem !== null) {
|
|
310
360
|
return refused(problem);
|
|
311
361
|
}
|
|
362
|
+
|
|
312
363
|
const running: Running = { ahead: [], reads, saving: steps.some((step) => step.kind === 'rename'), staged: [], touched: new Set() };
|
|
364
|
+
|
|
313
365
|
for (const [index, step] of steps.entries()) {
|
|
314
366
|
running.ahead = steps.slice(index + 1);
|
|
315
367
|
const reason = await run(step, host, running);
|
|
368
|
+
|
|
316
369
|
if (reason !== null) {
|
|
317
370
|
return refused(reason);
|
|
318
371
|
}
|
|
319
372
|
}
|
|
373
|
+
|
|
320
374
|
if (running.staged.length > 0) {
|
|
321
375
|
files?.stage(running.staged);
|
|
322
376
|
}
|
|
377
|
+
|
|
323
378
|
return { applied: true };
|
|
324
379
|
}
|
|
325
380
|
|
|
@@ -340,56 +395,74 @@ function driftOf(step: PlannedTextStep, host: WorkspaceEditHost, uri: string, ed
|
|
|
340
395
|
if (editor.getText() !== step.before) {
|
|
341
396
|
return `${step.uri} changed while the edit was being applied`;
|
|
342
397
|
}
|
|
398
|
+
|
|
343
399
|
const version = uri === step.readUri && !touched.has(editor) ? host.versionOf?.(uri) : undefined;
|
|
400
|
+
|
|
344
401
|
if (version !== undefined && step.version !== null && version !== step.version) {
|
|
345
402
|
return `${step.uri} changed while the edit was being applied`;
|
|
346
403
|
}
|
|
404
|
+
|
|
347
405
|
return readOnlyAt(host, uri, editor) ? `${step.uri} is read only` : null;
|
|
348
406
|
}
|
|
349
407
|
|
|
350
408
|
/* Does one step; the reason it could not, or null. */
|
|
351
409
|
async function run(step: WorkspaceEditStep, host: WorkspaceEditHost, running: Running): Promise<string | null> {
|
|
352
410
|
const files = host.files!;
|
|
411
|
+
|
|
353
412
|
if (step.kind === 'create') {
|
|
354
413
|
return step.overwrite ? overwriteFile(step, host) : files.create!(fileUriToPath(step.uri)!, step.text);
|
|
355
414
|
}
|
|
415
|
+
|
|
356
416
|
if (step.kind === 'rename') {
|
|
357
417
|
const [from, to] = [fileUriToPath(step.oldUri)!, fileUriToPath(step.newUri)!];
|
|
418
|
+
|
|
358
419
|
if (!step.overwrite) {
|
|
359
420
|
return files.rename(from, to);
|
|
360
421
|
}
|
|
422
|
+
|
|
361
423
|
// The steps before this one ran, so the unsaved work at the target is looked for once more.
|
|
362
424
|
return losesWork(!running.reads.disks.has(step.newUri) && !running.reads.open.has(step.newUri), [step.newUri], host)
|
|
363
425
|
? `${to} has changes that are not saved`
|
|
364
426
|
: files.rename(from, to, { overwrite: true });
|
|
365
427
|
}
|
|
428
|
+
|
|
366
429
|
if (step.kind === 'delete') {
|
|
367
430
|
const path = fileUriToPath(step.uri)!;
|
|
431
|
+
|
|
368
432
|
if (losesWork(step.recursive, [step.uri], host)) {
|
|
369
433
|
return `${path} has changes that are not saved`;
|
|
370
434
|
}
|
|
435
|
+
|
|
371
436
|
return files.delete!(path, { recursive: step.recursive });
|
|
372
437
|
}
|
|
438
|
+
|
|
373
439
|
if (step.after === step.before) {
|
|
374
440
|
return null;
|
|
375
441
|
}
|
|
442
|
+
|
|
376
443
|
if (step.open) {
|
|
377
444
|
const uri = host.editorOf(step.uri) === undefined ? step.readUri : step.uri;
|
|
445
|
+
|
|
378
446
|
return editOpen(step, host, running, uri, host.editorOf(uri));
|
|
379
447
|
}
|
|
448
|
+
|
|
380
449
|
return runDraft(step, host, running);
|
|
381
450
|
}
|
|
382
451
|
|
|
383
452
|
/* Empties a file that is there and gives it its text; the editor that still holds it is set to the same text. */
|
|
384
453
|
async function overwriteFile(step: PlannedCreateStep, host: WorkspaceEditHost): Promise<string | null> {
|
|
385
454
|
const path = fileUriToPath(step.uri)!;
|
|
455
|
+
|
|
386
456
|
if (losesWork(false, [step.uri], host)) {
|
|
387
457
|
return `${path} has changes that are not saved`;
|
|
388
458
|
}
|
|
459
|
+
|
|
389
460
|
const reason = await host.files!.create!(path, step.text, { overwrite: true });
|
|
461
|
+
|
|
390
462
|
if (reason === null) {
|
|
391
463
|
host.editorOf(step.uri)?.setText(step.text);
|
|
392
464
|
}
|
|
465
|
+
|
|
393
466
|
return reason;
|
|
394
467
|
}
|
|
395
468
|
|
|
@@ -397,11 +470,15 @@ function editOpen(step: PlannedTextStep, host: WorkspaceEditHost, running: Runni
|
|
|
397
470
|
if (editor === undefined) {
|
|
398
471
|
return `${step.uri} is not open any more`;
|
|
399
472
|
}
|
|
473
|
+
|
|
400
474
|
const drift = driftOf(step, host, uri, editor, running.touched);
|
|
475
|
+
|
|
401
476
|
if (drift !== null) {
|
|
402
477
|
return drift;
|
|
403
478
|
}
|
|
479
|
+
|
|
404
480
|
running.touched.add(editor);
|
|
481
|
+
|
|
405
482
|
// The edits stay apart, so the caret and what is drawn over the text stay where they were between them.
|
|
406
483
|
return editor.applyEdits(step.edits.map(contentChangeOf)) ? null : `${step.uri} is read only`;
|
|
407
484
|
}
|
|
@@ -414,18 +491,25 @@ function deletedAhead(uri: string, ahead: readonly WorkspaceEditStep[]): boolean
|
|
|
414
491
|
async function runDraft(step: PlannedTextStep, host: WorkspaceEditHost, running: Running): Promise<string | null> {
|
|
415
492
|
const { reads, saving, staged, ahead } = running;
|
|
416
493
|
const uri = [step.uri, step.readUri].find((candidate) => host.editorOf(candidate) !== undefined);
|
|
494
|
+
|
|
417
495
|
if (uri !== undefined) {
|
|
418
496
|
return editOpen(step, host, running, uri, host.editorOf(uri));
|
|
419
497
|
}
|
|
498
|
+
|
|
420
499
|
const path = fileUriToPath(step.uri);
|
|
421
500
|
const disk = reads.disks.get(step.readUri);
|
|
501
|
+
|
|
422
502
|
if (path === null || disk === undefined || deletedAhead(step.uri, ahead)) {
|
|
423
503
|
return null;
|
|
424
504
|
}
|
|
505
|
+
|
|
425
506
|
const file = { path, disk, text: step.after };
|
|
507
|
+
|
|
426
508
|
if (!saving) {
|
|
427
509
|
staged.push(file);
|
|
510
|
+
|
|
428
511
|
return null;
|
|
429
512
|
}
|
|
513
|
+
|
|
430
514
|
return host.files!.save([file]);
|
|
431
515
|
}
|