Skip to content

Commit 0e7e31b

Browse files
authored
save participants - provide access to the from resource in "Save As" scenarios (microsoft#203516)
1 parent b26b050 commit 0e7e31b

File tree

17 files changed

+172
-60
lines changed

17 files changed

+172
-60
lines changed

src/vs/platform/product/common/product.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ else {
5858
// Running out of sources
5959
if (Object.keys(product).length === 0) {
6060
Object.assign(product, {
61-
version: '1.82.0-dev',
61+
version: '1.87.0-dev',
6262
nameShort: 'Code - OSS Dev',
6363
nameLong: 'Code - OSS Dev',
6464
applicationName: 'code-oss',

src/vs/workbench/api/browser/mainThreadNotebookSaveParticipant.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ import { localize } from 'vs/nls';
88
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
99
import { IProgressStep, IProgress } from 'vs/platform/progress/common/progress';
1010
import { extHostCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
11-
import { SaveReason } from 'vs/workbench/common/editor';
1211
import { ExtHostContext, ExtHostNotebookDocumentSaveParticipantShape } from '../common/extHost.protocol';
1312
import { IDisposable } from 'vs/base/common/lifecycle';
1413
import { raceCancellationError } from 'vs/base/common/async';
15-
import { IStoredFileWorkingCopySaveParticipant, IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
14+
import { IStoredFileWorkingCopySaveParticipant, IStoredFileWorkingCopySaveParticipantContext, IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
1615
import { IStoredFileWorkingCopy, IStoredFileWorkingCopyModel } from 'vs/workbench/services/workingCopy/common/storedFileWorkingCopy';
1716
import { NotebookFileWorkingCopyModel } from 'vs/workbench/contrib/notebook/common/notebookEditorModel';
1817

@@ -24,7 +23,7 @@ class ExtHostNotebookDocumentSaveParticipant implements IStoredFileWorkingCopySa
2423
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebookDocumentSaveParticipant);
2524
}
2625

27-
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, env: { reason: SaveReason }, _progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
26+
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, context: IStoredFileWorkingCopySaveParticipantContext, _progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
2827

2928
if (!workingCopy.model || !(workingCopy.model instanceof NotebookFileWorkingCopyModel)) {
3029
return undefined;
@@ -38,7 +37,7 @@ class ExtHostNotebookDocumentSaveParticipant implements IStoredFileWorkingCopySa
3837
() => reject(new Error(localize('timeout.onWillSave', "Aborted onWillSaveNotebookDocument-event after 1750ms"))),
3938
1750
4039
);
41-
this._proxy.$participateInSave(workingCopy.resource, env.reason, token).then(_ => {
40+
this._proxy.$participateInSave(workingCopy.resource, context.reason, token).then(_ => {
4241
clearTimeout(_warningTimeout);
4342
return undefined;
4443
}).then(resolve, reject);

src/vs/workbench/api/browser/mainThreadSaveParticipant.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import { localize } from 'vs/nls';
99
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
1010
import { IProgressStep, IProgress } from 'vs/platform/progress/common/progress';
1111
import { extHostCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
12-
import { ITextFileSaveParticipant, ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
13-
import { SaveReason } from 'vs/workbench/common/editor';
12+
import { ITextFileSaveParticipant, ITextFileService, ITextFileEditorModel, ITextFileSaveParticipantContext } from 'vs/workbench/services/textfile/common/textfiles';
1413
import { ExtHostContext, ExtHostDocumentSaveParticipantShape } from '../common/extHost.protocol';
1514
import { IDisposable } from 'vs/base/common/lifecycle';
1615
import { raceCancellationError } from 'vs/base/common/async';
@@ -23,7 +22,7 @@ class ExtHostSaveParticipant implements ITextFileSaveParticipant {
2322
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentSaveParticipant);
2423
}
2524

26-
async participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason }, _progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
25+
async participate(editorModel: ITextFileEditorModel, context: ITextFileSaveParticipantContext, _progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
2726

2827
if (!editorModel.textEditorModel || !shouldSynchronizeModel(editorModel.textEditorModel)) {
2928
// the model never made it to the extension
@@ -37,7 +36,7 @@ class ExtHostSaveParticipant implements ITextFileSaveParticipant {
3736
() => reject(new Error(localize('timeout.onWillSave', "Aborted onWillSaveTextDocument-event after 1750ms"))),
3837
1750
3938
);
40-
this._proxy.$participateInSave(editorModel.resource, env.reason).then(values => {
39+
this._proxy.$participateInSave(editorModel.resource, context.reason).then(values => {
4140
if (!values.every(success => success)) {
4241
return Promise.reject(new Error('listener failed'));
4342
}

src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as
3030
import { SaveReason } from 'vs/workbench/common/editor';
3131
import { getModifiedRanges } from 'vs/workbench/contrib/format/browser/formatModified';
3232
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
33-
import { ITextFileEditorModel, ITextFileSaveParticipant, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
33+
import { ITextFileEditorModel, ITextFileSaveParticipant, ITextFileSaveParticipantContext, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
3434

3535
export class TrimWhitespaceParticipant implements ITextFileSaveParticipant {
3636

@@ -41,13 +41,13 @@ export class TrimWhitespaceParticipant implements ITextFileSaveParticipant {
4141
// Nothing
4242
}
4343

44-
async participate(model: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
44+
async participate(model: ITextFileEditorModel, context: ITextFileSaveParticipantContext): Promise<void> {
4545
if (!model.textEditorModel) {
4646
return;
4747
}
4848

4949
if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageId(), resource: model.resource })) {
50-
this.doTrimTrailingWhitespace(model.textEditorModel, env.reason === SaveReason.AUTO);
50+
this.doTrimTrailingWhitespace(model.textEditorModel, context.reason === SaveReason.AUTO);
5151
}
5252
}
5353

@@ -107,7 +107,7 @@ export class FinalNewLineParticipant implements ITextFileSaveParticipant {
107107
// Nothing
108108
}
109109

110-
async participate(model: ITextFileEditorModel, _env: { reason: SaveReason }): Promise<void> {
110+
async participate(model: ITextFileEditorModel, context: ITextFileSaveParticipantContext): Promise<void> {
111111
if (!model.textEditorModel) {
112112
return;
113113
}
@@ -145,13 +145,13 @@ export class TrimFinalNewLinesParticipant implements ITextFileSaveParticipant {
145145
// Nothing
146146
}
147147

148-
async participate(model: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
148+
async participate(model: ITextFileEditorModel, context: ITextFileSaveParticipantContext): Promise<void> {
149149
if (!model.textEditorModel) {
150150
return;
151151
}
152152

153153
if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageId(), resource: model.resource })) {
154-
this.doTrimFinalNewLines(model.textEditorModel, env.reason === SaveReason.AUTO);
154+
this.doTrimFinalNewLines(model.textEditorModel, context.reason === SaveReason.AUTO);
155155
}
156156
}
157157

@@ -217,11 +217,11 @@ class FormatOnSaveParticipant implements ITextFileSaveParticipant {
217217
// Nothing
218218
}
219219

220-
async participate(model: ITextFileEditorModel, env: { reason: SaveReason }, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
220+
async participate(model: ITextFileEditorModel, context: ITextFileSaveParticipantContext, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
221221
if (!model.textEditorModel) {
222222
return;
223223
}
224-
if (env.reason === SaveReason.AUTO) {
224+
if (context.reason === SaveReason.AUTO) {
225225
return undefined;
226226
}
227227

@@ -272,7 +272,7 @@ class CodeActionOnSaveParticipant implements ITextFileSaveParticipant {
272272
@ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService,
273273
) { }
274274

275-
async participate(model: ITextFileEditorModel, env: { reason: SaveReason }, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
275+
async participate(model: ITextFileEditorModel, context: ITextFileSaveParticipantContext, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
276276
if (!model.textEditorModel) {
277277
return;
278278
}
@@ -286,11 +286,11 @@ class CodeActionOnSaveParticipant implements ITextFileSaveParticipant {
286286
return undefined;
287287
}
288288

289-
if (env.reason === SaveReason.AUTO) {
289+
if (context.reason === SaveReason.AUTO) {
290290
return undefined;
291291
}
292292

293-
if (env.reason !== SaveReason.EXPLICIT && Array.isArray(setting)) {
293+
if (context.reason !== SaveReason.EXPLICIT && Array.isArray(setting)) {
294294
return undefined;
295295
}
296296

@@ -326,7 +326,7 @@ class CodeActionOnSaveParticipant implements ITextFileSaveParticipant {
326326

327327
progress.report({ message: localize('codeaction', "Quick Fixes") });
328328

329-
const filteredSaveList = Array.isArray(setting) ? codeActionsOnSave : codeActionsOnSave.filter(x => setting[x.value] === 'always' || ((setting[x.value] === 'explicit' || setting[x.value] === true) && env.reason === SaveReason.EXPLICIT));
329+
const filteredSaveList = Array.isArray(setting) ? codeActionsOnSave : codeActionsOnSave.filter(x => setting[x.value] === 'always' || ((setting[x.value] === 'explicit' || setting[x.value] === true) && context.reason === SaveReason.EXPLICIT));
330330

331331
await this.applyOnSaveActions(textEditorModel, filteredSaveList, excludedActions, progress, token);
332332
}

src/vs/workbench/contrib/notebook/browser/contrib/saveParticipants/saveParticipants.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import { NotebookFileWorkingCopyModel } from 'vs/workbench/contrib/notebook/comm
3636
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
3737
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
3838
import { IStoredFileWorkingCopy, IStoredFileWorkingCopyModel } from 'vs/workbench/services/workingCopy/common/storedFileWorkingCopy';
39-
import { IStoredFileWorkingCopySaveParticipant, IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
39+
import { IStoredFileWorkingCopySaveParticipant, IStoredFileWorkingCopySaveParticipantContext, IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
4040

4141
class FormatOnSaveParticipant implements IStoredFileWorkingCopySaveParticipant {
4242
constructor(
@@ -47,7 +47,7 @@ class FormatOnSaveParticipant implements IStoredFileWorkingCopySaveParticipant {
4747
@IConfigurationService private readonly configurationService: IConfigurationService,
4848
) { }
4949

50-
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, context: { reason: SaveReason }, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
50+
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, context: IStoredFileWorkingCopySaveParticipantContext, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
5151
if (!workingCopy.model || !(workingCopy.model instanceof NotebookFileWorkingCopyModel)) {
5252
return;
5353
}
@@ -108,7 +108,7 @@ class TrimWhitespaceParticipant implements IStoredFileWorkingCopySaveParticipant
108108
@IBulkEditService private readonly bulkEditService: IBulkEditService,
109109
) { }
110110

111-
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, context: { reason: SaveReason }, progress: IProgress<IProgressStep>, _token: CancellationToken): Promise<void> {
111+
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, context: IStoredFileWorkingCopySaveParticipantContext, progress: IProgress<IProgressStep>, _token: CancellationToken): Promise<void> {
112112
if (this.configurationService.getValue<boolean>('files.trimTrailingWhitespace')) {
113113
await this.doTrimTrailingWhitespace(workingCopy, context.reason === SaveReason.AUTO, progress);
114114
}
@@ -175,7 +175,7 @@ class TrimFinalNewLinesParticipant implements IStoredFileWorkingCopySaveParticip
175175
@IBulkEditService private readonly bulkEditService: IBulkEditService,
176176
) { }
177177

178-
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, context: { reason: SaveReason }, progress: IProgress<IProgressStep>, _token: CancellationToken): Promise<void> {
178+
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, context: IStoredFileWorkingCopySaveParticipantContext, progress: IProgress<IProgressStep>, _token: CancellationToken): Promise<void> {
179179
if (this.configurationService.getValue<boolean>('files.trimFinalNewlines')) {
180180
await this.doTrimFinalNewLines(workingCopy, context.reason === SaveReason.AUTO, progress);
181181
}
@@ -252,7 +252,7 @@ class FinalNewLineParticipant implements IStoredFileWorkingCopySaveParticipant {
252252
@IEditorService private readonly editorService: IEditorService,
253253
) { }
254254

255-
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, context: { reason: SaveReason }, progress: IProgress<IProgressStep>, _token: CancellationToken): Promise<void> {
255+
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, context: IStoredFileWorkingCopySaveParticipantContext, progress: IProgress<IProgressStep>, _token: CancellationToken): Promise<void> {
256256
// waiting on notebook-specific override before this feature can sync with 'files.insertFinalNewline'
257257
// if (this.configurationService.getValue('files.insertFinalNewline')) {
258258

@@ -317,7 +317,7 @@ class CodeActionOnSaveParticipant implements IStoredFileWorkingCopySaveParticipa
317317
) {
318318
}
319319

320-
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, context: { reason: SaveReason }, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
320+
async participate(workingCopy: IStoredFileWorkingCopy<IStoredFileWorkingCopyModel>, context: IStoredFileWorkingCopySaveParticipantContext, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
321321
const nbDisposable = new DisposableStore();
322322
const isTrusted = this.workspaceTrustManagementService.isWorkspaceTrusted();
323323
if (!isTrusted) {

src/vs/workbench/services/textfile/browser/textFileService.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,10 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
560560
}
561561

562562
// save model
563-
return targetModel.save(options);
563+
return targetModel.save({
564+
...options,
565+
from: source
566+
});
564567
}
565568

566569
private async confirmOverwrite(resource: URI): Promise<boolean> {

src/vs/workbench/services/textfile/common/textFileEditorModel.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Emitter } from 'vs/base/common/event';
88
import { URI } from 'vs/base/common/uri';
99
import { mark } from 'vs/base/common/performance';
1010
import { assertIsDefined } from 'vs/base/common/types';
11-
import { EncodingMode, ITextFileService, TextFileEditorModelState, ITextFileEditorModel, ITextFileStreamContent, ITextFileResolveOptions, IResolvedTextFileEditorModel, ITextFileSaveOptions, TextFileResolveReason, ITextFileEditorModelSaveEvent } from 'vs/workbench/services/textfile/common/textfiles';
11+
import { EncodingMode, ITextFileService, TextFileEditorModelState, ITextFileEditorModel, ITextFileStreamContent, ITextFileResolveOptions, IResolvedTextFileEditorModel, TextFileResolveReason, ITextFileEditorModelSaveEvent, ITextFileSaveAsOptions } from 'vs/workbench/services/textfile/common/textfiles';
1212
import { IRevertOptions, SaveReason, SaveSourceRegistry } from 'vs/workbench/common/editor';
1313
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
1414
import { IWorkingCopyBackupService, IResolvedWorkingCopyBackup } from 'vs/workbench/services/workingCopy/common/workingCopyBackup';
@@ -723,7 +723,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
723723

724724
//#region Save
725725

726-
async save(options: ITextFileSaveOptions = Object.create(null)): Promise<boolean> {
726+
async save(options: ITextFileSaveAsOptions = Object.create(null)): Promise<boolean> {
727727
if (!this.isResolved()) {
728728
return false;
729729
}
@@ -751,7 +751,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
751751
return this.hasState(TextFileEditorModelState.SAVED);
752752
}
753753

754-
private async doSave(options: ITextFileSaveOptions): Promise<void> {
754+
private async doSave(options: ITextFileSaveAsOptions): Promise<void> {
755755
if (typeof options.reason !== 'number') {
756756
options.reason = SaveReason.EXPLICIT;
757757
}
@@ -852,7 +852,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
852852
if (!saveCancellation.token.isCancellationRequested) {
853853
this.ignoreSaveFromSaveParticipants = true;
854854
try {
855-
await this.textFileService.files.runSaveParticipants(this, { reason: options.reason ?? SaveReason.EXPLICIT }, saveCancellation.token);
855+
await this.textFileService.files.runSaveParticipants(this, { reason: options.reason ?? SaveReason.EXPLICIT, savedFrom: options.from }, saveCancellation.token);
856856
} finally {
857857
this.ignoreSaveFromSaveParticipants = false;
858858
}
@@ -919,7 +919,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
919919
})(), () => saveCancellation.cancel());
920920
}
921921

922-
private handleSaveSuccess(stat: IFileStatWithMetadata, versionId: number, options: ITextFileSaveOptions): void {
922+
private handleSaveSuccess(stat: IFileStatWithMetadata, versionId: number, options: ITextFileSaveAsOptions): void {
923923

924924
// Updated resolved stat with updated stat
925925
this.updateLastResolvedFileStat(stat);
@@ -939,7 +939,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
939939
this._onDidSave.fire({ reason: options.reason, stat, source: options.source });
940940
}
941941

942-
private handleSaveError(error: Error, versionId: number, options: ITextFileSaveOptions): void {
942+
private handleSaveError(error: Error, versionId: number, options: ITextFileSaveAsOptions): void {
943943
(options.ignoreErrorHandler ? this.logService.trace : this.logService.error).apply(this.logService, [`[text file model] handleSaveError(${versionId}) - exit - resulted in a save error: ${error.toString()}`, this.resource.toString()]);
944944

945945
// Return early if the save() call was made asking to

src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ import { IFileService, FileChangesEvent, FileOperation, FileChangeType, IFileSys
1616
import { Promises, ResourceQueue } from 'vs/base/common/async';
1717
import { onUnexpectedError } from 'vs/base/common/errors';
1818
import { TextFileSaveParticipant } from 'vs/workbench/services/textfile/common/textFileSaveParticipant';
19-
import { SaveReason } from 'vs/workbench/common/editor';
2019
import { CancellationToken } from 'vs/base/common/cancellation';
2120
import { INotificationService } from 'vs/platform/notification/common/notification';
22-
import { IWorkingCopyFileService, WorkingCopyFileEvent } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
21+
import { IStoredFileWorkingCopySaveParticipantContext, IWorkingCopyFileService, WorkingCopyFileEvent } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
2322
import { ITextSnapshot } from 'vs/editor/common/model';
2423
import { extname, joinPath } from 'vs/base/common/resources';
2524
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
@@ -536,7 +535,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
536535
return this.saveParticipants.addSaveParticipant(participant);
537536
}
538537

539-
runSaveParticipants(model: ITextFileEditorModel, context: { reason: SaveReason }, token: CancellationToken): Promise<void> {
538+
runSaveParticipants(model: ITextFileEditorModel, context: IStoredFileWorkingCopySaveParticipantContext, token: CancellationToken): Promise<void> {
540539
return this.saveParticipants.participate(model, context, token);
541540
}
542541

0 commit comments

Comments
 (0)