From 0ecbfa0fc185f6e6f98ba4c5fe2c5de3918b0060 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 25 Jun 2018 16:27:07 +0200 Subject: [PATCH] explorer decoration provider refactor fixes #50866 --- .../parts/files/common/explorerModel.ts | 17 ++++++++++------- .../views/explorerDecorationsProvider.ts | 18 +++++++++++++++--- .../electron-browser/views/explorerView.ts | 14 ++++++++++---- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/parts/files/common/explorerModel.ts b/src/vs/workbench/parts/files/common/explorerModel.ts index 4b72173d75a..bdb52e71e26 100644 --- a/src/vs/workbench/parts/files/common/explorerModel.ts +++ b/src/vs/workbench/parts/files/common/explorerModel.ts @@ -74,11 +74,12 @@ export class ExplorerItem { private _isSymbolicLink: boolean; private _isReadonly: boolean; private children: Map; + private _isError: boolean; public parent: ExplorerItem; public isDirectoryResolved: boolean; - constructor(resource: URI, public root: ExplorerItem, isSymbolicLink?: boolean, isReadonly?: boolean, isDirectory?: boolean, name: string = resources.basenameOrAuthority(resource), mtime?: number, etag?: string) { + constructor(resource: URI, public root: ExplorerItem, isSymbolicLink?: boolean, isReadonly?: boolean, isDirectory?: boolean, name: string = resources.basenameOrAuthority(resource), mtime?: number, etag?: string, isError?: boolean) { this.resource = resource; this._name = name; this.isDirectory = !!isDirectory; @@ -86,6 +87,7 @@ export class ExplorerItem { this._isReadonly = !!isReadonly; this.etag = etag; this.mtime = mtime; + this._isError = !!isError; if (!this.root) { this.root = this; @@ -106,6 +108,10 @@ export class ExplorerItem { return this._isReadonly; } + public get isError(): boolean { + return this._isError; + } + public set isDirectory(value: boolean) { if (value !== this._isDirectory) { this._isDirectory = value; @@ -118,10 +124,6 @@ export class ExplorerItem { } - public get nonexistentRoot(): boolean { - return this.isRoot && !this.isDirectoryResolved && this.isDirectory; - } - public get name(): string { return this._name; } @@ -145,8 +147,8 @@ export class ExplorerItem { return this === this.root; } - public static create(raw: IFileStat, root: ExplorerItem, resolveTo?: URI[]): ExplorerItem { - const stat = new ExplorerItem(raw.resource, root, raw.isSymbolicLink, raw.isReadonly, raw.isDirectory, raw.name, raw.mtime, raw.etag); + public static create(raw: IFileStat, root: ExplorerItem, resolveTo?: URI[], isError = false): ExplorerItem { + const stat = new ExplorerItem(raw.resource, root, raw.isSymbolicLink, raw.isReadonly, raw.isDirectory, raw.name, raw.mtime, raw.etag, isError); // Recursively add children if present if (stat.isDirectory) { @@ -195,6 +197,7 @@ export class ExplorerItem { local.isDirectoryResolved = disk.isDirectoryResolved; local._isSymbolicLink = disk.isSymbolicLink; local._isReadonly = disk.isReadonly; + local._isError = disk.isError; // Merge Children if resolved if (mergingDirectories && disk.isDirectoryResolved) { diff --git a/src/vs/workbench/parts/files/electron-browser/views/explorerDecorationsProvider.ts b/src/vs/workbench/parts/files/electron-browser/views/explorerDecorationsProvider.ts index dcbb387a155..9740c47831b 100644 --- a/src/vs/workbench/parts/files/electron-browser/views/explorerDecorationsProvider.ts +++ b/src/vs/workbench/parts/files/electron-browser/views/explorerDecorationsProvider.ts @@ -12,27 +12,35 @@ import { Model } from 'vs/workbench/parts/files/common/explorerModel'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import { listInvalidItemForeground } from 'vs/platform/theme/common/colorRegistry'; +import { IDisposable } from 'vscode-xterm'; +import { dispose } from 'vs/base/common/lifecycle'; export class ExplorerDecorationsProvider implements IDecorationsProvider { readonly label: string = localize('label', "Explorer"); private _onDidChange = new Emitter(); + private toDispose: IDisposable[]; constructor( private model: Model, @IWorkspaceContextService contextService: IWorkspaceContextService ) { - contextService.onDidChangeWorkspaceFolders(e => { + this.toDispose = []; + this.toDispose.push(contextService.onDidChangeWorkspaceFolders(e => { this._onDidChange.fire(e.changed.concat(e.added).map(wf => wf.uri)); - }); + })); } get onDidChange(): Event { return this._onDidChange.event; } + changed(uris: URI[]): void { + this._onDidChange.fire(uris); + } + provideDecorations(resource: URI): IDecorationData { const fileStat = this.model.findClosest(resource); - if (fileStat && fileStat.nonexistentRoot) { + if (fileStat && fileStat.isRoot && fileStat.isError) { return { tooltip: localize('canNotResolve', "Can not resolve workspace folder"), letter: '!', @@ -48,4 +56,8 @@ export class ExplorerDecorationsProvider implements IDecorationsProvider { return undefined; } + + dispose(): IDisposable[] { + return dispose(this.toDispose); + } } diff --git a/src/vs/workbench/parts/files/electron-browser/views/explorerView.ts b/src/vs/workbench/parts/files/electron-browser/views/explorerView.ts index b471abb1017..cadc88c5131 100644 --- a/src/vs/workbench/parts/files/electron-browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/electron-browser/views/explorerView.ts @@ -78,6 +78,7 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView private settings: object; private treeContainer: HTMLElement; private dragHandler: DelayedDragHandler; + private decorationProvider: ExplorerDecorationsProvider; private isDisposed: boolean; constructor( @@ -114,7 +115,9 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView (event: IConfigurationChangeEvent) => event.affectsConfiguration(FILES_EXCLUDE_CONFIG) ); - decorationService.registerDecorationsProvider(new ExplorerDecorationsProvider(this.model, contextService)); + this.decorationProvider = new ExplorerDecorationsProvider(this.model, contextService); + decorationService.registerDecorationsProvider(this.decorationProvider); + this.disposables.push(this.decorationProvider); } private getFileEventsExcludes(root?: URI): glob.IExpression { @@ -782,7 +785,10 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView }); } - const promise = this.resolveRoots(targetsToResolve, targetsToExpand); + const promise = this.resolveRoots(targetsToResolve, targetsToExpand).then(result => { + this.decorationProvider.changed(targetsToResolve.map(t => t.root.resource)); + return result; + }); this.progressService.showWhile(promise, this.partService.isCreated() ? 800 : 3200 /* less ugly initial startup */); return promise; @@ -798,7 +804,7 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView mtime: 0, etag: undefined, isDirectory: true - }, root); + }, root, undefined, true); const setInputAndExpand = (input: ExplorerItem | Model, statsToExpand: ExplorerItem[]) => { // Make sure to expand all folders that where expanded in the previous session @@ -842,7 +848,7 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView let delayer = new Delayer(100); let delayerPromise: TPromise; return TPromise.join(targetsToResolve.map((target, index) => this.fileService.resolveFile(target.resource, target.options) - .then(result => result.isDirectory ? ExplorerItem.create(result, target.root, target.options.resolveTo) : errorFileStat(target.resource, target.root), err => errorFileStat(target.resource, target.root)) + .then(result => result.isDirectory ? ExplorerItem.create(result, target.root, target.options.resolveTo) : errorFileStat(target.resource, target.root), () => errorFileStat(target.resource, target.root)) .then(modelStat => { // Subsequent refresh: Merge stat into our local model and refresh tree if (index < this.model.roots.length) { -- GitLab