From 71222493f3fa6e9489923b4437c6723c5a65b908 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 17 Sep 2021 10:20:38 +0200 Subject: [PATCH] editors - use decorations to indicate deleted and readonly (#130526) --- .../common/editor/resourceEditorInput.ts | 25 +----- .../customEditor/browser/customEditorInput.ts | 9 +- .../test/browser/keybindingEditing.test.ts | 4 +- .../browser/browserTextFileService.ts | 6 +- .../textfile/browser/textFileService.ts | 84 +++++++++++++++++- .../common/textFileEditorModelManager.ts | 8 ++ .../services/textfile/common/textfiles.ts | 2 + .../electron-sandbox/nativeTextFileService.ts | 6 +- .../common/fileWorkingCopyManager.ts | 86 ++++++++++++++++++- .../common/storedFileWorkingCopyManager.ts | 18 ++++ .../browser/fileWorkingCopyManager.test.ts | 2 +- .../untitledFileWorkingCopyManager.test.ts | 6 +- .../test/browser/workbenchTestServices.ts | 9 +- .../electron-browser/workbenchTestServices.ts | 7 +- 14 files changed, 225 insertions(+), 47 deletions(-) diff --git a/src/vs/workbench/common/editor/resourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts index 1065d77fca076..7903e36fab2a3 100644 --- a/src/vs/workbench/common/editor/resourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { localize } from 'vs/nls'; import { Verbosity, IEditorInputWithPreferredResource, EditorInputCapabilities } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { URI } from 'vs/base/common/uri'; @@ -159,16 +158,14 @@ export abstract class AbstractResourceEditorInput extends EditorInput implements } override getTitle(verbosity?: Verbosity): string { - const state = { readonly: this.hasCapability(EditorInputCapabilities.Readonly), orphaned: this.isOrphaned() }; - switch (verbosity) { case Verbosity.SHORT: - return decorateFileEditorLabel(this.shortTitle, state); + return this.shortTitle; case Verbosity.LONG: - return decorateFileEditorLabel(this.longTitle, state); + return this.longTitle; default: case Verbosity.MEDIUM: - return decorateFileEditorLabel(this.mediumTitle, state); + return this.mediumTitle; } } @@ -180,19 +177,3 @@ export abstract class AbstractResourceEditorInput extends EditorInput implements return this.isOrphaned() ? ['strikethrough'] : []; } } - -export function decorateFileEditorLabel(label: string, state: { orphaned: boolean, readonly: boolean }): string { - if (state.orphaned && state.readonly) { - return localize('orphanedReadonlyFile', "{0} (deleted, read-only)", label); - } - - if (state.orphaned) { - return localize('orphanedFile', "{0} (deleted)", label); - } - - if (state.readonly) { - return localize('readonlyFile', "{0} (read-only)", label); - } - - return label; -} diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts index e127487d9832b..f7091f9a7bde7 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -19,7 +19,6 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { DEFAULT_EDITOR_ASSOCIATION, EditorInputCapabilities, GroupIdentifier, IRevertOptions, ISaveOptions, isEditorInputWithOptionsAndGroup, IUntypedEditorInput, Verbosity } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; -import { decorateFileEditorLabel } from 'vs/workbench/common/editor/resourceEditorInput'; import { ICustomEditorModel, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { IWebviewService, WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview'; import { IWebviewWorkbenchService, LazilyResolvedWebviewEditorInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; @@ -219,16 +218,14 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { } override getTitle(verbosity?: Verbosity): string { - const state = { readonly: this.hasCapability(EditorInputCapabilities.Readonly), orphaned: this.isOrphaned() }; - switch (verbosity) { case Verbosity.SHORT: - return decorateFileEditorLabel(this.shortTitle, state); + return this.shortTitle; case Verbosity.LONG: - return decorateFileEditorLabel(this.longTitle, state); + return this.longTitle; default: case Verbosity.MEDIUM: - return decorateFileEditorLabel(this.mediumTitle, state); + return this.mediumTitle; } } diff --git a/src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts index 679e0b10c6104..e43b5ed5f3f17 100644 --- a/src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts @@ -33,7 +33,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; -import { TestWorkingCopyBackupService, TestEditorGroupsService, TestEditorService, TestEnvironmentService, TestLifecycleService, TestPathService, TestTextFileService } from 'vs/workbench/test/browser/workbenchTestServices'; +import { TestWorkingCopyBackupService, TestEditorGroupsService, TestEditorService, TestEnvironmentService, TestLifecycleService, TestPathService, TestTextFileService, TestDecorationsService } from 'vs/workbench/test/browser/workbenchTestServices'; import { FileService } from 'vs/platform/files/common/fileService'; import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; @@ -57,6 +57,7 @@ import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFil import { DisposableStore } from 'vs/base/common/lifecycle'; import { VSBuffer } from 'vs/base/common/buffer'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IDecorationsService } from 'vs/workbench/services/decorations/common/decorations'; interface Modifiers { metaKey?: boolean; @@ -89,6 +90,7 @@ suite('KeybindingsEditing', () => { configService.setUserConfiguration('files', { 'eol': '\n' }); instantiationService.stub(IEnvironmentService, environmentService); + instantiationService.stub(IDecorationsService, TestDecorationsService); instantiationService.stub(IWorkbenchEnvironmentService, environmentService); instantiationService.stub(IPathService, new TestPathService()); instantiationService.stub(IConfigurationService, configService); diff --git a/src/vs/workbench/services/textfile/browser/browserTextFileService.ts b/src/vs/workbench/services/textfile/browser/browserTextFileService.ts index ed4dbf882b7ae..32a9603f1a2b6 100644 --- a/src/vs/workbench/services/textfile/browser/browserTextFileService.ts +++ b/src/vs/workbench/services/textfile/browser/browserTextFileService.ts @@ -23,6 +23,7 @@ import { IPathService } from 'vs/workbench/services/path/common/pathService'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService'; +import { IDecorationsService } from 'vs/workbench/services/decorations/common/decorations'; export class BrowserTextFileService extends AbstractTextFileService { @@ -44,9 +45,10 @@ export class BrowserTextFileService extends AbstractTextFileService { @IUriIdentityService uriIdentityService: IUriIdentityService, @IModeService modeService: IModeService, @IElevatedFileService elevatedFileService: IElevatedFileService, - @ILogService logService: ILogService + @ILogService logService: ILogService, + @IDecorationsService decorationsService: IDecorationsService ) { - super(fileService, untitledTextEditorService, lifecycleService, instantiationService, modelService, environmentService, dialogService, fileDialogService, textResourceConfigurationService, filesConfigurationService, textModelService, codeEditorService, pathService, workingCopyFileService, uriIdentityService, modeService, logService, elevatedFileService); + super(fileService, untitledTextEditorService, lifecycleService, instantiationService, modelService, environmentService, dialogService, fileDialogService, textResourceConfigurationService, filesConfigurationService, textModelService, codeEditorService, pathService, workingCopyFileService, uriIdentityService, modeService, logService, elevatedFileService, decorationsService); this.registerListeners(); } diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index 11c67c66e0bef..1f235524288cc 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -5,7 +5,7 @@ import { localize } from 'vs/nls'; import { URI } from 'vs/base/common/uri'; -import { IEncodingSupport, ITextFileService, ITextFileStreamContent, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, ITextFileSaveOptions, ITextFileEditorModelManager, IResourceEncoding, stringToSnapshot, ITextFileSaveAsOptions, IReadTextFileEncodingOptions } from 'vs/workbench/services/textfile/common/textfiles'; +import { IEncodingSupport, ITextFileService, ITextFileStreamContent, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, ITextFileSaveOptions, ITextFileEditorModelManager, IResourceEncoding, stringToSnapshot, ITextFileSaveAsOptions, IReadTextFileEncodingOptions, TextFileEditorModelState } from 'vs/workbench/services/textfile/common/textfiles'; import { IRevertOptions } from 'vs/workbench/common/editor'; import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IFileService, FileOperationError, FileOperationResult, IFileStatWithMetadata, ICreateFileOptions, IFileStreamContent } from 'vs/platform/files/common/files'; @@ -40,6 +40,10 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { ILogService } from 'vs/platform/log/common/log'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IElevatedFileService } from 'vs/workbench/services/files/common/elevatedFileService'; +import { IDecorationData, IDecorationsProvider, IDecorationsService } from 'vs/workbench/services/decorations/common/decorations'; +import { Emitter } from 'vs/base/common/event'; +import { Codicon } from 'vs/base/common/codicons'; +import { listErrorForeground } from 'vs/platform/theme/common/colorRegistry'; /** * The workbench file service implementation implements the raw file service spec and adds additional methods on top. @@ -70,11 +74,87 @@ export abstract class AbstractTextFileService extends Disposable implements ITex @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, @IModeService private readonly modeService: IModeService, @ILogService protected readonly logService: ILogService, - @IElevatedFileService private readonly elevatedFileService: IElevatedFileService + @IElevatedFileService private readonly elevatedFileService: IElevatedFileService, + @IDecorationsService private readonly decorationsService: IDecorationsService ) { super(); + + this.provideDecorations(); } + //#region decorations + + private provideDecorations(): void { + + // Text file model decorations + this.decorationsService.registerDecorationsProvider(new class extends Disposable implements IDecorationsProvider { + + readonly label = localize('textFileModelDecorations', "Text File Model Decorations"); + + private readonly _onDidChange = this._register(new Emitter()); + readonly onDidChange = this._onDidChange.event; + + constructor(private readonly files: ITextFileEditorModelManager) { + super(); + + this.registerListeners(); + } + + private registerListeners(): void { + + // Creates + this._register(this.files.onDidCreate(model => { + if (model.isReadonly() || model.hasState(TextFileEditorModelState.ORPHAN)) { + this._onDidChange.fire([model.resource]); + } + })); + + // Changes + this._register(this.files.onDidChangeReadonly(model => this._onDidChange.fire([model.resource]))); + this._register(this.files.onDidChangeOrphaned(model => this._onDidChange.fire([model.resource]))); + } + + provideDecorations(uri: URI): IDecorationData | undefined { + const model = this.files.get(uri); + if (!model) { + return undefined; + } + + const isReadonly = model.isReadonly(); + const isOrphaned = model.hasState(TextFileEditorModelState.ORPHAN); + + // Readonly + Orphaned + if (isReadonly && isOrphaned) { + return { + color: listErrorForeground, + letter: Codicon.lock, + tooltip: localize('readonlyAndDeleted', "Deleted, Read Only"), + }; + } + + // Readonly + else if (isReadonly) { + return { + letter: Codicon.lock, + tooltip: localize('readonly', "Read Only"), + }; + } + + // Orphaned + else if (isOrphaned) { + return { + color: listErrorForeground, + tooltip: localize('deleted', "Deleted"), + }; + } + + return undefined; + } + }(this.files)); + } + + //#endregin + //#region text file read / write / create private _encoding: EncodingOracle | undefined; diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index 4f466542c0b48..d7907191484f6 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -37,6 +37,12 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE private readonly _onDidChangeDirty = this._register(new Emitter()); readonly onDidChangeDirty = this._onDidChangeDirty.event; + private readonly _onDidChangeReadonly = this._register(new Emitter()); + readonly onDidChangeReadonly = this._onDidChangeReadonly.event; + + private readonly _onDidChangeOrphaned = this._register(new Emitter()); + readonly onDidChangeOrphaned = this._onDidChangeOrphaned.event; + private readonly _onDidSaveError = this._register(new Emitter()); readonly onDidSaveError = this._onDidSaveError.event; @@ -411,6 +417,8 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE const modelListeners = new DisposableStore(); modelListeners.add(model.onDidResolve(reason => this._onDidResolve.fire({ model, reason }))); modelListeners.add(model.onDidChangeDirty(() => this._onDidChangeDirty.fire(model))); + modelListeners.add(model.onDidChangeReadonly(() => this._onDidChangeReadonly.fire(model))); + modelListeners.add(model.onDidChangeOrphaned(() => this._onDidChangeOrphaned.fire(model))); modelListeners.add(model.onDidSaveError(() => this._onDidSaveError.fire(model))); modelListeners.add(model.onDidSave(reason => this._onDidSave.fire({ model, reason }))); modelListeners.add(model.onDidRevert(() => this._onDidRevert.fire(model))); diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 1d13ce8a563ba..160cfa0240285 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -335,6 +335,8 @@ export interface ITextFileEditorModelManager { readonly onDidCreate: Event; readonly onDidResolve: Event; readonly onDidChangeDirty: Event; + readonly onDidChangeReadonly: Event; + readonly onDidChangeOrphaned: Event; readonly onDidChangeEncoding: Event; readonly onDidSaveError: Event; readonly onDidSave: Event; diff --git a/src/vs/workbench/services/textfile/electron-sandbox/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-sandbox/nativeTextFileService.ts index f18d237f4f44d..985280a021856 100644 --- a/src/vs/workbench/services/textfile/electron-sandbox/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-sandbox/nativeTextFileService.ts @@ -26,6 +26,7 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { IElevatedFileService } from 'vs/workbench/services/files/common/elevatedFileService'; import { ILogService } from 'vs/platform/log/common/log'; import { Promises } from 'vs/base/common/async'; +import { IDecorationsService } from 'vs/workbench/services/decorations/common/decorations'; export class NativeTextFileService extends AbstractTextFileService { @@ -49,9 +50,10 @@ export class NativeTextFileService extends AbstractTextFileService { @IUriIdentityService uriIdentityService: IUriIdentityService, @IModeService modeService: IModeService, @IElevatedFileService elevatedFileService: IElevatedFileService, - @ILogService logService: ILogService + @ILogService logService: ILogService, + @IDecorationsService decorationsService: IDecorationsService ) { - super(fileService, untitledTextEditorService, lifecycleService, instantiationService, modelService, environmentService, dialogService, fileDialogService, textResourceConfigurationService, filesConfigurationService, textModelService, codeEditorService, pathService, workingCopyFileService, uriIdentityService, modeService, logService, elevatedFileService); + super(fileService, untitledTextEditorService, lifecycleService, instantiationService, modelService, environmentService, dialogService, fileDialogService, textResourceConfigurationService, filesConfigurationService, textModelService, codeEditorService, pathService, workingCopyFileService, uriIdentityService, modeService, logService, elevatedFileService, decorationsService); this.environmentService = environmentService; diff --git a/src/vs/workbench/services/workingCopy/common/fileWorkingCopyManager.ts b/src/vs/workbench/services/workingCopy/common/fileWorkingCopyManager.ts index af3b1828be8db..f8889727e8826 100644 --- a/src/vs/workbench/services/workingCopy/common/fileWorkingCopyManager.ts +++ b/src/vs/workbench/services/workingCopy/common/fileWorkingCopyManager.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { Event } from 'vs/base/common/event'; +import { Emitter, Event } from 'vs/base/common/event'; import { Promises } from 'vs/base/common/async'; import { VSBufferReadableStream } from 'vs/base/common/buffer'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -17,7 +17,7 @@ import { ISaveOptions } from 'vs/workbench/common/editor'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; -import { IStoredFileWorkingCopy, IStoredFileWorkingCopyModel, IStoredFileWorkingCopyModelFactory, IStoredFileWorkingCopyResolveOptions } from 'vs/workbench/services/workingCopy/common/storedFileWorkingCopy'; +import { IStoredFileWorkingCopy, IStoredFileWorkingCopyModel, IStoredFileWorkingCopyModelFactory, IStoredFileWorkingCopyResolveOptions, StoredFileWorkingCopyState } from 'vs/workbench/services/workingCopy/common/storedFileWorkingCopy'; import { StoredFileWorkingCopyManager, IStoredFileWorkingCopyManager, IStoredFileWorkingCopyManagerResolveOptions } from 'vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager'; import { IUntitledFileWorkingCopy, IUntitledFileWorkingCopyModel, IUntitledFileWorkingCopyModelFactory, UntitledFileWorkingCopy } from 'vs/workbench/services/workingCopy/common/untitledFileWorkingCopy'; import { INewOrExistingUntitledFileWorkingCopyOptions, INewUntitledFileWorkingCopyOptions, INewUntitledFileWorkingCopyWithAssociatedResourceOptions, IUntitledFileWorkingCopyManager, UntitledFileWorkingCopyManager } from 'vs/workbench/services/workingCopy/common/untitledFileWorkingCopyManager'; @@ -36,6 +36,9 @@ import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/com import { IWorkingCopyEditorService } from 'vs/workbench/services/workingCopy/common/workingCopyEditorService'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { Schemas } from 'vs/base/common/network'; +import { IDecorationData, IDecorationsProvider, IDecorationsService } from 'vs/workbench/services/decorations/common/decorations'; +import { Codicon } from 'vs/base/common/codicons'; +import { listErrorForeground } from 'vs/platform/theme/common/colorRegistry'; export interface IFileWorkingCopyManager extends IBaseFileWorkingCopyManager> { @@ -156,7 +159,8 @@ export class FileWorkingCopyManager>(this.stored.onDidCreate, this.untitled.onDidCreate); + + // Decorations + this.provideDecorations(); } + //#region decorations + + private provideDecorations(): void { + + // File working copy decorations + this.decorationsService.registerDecorationsProvider(new class extends Disposable implements IDecorationsProvider { + + readonly label = localize('fileWorkingCopyDecorations', "File Working Copy Decorations"); + + private readonly _onDidChange = this._register(new Emitter()); + readonly onDidChange = this._onDidChange.event; + + constructor(private readonly stored: IStoredFileWorkingCopyManager) { + super(); + + this.registerListeners(); + } + + private registerListeners(): void { + + // Creates + this._register(this.stored.onDidCreate(workingCopy => { + if (workingCopy.isReadonly() || workingCopy.hasState(StoredFileWorkingCopyState.ORPHAN)) { + this._onDidChange.fire([workingCopy.resource]); + } + })); + + // Changes + this._register(this.stored.onDidChangeReadonly(workingCopy => this._onDidChange.fire([workingCopy.resource]))); + this._register(this.stored.onDidChangeOrphaned(workingCopy => this._onDidChange.fire([workingCopy.resource]))); + } + + provideDecorations(uri: URI): IDecorationData | undefined { + const workingCopy = this.stored.get(uri); + if (!workingCopy) { + return undefined; + } + + const isReadonly = workingCopy.isReadonly(); + const isOrphaned = workingCopy.hasState(StoredFileWorkingCopyState.ORPHAN); + + // Readonly + Orphaned + if (isReadonly && isOrphaned) { + return { + color: listErrorForeground, + letter: Codicon.lock, + tooltip: localize('readonlyAndDeleted', "Deleted, Read Only"), + }; + } + + // Readonly + else if (isReadonly) { + return { + letter: Codicon.lock, + tooltip: localize('readonly', "Read Only"), + }; + } + + // Orphaned + else if (isOrphaned) { + return { + color: listErrorForeground, + tooltip: localize('deleted', "Deleted"), + }; + } + + return undefined; + } + }(this.stored)); + } + + //#endregin + //#region get / get all get workingCopies(): (IUntitledFileWorkingCopy | IStoredFileWorkingCopy)[] { diff --git a/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager.ts b/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager.ts index 2f73bb84fb5b9..fd7e4f917d1ad 100644 --- a/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager.ts +++ b/src/vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager.ts @@ -46,6 +46,16 @@ export interface IStoredFileWorkingCopyManager>; + /** + * An event for when a stored file working copy changed it's readonly state. + */ + readonly onDidChangeReadonly: Event>; + + /** + * An event for when a stored file working copy changed it's orphaned state. + */ + readonly onDidChangeOrphaned: Event>; + /** * An event for when a stored file working copy failed to save. */ @@ -127,6 +137,12 @@ export class StoredFileWorkingCopyManager private readonly _onDidChangeDirty = this._register(new Emitter>()); readonly onDidChangeDirty = this._onDidChangeDirty.event; + private readonly _onDidChangeReadonly = this._register(new Emitter>()); + readonly onDidChangeReadonly = this._onDidChangeReadonly.event; + + private readonly _onDidChangeOrphaned = this._register(new Emitter>()); + readonly onDidChangeOrphaned = this._onDidChangeOrphaned.event; + private readonly _onDidSaveError = this._register(new Emitter>()); readonly onDidSaveError = this._onDidSaveError.event; @@ -523,6 +539,8 @@ export class StoredFileWorkingCopyManager const workingCopyListeners = new DisposableStore(); workingCopyListeners.add(workingCopy.onDidResolve(() => this._onDidResolve.fire(workingCopy))); workingCopyListeners.add(workingCopy.onDidChangeDirty(() => this._onDidChangeDirty.fire(workingCopy))); + workingCopyListeners.add(workingCopy.onDidChangeReadonly(() => this._onDidChangeReadonly.fire(workingCopy))); + workingCopyListeners.add(workingCopy.onDidChangeOrphaned(() => this._onDidChangeOrphaned.fire(workingCopy))); workingCopyListeners.add(workingCopy.onDidSaveError(() => this._onDidSaveError.fire(workingCopy))); workingCopyListeners.add(workingCopy.onDidSave(reason => this._onDidSave.fire({ workingCopy: workingCopy, reason }))); workingCopyListeners.add(workingCopy.onDidRevert(() => this._onDidRevert.fire(workingCopy))); diff --git a/src/vs/workbench/services/workingCopy/test/browser/fileWorkingCopyManager.test.ts b/src/vs/workbench/services/workingCopy/test/browser/fileWorkingCopyManager.test.ts index 8e77ba71280e9..e16cc69fa70cc 100644 --- a/src/vs/workbench/services/workingCopy/test/browser/fileWorkingCopyManager.test.ts +++ b/src/vs/workbench/services/workingCopy/test/browser/fileWorkingCopyManager.test.ts @@ -37,7 +37,7 @@ suite('FileWorkingCopyManager', () => { accessor.workingCopyFileService, accessor.workingCopyBackupService, accessor.uriIdentityService, accessor.fileDialogService, accessor.filesConfigurationService, accessor.workingCopyService, accessor.notificationService, accessor.workingCopyEditorService, accessor.editorService, accessor.elevatedFileService, accessor.pathService, - accessor.environmentService, accessor.dialogService + accessor.environmentService, accessor.dialogService, accessor.decorationsService ); }); diff --git a/src/vs/workbench/services/workingCopy/test/browser/untitledFileWorkingCopyManager.test.ts b/src/vs/workbench/services/workingCopy/test/browser/untitledFileWorkingCopyManager.test.ts index 17d773fb5ef50..916f58a446b74 100644 --- a/src/vs/workbench/services/workingCopy/test/browser/untitledFileWorkingCopyManager.test.ts +++ b/src/vs/workbench/services/workingCopy/test/browser/untitledFileWorkingCopyManager.test.ts @@ -36,7 +36,7 @@ suite('UntitledFileWorkingCopyManager', () => { accessor.workingCopyFileService, accessor.workingCopyBackupService, accessor.uriIdentityService, accessor.fileDialogService, accessor.filesConfigurationService, accessor.workingCopyService, accessor.notificationService, accessor.workingCopyEditorService, accessor.editorService, accessor.elevatedFileService, accessor.pathService, - accessor.environmentService, accessor.dialogService + accessor.environmentService, accessor.dialogService, accessor.decorationsService ); }); @@ -277,7 +277,7 @@ suite('UntitledFileWorkingCopyManager', () => { accessor.workingCopyFileService, accessor.workingCopyBackupService, accessor.uriIdentityService, accessor.fileDialogService, accessor.filesConfigurationService, accessor.workingCopyService, accessor.notificationService, accessor.workingCopyEditorService, accessor.editorService, accessor.elevatedFileService, accessor.pathService, - accessor.environmentService, accessor.dialogService + accessor.environmentService, accessor.dialogService, accessor.decorationsService ); const untitled1OriginalType = await manager.untitled.resolve(); @@ -299,7 +299,7 @@ suite('UntitledFileWorkingCopyManager', () => { accessor.workingCopyFileService, accessor.workingCopyBackupService, accessor.uriIdentityService, accessor.fileDialogService, accessor.filesConfigurationService, accessor.workingCopyService, accessor.notificationService, accessor.workingCopyEditorService, accessor.editorService, accessor.elevatedFileService, accessor.pathService, - accessor.environmentService, accessor.dialogService + accessor.environmentService, accessor.dialogService, accessor.decorationsService ); const result = await manager.untitled.resolve(); diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 496e43de55a2d..6d80b89c7214b 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -303,7 +303,8 @@ export class TestServiceAccessor { @IWorkingCopyEditorService public workingCopyEditorService: IWorkingCopyEditorService, @IInstantiationService public instantiationService: IInstantiationService, @IElevatedFileService public elevatedFileService: IElevatedFileService, - @IWorkspaceTrustRequestService public workspaceTrustRequestService: TestWorkspaceTrustRequestService + @IWorkspaceTrustRequestService public workspaceTrustRequestService: TestWorkspaceTrustRequestService, + @IDecorationsService public decorationsService: IDecorationsService ) { } } @@ -330,7 +331,8 @@ export class TestTextFileService extends BrowserTextFileService { @IUriIdentityService uriIdentityService: IUriIdentityService, @IModeService modeService: IModeService, @ILogService logService: ILogService, - @IElevatedFileService elevatedFileService: IElevatedFileService + @IElevatedFileService elevatedFileService: IElevatedFileService, + @IDecorationsService decorationsService: IDecorationsService ) { super( fileService, @@ -350,7 +352,8 @@ export class TestTextFileService extends BrowserTextFileService { uriIdentityService, modeService, elevatedFileService, - logService + logService, + decorationsService ); } diff --git a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts index b5ee3efe90125..cd98feb5507b4 100644 --- a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts @@ -45,6 +45,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { getUserDataPath } from 'vs/platform/environment/node/userDataPath'; import product from 'vs/platform/product/common/product'; import { IElevatedFileService } from 'vs/workbench/services/files/common/elevatedFileService'; +import { IDecorationsService } from 'vs/workbench/services/decorations/common/decorations'; const args = parseArgs(process.argv, OPTIONS); @@ -90,7 +91,8 @@ export class TestTextFileService extends NativeTextFileService { @ILogService logService: ILogService, @IUriIdentityService uriIdentityService: IUriIdentityService, @IModeService modeService: IModeService, - @IElevatedFileService elevatedFileService: IElevatedFileService + @IElevatedFileService elevatedFileService: IElevatedFileService, + @IDecorationsService decorationsService: IDecorationsService ) { super( fileService, @@ -110,7 +112,8 @@ export class TestTextFileService extends NativeTextFileService { uriIdentityService, modeService, elevatedFileService, - logService + logService, + decorationsService ); }