diff --git a/src/vs/workbench/api/browser/mainThreadDocuments.ts b/src/vs/workbench/api/browser/mainThreadDocuments.ts index 9189cebfb1e..8b624063795 100644 --- a/src/vs/workbench/api/browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadDocuments.ts @@ -104,9 +104,9 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { this._toDispose.add(this._modelReferenceCollection); this._toDispose.add(modelService.onModelModeChanged(this._onModelModeChanged, this)); - this._toDispose.add(textFileService.models.onDidSave(m => { - if (this._shouldHandleFileEvent(m.resource)) { - this._proxy.$acceptModelSaved(m.resource); + this._toDispose.add(textFileService.models.onDidSave(e => { + if (this._shouldHandleFileEvent(e.model.resource)) { + this._proxy.$acceptModelSaved(e.model.resource); } })); this._toDispose.add(textFileService.models.onDidRevert(m => { diff --git a/src/vs/workbench/contrib/experiments/common/experimentService.ts b/src/vs/workbench/contrib/experiments/common/experimentService.ts index 65937cf4908..226b389f3f5 100644 --- a/src/vs/workbench/contrib/experiments/common/experimentService.ts +++ b/src/vs/workbench/contrib/experiments/common/experimentService.ts @@ -448,7 +448,7 @@ export class ExperimentService extends Disposable implements IExperimentService } }, 250)); - const onSaveHandler = this._register(this.textFileService.models.onDidSave(m => onModelsSavedWorker.work(m))); + const onSaveHandler = this._register(this.textFileService.models.onDidSave(e => onModelsSavedWorker.work(e.model))); return ExperimentState.Evaluating; }); } diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts b/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts index 7a0d530facb..02b32c67006 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts @@ -71,7 +71,7 @@ export class TextFileSaveErrorHandler extends Disposable implements ISaveErrorHa } private registerListeners(): void { - this._register(this.textFileService.models.onDidSave(m => this.onFileSavedOrReverted(m.resource))); + this._register(this.textFileService.models.onDidSave(e => this.onFileSavedOrReverted(e.model.resource))); this._register(this.textFileService.models.onDidRevert(m => this.onFileSavedOrReverted(m.resource))); this._register(this.editorService.onDidActiveEditorChange(() => this.onActiveEditorChanged())); } diff --git a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts index 59af8f75b00..e21bfa9fec3 100644 --- a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts @@ -72,7 +72,7 @@ export class FileEditorInput extends TextEditorInput implements IFileEditorInput // Dirty changes this._register(this.textFileService.models.onDidChangeDirty(m => this.onDirtyStateChange(m))); this._register(this.textFileService.models.onDidSaveError(m => this.onDirtyStateChange(m))); - this._register(this.textFileService.models.onDidSave(m => this.onDirtyStateChange(m))); + this._register(this.textFileService.models.onDidSave(e => this.onDirtyStateChange(e.model))); this._register(this.textFileService.models.onDidRevert(m => this.onDirtyStateChange(m))); // Label changes diff --git a/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts b/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts index 4cba8e2b818..e196f2c4ecd 100644 --- a/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts +++ b/src/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts @@ -62,7 +62,7 @@ class LanguageSurvey extends Disposable { }); }, 250)); - this._register(textFileService.models.onDidSave(m => onModelsSavedWorker.work(m))); + this._register(textFileService.models.onDidSave(e => onModelsSavedWorker.work(e.model))); } const lastSessionDate = storageService.get(LAST_SESSION_DATE_KEY, StorageScope.GLOBAL, new Date(0).toDateString()); diff --git a/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts b/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts index de4f62d26e9..a01ba225296 100644 --- a/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts +++ b/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts @@ -19,7 +19,7 @@ import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry'; import { configurationTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ITextFileModelSaveEvent, ITextFileModelLoadEvent } from 'vs/workbench/services/textfile/common/textfiles'; import { extname, basename, isEqual, isEqualOrParent, joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; @@ -124,15 +124,15 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr this._register(configurationTelemetry(telemetryService, configurationService)); // Files Telemetry - this._register(textFileService.models.onDidLoad(m => this.onTextFileModelLoaded(m))); - this._register(textFileService.models.onDidSave(m => this.onTextFileModelSaved(m))); + this._register(textFileService.models.onDidLoad(e => this.onTextFileModelLoaded(e))); + this._register(textFileService.models.onDidSave(e => this.onTextFileModelSaved(e))); // Lifecycle this._register(lifecycleService.onShutdown(() => this.dispose())); } - private onTextFileModelLoaded(model: ITextFileEditorModel): void { - const settingsType = this.getTypeIfSettings(model.resource); + private onTextFileModelLoaded(e: ITextFileModelLoadEvent): void { + const settingsType = this.getTypeIfSettings(e.model.resource); if (settingsType) { type SettingsReadClassification = { settingsType: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; @@ -142,12 +142,12 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr } else { type FileGetClassification = {} & FileTelemetryDataFragment; - this.telemetryService.publicLog2('fileGet', this.getTelemetryData(model.resource)); + this.telemetryService.publicLog2('fileGet', this.getTelemetryData(e.model.resource, e.reason)); } } - private onTextFileModelSaved(model: ITextFileEditorModel): void { - const settingsType = this.getTypeIfSettings(model.resource); + private onTextFileModelSaved(e: ITextFileModelSaveEvent): void { + const settingsType = this.getTypeIfSettings(e.model.resource); if (settingsType) { type SettingsWrittenClassification = { settingsType: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; @@ -155,7 +155,7 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr this.telemetryService.publicLog2<{ settingsType: string }, SettingsWrittenClassification>('settingsWritten', { settingsType }); // Do not log write to user settings.json and .vscode folder as a filePUT event as it ruins our JSON usage data } else { type FilePutClassfication = {} & FileTelemetryDataFragment; - this.telemetryService.publicLog2('filePUT', this.getTelemetryData(model.resource)); + this.telemetryService.publicLog2('filePUT', this.getTelemetryData(e.model.resource, e.reason)); } } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index bce63d972b3..7abf65e410c 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -8,7 +8,7 @@ import { Emitter } from 'vs/base/common/event'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { URI } from 'vs/base/common/uri'; import { assertIsDefined } from 'vs/base/common/types'; -import { ITextFileService, ModelState, ITextFileEditorModel, ISaveErrorHandler, ISaveParticipant, ITextFileStreamContent, ILoadOptions, IResolvedTextFileEditorModel, ITextFileSaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ModelState, ITextFileEditorModel, ISaveErrorHandler, ISaveParticipant, ITextFileStreamContent, ILoadOptions, IResolvedTextFileEditorModel, ITextFileSaveOptions, LoadReason } from 'vs/workbench/services/textfile/common/textfiles'; import { EncodingMode, IRevertOptions, SaveReason } from 'vs/workbench/common/editor'; import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; @@ -49,13 +49,13 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private readonly _onDidChangeContent = this._register(new Emitter()); readonly onDidChangeContent = this._onDidChangeContent.event; - private readonly _onDidLoad = this._register(new Emitter()); + private readonly _onDidLoad = this._register(new Emitter()); readonly onDidLoad = this._onDidLoad.event; private readonly _onDidSaveError = this._register(new Emitter()); readonly onDidSaveError = this._onDidSaveError.event; - private readonly _onDidSave = this._register(new Emitter()); + private readonly _onDidSave = this._register(new Emitter()); readonly onDidSave = this._onDidSave.event; private readonly _onDidRevert = this._register(new Emitter()); @@ -405,7 +405,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } // Emit as event - this._onDidLoad.fire(); + this._onDidLoad.fire(options?.reason ?? LoadReason.OTHER); return this; } @@ -637,7 +637,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // - the model is not in orphan mode (because in that case we know the file does not exist on disk) // - the model version did not change due to save participants running if (options.force && !this.dirty && !this.inOrphanMode && options.reason === SaveReason.EXPLICIT && versionId === newVersionId) { - return this.doTouch(newVersionId); + return this.doTouch(newVersionId, options.reason); } // update versionId with its new value (if pre-save changes happened) @@ -675,7 +675,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.updateLastResolvedFileStat(stat); // Emit Events - this._onDidSave.fire(); + this._onDidSave.fire(options.reason ?? SaveReason.EXPLICIT); this._onDidChangeDirty.fire(); }, error => { this.logService.error(`[text file model] doSave(${versionId}) - exit - resulted in a save error: ${error.toString()}`, this.resource.toString()); @@ -697,7 +697,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil })); } - private doTouch(versionId: number): Promise { + private doTouch(versionId: number, reason: SaveReason): Promise { if (!this.isResolved()) { return Promise.resolve(); } @@ -713,7 +713,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.updateLastResolvedFileStat(stat); // Emit File Saved Event - this._onDidSave.fire(); + this._onDidSave.fire(reason); }, error => onUnexpectedError(error) /* just log any error but do not notify the user since the file was not dirty */)); } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index f772a62df09..4fbc86a0d1f 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -7,7 +7,7 @@ import { Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { dispose, IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { ITextFileEditorModel, ITextFileEditorModelManager, IModelLoadOrCreateOptions } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileEditorModel, ITextFileEditorModelManager, IModelLoadOrCreateOptions, ITextFileModelLoadEvent, ITextFileModelSaveEvent } from 'vs/workbench/services/textfile/common/textfiles'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ResourceMap } from 'vs/base/common/map'; @@ -18,7 +18,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; export class TextFileEditorModelManager extends Disposable implements ITextFileEditorModelManager { - private readonly _onDidLoad = this._register(new Emitter()); + private readonly _onDidLoad = this._register(new Emitter()); readonly onDidLoad = this._onDidLoad.event; private readonly _onDidChangeDirty = this._register(new Emitter()); @@ -27,7 +27,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE private readonly _onDidSaveError = this._register(new Emitter()); readonly onDidSaveError = this._onDidSaveError.event; - private readonly _onDidSave = this._register(new Emitter()); + private readonly _onDidSave = this._register(new Emitter()); readonly onDidSave = this._onDidSave.event; private readonly _onDidRevert = this._register(new Emitter()); @@ -129,10 +129,10 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE // Install model listeners const listeners = new DisposableStore(); - listeners.add(model.onDidLoad(() => this._onDidLoad.fire(newModel))); + listeners.add(model.onDidLoad(reason => this._onDidLoad.fire({ model: newModel, reason }))); listeners.add(model.onDidChangeDirty(() => this._onDidChangeDirty.fire(newModel))); listeners.add(model.onDidSaveError(() => this._onDidSaveError.fire(newModel))); - listeners.add(model.onDidSave(() => this._onDidSave.fire(newModel))); + listeners.add(model.onDidSave(reason => this._onDidSave.fire({ model: newModel, reason }))); listeners.add(model.onDidRevert(() => this._onDidRevert.fire(newModel))); listeners.add(model.onDidChangeEncoding(() => this._onDidChangeEncoding.fire(newModel))); listeners.add(model.onDidChangeOrphaned(() => this._onDidChangeOrphaned.fire(newModel))); diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index f32f2fd796c..89ce41bdbaa 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -350,12 +350,22 @@ export interface IModelLoadOrCreateOptions { allowBinary?: boolean; } +export interface ITextFileModelSaveEvent { + model: ITextFileEditorModel; + reason: SaveReason; +} + +export interface ITextFileModelLoadEvent { + model: ITextFileEditorModel; + reason: LoadReason; +} + export interface ITextFileEditorModelManager { - readonly onDidLoad: Event; + readonly onDidLoad: Event; readonly onDidChangeDirty: Event; readonly onDidSaveError: Event; - readonly onDidSave: Event; + readonly onDidSave: Event; readonly onDidRevert: Event; readonly onDidChangeEncoding: Event; readonly onDidChangeOrphaned: Event; @@ -397,9 +407,9 @@ export interface ILoadOptions { export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport, IModeSupport, IWorkingCopy { readonly onDidChangeContent: Event; - readonly onDidLoad: Event; + readonly onDidLoad: Event; readonly onDidSaveError: Event; - readonly onDidSave: Event; + readonly onDidSave: Event; readonly onDidRevert: Event; readonly onDidChangeEncoding: Event; readonly onDidChangeOrphaned: Event; diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts index b59f1e7b12e..3eab2ccf1aa 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts @@ -139,7 +139,7 @@ suite('Files - TextFileEditorModelManager', () => { let savedCounter = 0; let encodingCounter = 0; - manager.onDidLoad(model => { + manager.onDidLoad(({ model }) => { if (model.resource.toString() === resource1.toString()) { loadedCounter++; } @@ -157,7 +157,7 @@ suite('Files - TextFileEditorModelManager', () => { } }); - manager.onDidSave(model => { + manager.onDidSave(({ model }) => { if (model.resource.toString() === resource1.toString()) { savedCounter++; }