diff --git a/src/vs/workbench/api/electron-browser/mainThreadCommands.ts b/src/vs/workbench/api/electron-browser/mainThreadCommands.ts index bea731ce497..17a107c894d 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadCommands.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadCommands.ts @@ -12,32 +12,34 @@ import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape } from '. export class MainThreadCommands extends MainThreadCommandsShape { - private _disposables: { [id: string]: IDisposable } = Object.create(null); - private _proxy: ExtHostCommandsShape; + private readonly _disposables = new Map(); + private readonly _proxy: ExtHostCommandsShape; constructor( - @IThreadService private _threadService: IThreadService, - @ICommandService private _commandService: ICommandService + @IThreadService private readonly _threadService: IThreadService, + @ICommandService private readonly _commandService: ICommandService ) { super(); this._proxy = this._threadService.get(ExtHostContext.ExtHostCommands); } dispose() { - for (let id in this._disposables) { - this._disposables[id].dispose(); - } + this._disposables.forEach(value => value.dispose()); + this._disposables.clear(); } $registerCommand(id: string): TPromise { - this._disposables[id] = CommandsRegistry.registerCommand(id, (accessor, ...args) => this._proxy.$executeContributedCommand(id, ...args)); + this._disposables.set( + id, + CommandsRegistry.registerCommand(id, (accessor, ...args) => this._proxy.$executeContributedCommand(id, ...args)) + ); return undefined; } $unregisterCommand(id: string): TPromise { - if (this._disposables[id]) { - this._disposables[id].dispose(); - delete this._disposables[id]; + if (this._disposables.has(id)) { + this._disposables.get(id).dispose(); + this._disposables.delete(id); } return undefined; } diff --git a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts index 6d3b48ea2bf..fd8d794be99 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadConfiguration.ts @@ -6,7 +6,7 @@ import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; @@ -14,8 +14,8 @@ import { MainThreadConfigurationShape, ExtHostContext } from '../node/extHost.pr export class MainThreadConfiguration extends MainThreadConfigurationShape { - private _configurationEditingService: IConfigurationEditingService; - private _toDispose: IDisposable; + private readonly _configurationEditingService: IConfigurationEditingService; + private readonly _configurationListener: IDisposable; constructor( @IConfigurationEditingService configurationEditingService: IConfigurationEditingService, @@ -26,13 +26,13 @@ export class MainThreadConfiguration extends MainThreadConfigurationShape { this._configurationEditingService = configurationEditingService; const proxy = threadService.get(ExtHostContext.ExtHostConfiguration); - this._toDispose = configurationService.onDidUpdateConfiguration(() => { + this._configurationListener = configurationService.onDidUpdateConfiguration(() => { proxy.$acceptConfigurationChanged(configurationService.getConfigurationData()); }); } public dispose(): void { - this._toDispose = dispose(this._toDispose); + this._configurationListener.dispose(); } $updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resource: URI): TPromise { diff --git a/src/vs/workbench/api/electron-browser/mainThreadDiagnostics.ts b/src/vs/workbench/api/electron-browser/mainThreadDiagnostics.ts index f0abcbb6486..a7e5e47b5fc 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDiagnostics.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDiagnostics.ts @@ -11,23 +11,30 @@ import { MainThreadDiagnosticsShape } from '../node/extHost.protocol'; export class MainThreadDiagnostics extends MainThreadDiagnosticsShape { - private _markerService: IMarkerService; + private readonly _activeOwners = new Set(); + private readonly _markerService: IMarkerService; constructor( @IMarkerService markerService: IMarkerService) { super(); this._markerService = markerService; } + dispose(): void { + this._activeOwners.forEach(owner => this._markerService.changeAll(owner, undefined)); + } + $changeMany(owner: string, entries: [URI, IMarkerData[]][]): TPromise { for (let entry of entries) { let [uri, markers] = entry; this._markerService.changeOne(owner, uri, markers); } + this._activeOwners.add(owner); return undefined; } $clear(owner: string): TPromise { this._markerService.changeAll(owner, undefined); + this._activeOwners.delete(owner); return undefined; } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadFileSystemEventService.ts b/src/vs/workbench/api/electron-browser/mainThreadFileSystemEventService.ts index 49022aacc7c..08bda384b6f 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadFileSystemEventService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadFileSystemEventService.ts @@ -7,9 +7,12 @@ import { FileChangeType, IFileService } from 'vs/platform/files/common/files'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { ExtHostContext, ExtHostFileSystemEventServiceShape, FileSystemEvents } from '../node/extHost.protocol'; +import { IDisposable } from "vs/base/common/lifecycle"; export class MainThreadFileSystemEventService { + private readonly _listener: IDisposable; + constructor( @IThreadService threadService: IThreadService, @IFileService fileService: IFileService @@ -22,7 +25,7 @@ export class MainThreadFileSystemEventService { deleted: [] }; - fileService.onFileChanges(event => { + this._listener = fileService.onFileChanges(event => { for (let change of event.changes) { switch (change.type) { case FileChangeType.ADDED: @@ -43,4 +46,8 @@ export class MainThreadFileSystemEventService { events.deleted.length = 0; }); } + + dispose(): void { + this._listener.dispose(); + } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts index 9bf2eb4763f..d3557ec1d11 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguageFeatures.ts @@ -43,6 +43,12 @@ export class MainThreadLanguageFeatures extends MainThreadLanguageFeaturesShape this._formatters = new Map(); } + dispose(): void { + for (const key in this._registrations) { + this._registrations[key].dispose(); + } + } + $unregister(handle: number): TPromise { let registration = this._registrations[handle]; if (registration) { diff --git a/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts b/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts index 994c9cf2afa..93e532a348c 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts @@ -13,11 +13,12 @@ import { MainThreadOutputServiceShape } from '../node/extHost.protocol'; export class MainThreadOutputService extends MainThreadOutputServiceShape { - private _outputService: IOutputService; - private _partService: IPartService; - private _panelService: IPanelService; + private readonly _outputService: IOutputService; + private readonly _partService: IPartService; + private readonly _panelService: IPanelService; - constructor( @IOutputService outputService: IOutputService, + constructor( + @IOutputService outputService: IOutputService, @IPartService partService: IPartService, @IPanelService panelService: IPanelService ) { diff --git a/src/vs/workbench/api/electron-browser/mainThreadProgress.ts b/src/vs/workbench/api/electron-browser/mainThreadProgress.ts index eb3242904e0..86e75c62868 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadProgress.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadProgress.ts @@ -11,7 +11,7 @@ import { MainThreadProgressShape } from '../node/extHost.protocol'; export class MainThreadProgress extends MainThreadProgressShape { private _progressService: IProgressService2; - private progress = new Map }>(); + private _progress = new Map }>(); constructor( @IProgressService2 progressService: IProgressService2 @@ -20,24 +20,29 @@ export class MainThreadProgress extends MainThreadProgressShape { this._progressService = progressService; } + dispose(): void { + this._progress.forEach(handle => handle.resolve()); + this._progress.clear(); + } + $startProgress(handle: number, options: IProgressOptions): void { const task = this._createTask(handle); this._progressService.withProgress(options, task); } $progressReport(handle: number, message: IProgressStep): void { - this.progress.get(handle).progress.report(message); + this._progress.get(handle).progress.report(message); } $progressEnd(handle: number): void { - this.progress.get(handle).resolve(); - this.progress.delete(handle); + this._progress.get(handle).resolve(); + this._progress.delete(handle); } private _createTask(handle: number) { return (progress: IProgress) => { return new TPromise(resolve => { - this.progress.set(handle, { resolve, progress }); + this._progress.set(handle, { resolve, progress }); }); }; } diff --git a/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts index b1de2a035c9..3a990a5f89e 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts @@ -240,6 +240,11 @@ export class SaveParticipant implements ISaveParticipant { // Hook into model TextFileEditorModel.setSaveParticipant(this); } + + dispose(): void { + TextFileEditorModel.setSaveParticipant(undefined); + } + participate(model: ITextFileEditorModel, env: { reason: SaveReason }): TPromise { const stats: { [name: string]: number } = Object.create(null); diff --git a/src/vs/workbench/api/electron-browser/mainThreadStatusBar.ts b/src/vs/workbench/api/electron-browser/mainThreadStatusBar.ts index 55533e132ab..d6f8b022136 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadStatusBar.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadStatusBar.ts @@ -10,13 +10,20 @@ import { MainThreadStatusBarShape } from '../node/extHost.protocol'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; export class MainThreadStatusBar extends MainThreadStatusBarShape { - private mapIdToDisposable: { [id: number]: IDisposable }; + + private readonly _entries: { [id: number]: IDisposable }; constructor( - @IStatusbarService private statusbarService: IStatusbarService + @IStatusbarService private readonly _statusbarService: IStatusbarService ) { super(); - this.mapIdToDisposable = Object.create(null); + this._entries = Object.create(null); + } + + dispose(): void { + for (const key in this._entries) { + this._entries[key].dispose(); + } } $setEntry(id: number, extensionId: string, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void { @@ -25,16 +32,16 @@ export class MainThreadStatusBar extends MainThreadStatusBarShape { this.$dispose(id); // Add new - let disposeable = this.statusbarService.addEntry({ text, tooltip, command, color, extensionId }, alignment, priority); - this.mapIdToDisposable[id] = disposeable; + let entry = this._statusbarService.addEntry({ text, tooltip, command, color, extensionId }, alignment, priority); + this._entries[id] = entry; } $dispose(id: number) { - let disposeable = this.mapIdToDisposable[id]; + let disposeable = this._entries[id]; if (disposeable) { disposeable.dispose(); } - delete this.mapIdToDisposable[id]; + delete this._entries[id]; } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index 84b65bafdba..ff08df00bba 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -17,7 +17,7 @@ import { MainThreadWorkspaceShape, ExtHostWorkspaceShape, ExtHostContext } from import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IFileService } from 'vs/platform/files/common/files'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { RemoteFileService, IRemoteFileSystemProvider } from 'vs/workbench/services/files/electron-browser/remoteFileService'; import { Emitter } from 'vs/base/common/event'; @@ -42,6 +42,10 @@ export class MainThreadWorkspace extends MainThreadWorkspaceShape { this._contextService.onDidChangeWorkspaceRoots(this._onDidChangeWorkspace, this, this._toDispose); } + dispose(): void { + dispose(this._toDispose); + } + // --- workspace --- private _onDidChangeWorkspace(): void { diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadCommands.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadCommands.test.ts index 616043909a0..144bc7665b8 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadCommands.test.ts @@ -25,4 +25,21 @@ suite('MainThreadCommands', function () { commands.$unregisterCommand('foo'); assert.equal(CommandsRegistry.getCommand('foo'), undefined); }); + + test('unregister all on dispose', function () { + + const commands = new MainThreadCommands(OneGetThreadService(null), undefined); + assert.equal(CommandsRegistry.getCommand('foo'), undefined); + + commands.$registerCommand('foo'); + commands.$registerCommand('bar'); + + assert.ok(CommandsRegistry.getCommand('foo')); + assert.ok(CommandsRegistry.getCommand('bar')); + + commands.dispose(); + + assert.equal(CommandsRegistry.getCommand('foo'), undefined); + assert.equal(CommandsRegistry.getCommand('bar'), undefined); + }); }); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadDiagnostics.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadDiagnostics.test.ts new file mode 100644 index 00000000000..0eb08419eec --- /dev/null +++ b/src/vs/workbench/test/electron-browser/api/mainThreadDiagnostics.test.ts @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as assert from 'assert'; +import { MarkerService } from "vs/platform/markers/common/markerService"; +import { MainThreadDiagnostics } from "vs/workbench/api/electron-browser/mainThreadDiagnostics"; +import URI from "vs/base/common/uri"; + + +suite('MainThreadDiagnostics', function () { + + let markerService: MarkerService; + + setup(function () { + markerService = new MarkerService(); + }); + + test('clear markers on dispose', function () { + + let diag = new MainThreadDiagnostics(markerService); + + diag.$changeMany('foo', [[URI.file('a'), [{ + code: '666', + startLineNumber: 1, + startColumn: 1, + endLineNumber: 1, + endColumn: 1, + message: 'fffff', + severity: 1, + source: 'me' + }]]]); + + assert.equal(markerService.read().length, 1); + diag.dispose(); + assert.equal(markerService.read().length, 0); + }); +});