diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index cde13b00f2c..6e7d60942b4 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -7,7 +7,7 @@ import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { IDecorationsService, IDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IDecorationData } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; -import { Disposable, IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { isThenable } from 'vs/base/common/async'; import { LinkedList } from 'vs/base/common/linkedList'; import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom'; @@ -19,6 +19,7 @@ import { localize } from 'vs/nls'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILogService } from 'vs/platform/log/common/log'; class DecorationRule { @@ -96,25 +97,21 @@ class DecorationRule { } } -class DecorationStyles extends Disposable { +class DecorationStyles { private readonly _styleElement = createStyleSheet(); private readonly _decorationRules = new Map(); + private readonly _dispoables = new DisposableStore(); constructor( private _themeService: IThemeService, ) { - super(); - this._register(this._themeService.onThemeChange(this._onThemeChange, this)); + this._themeService.onThemeChange(this._onThemeChange, this, this._dispoables); } dispose(): void { - super.dispose(); - - const parent = this._styleElement.parentElement; - if (parent) { - parent.removeChild(this._styleElement); - } + this._dispoables.dispose(); + this._styleElement.remove(); } asDecoration(data: IDecorationData[], onlyChildren: boolean): IDecoration { @@ -224,11 +221,11 @@ class DecorationProviderWrapper { private readonly _dispoable: IDisposable; constructor( - private readonly _provider: IDecorationsProvider, + readonly provider: IDecorationsProvider, private readonly _uriEmitter: Emitter, private readonly _flushEmitter: Emitter ) { - this._dispoable = this._provider.onDidChange(uris => { + this._dispoable = this.provider.onDidChange(uris => { if (!uris) { // flush event -> drop all data, can affect everything this.data.clear(); @@ -292,7 +289,7 @@ class DecorationProviderWrapper { } const source = new CancellationTokenSource(); - const dataOrThenable = this._provider.provideDecorations(uri, source.token); + const dataOrThenable = this.provider.provideDecorations(uri, source.token); if (!isThenable | undefined>(dataOrThenable)) { // sync -> we have a result now return this._keepItem(uri, dataOrThenable); @@ -325,7 +322,7 @@ class DecorationProviderWrapper { } } -export class FileDecorationsService implements IDecorationsService { +export class DecorationsService implements IDecorationsService { _serviceBrand: undefined; @@ -333,7 +330,6 @@ export class FileDecorationsService implements IDecorationsService { private readonly _onDidChangeDecorationsDelayed = new Emitter(); private readonly _onDidChangeDecorations = new Emitter(); private readonly _decorationStyles: DecorationStyles; - private readonly _disposables: IDisposable[]; readonly onDidChangeDecorations: Event = Event.any( this._onDidChangeDecorations.event, @@ -345,29 +341,25 @@ export class FileDecorationsService implements IDecorationsService { ); constructor( - @IThemeService themeService: IThemeService + @IThemeService themeService: IThemeService, + @ILogService private readonly _logService: ILogService, ) { this._decorationStyles = new DecorationStyles(themeService); // every so many events we check if there are // css styles that we don't need anymore let count = 0; - let reg = this.onDidChangeDecorations(() => { + this.onDidChangeDecorations(() => { if (++count % 17 === 0) { this._decorationStyles.cleanUp(this._data.iterator()); } }); - - this._disposables = [ - reg, - this._decorationStyles - ]; } dispose(): void { - dispose(this._disposables); - dispose(this._onDidChangeDecorations); - dispose(this._onDidChangeDecorationsDelayed); + this._decorationStyles.dispose(); + this._onDidChangeDecorations.dispose(); + this._onDidChangeDecorationsDelayed.dispose(); } registerDecorationsProvider(provider: IDecorationsProvider): IDisposable { @@ -397,10 +389,12 @@ export class FileDecorationsService implements IDecorationsService { let data: IDecorationData[] = []; let containsChildren: boolean = false; for (let iter = this._data.iterator(), next = iter.next(); !next.done; next = iter.next()) { + const { label } = next.value.provider; next.value.getOrRetrieve(uri, includeChildren, (deco, isChild) => { if (!isChild || deco.bubble) { data.push(deco); containsChildren = isChild || containsChildren; + this._logService.trace('DecorationsService#getDecoration#getOrRetrieve', label, deco, isChild, uri); } }); } @@ -420,4 +414,4 @@ function getColor(theme: ITheme, color: string | undefined) { return 'inherit'; } -registerSingleton(IDecorationsService, FileDecorationsService); +registerSingleton(IDecorationsService, DecorationsService, true); diff --git a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts index 6975f0b64d3..2f1298ea85b 100644 --- a/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts +++ b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts @@ -4,22 +4,23 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; +import { DecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; import { IDecorationsProvider, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { ConsoleLogService } from 'vs/platform/log/common/log'; suite('DecorationsService', function () { - let service: FileDecorationsService; + let service: DecorationsService; setup(function () { if (service) { service.dispose(); } - service = new FileDecorationsService(new TestThemeService()); + service = new DecorationsService(new TestThemeService(), new ConsoleLogService()); }); test('Async provider, async/evented result', function () {