diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 7ea36f61d15..b3cc40b3eee 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -5,7 +5,7 @@ import 'vs/css!./list'; import { localize } from 'vs/nls'; -import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { isNumber } from 'vs/base/common/types'; import { range, firstIndex, binarySearch } from 'vs/base/common/arrays'; import { memoize } from 'vs/base/common/decorators'; @@ -226,8 +226,9 @@ function isInputElement(e: HTMLElement): boolean { return e.tagName === 'INPUT' || e.tagName === 'TEXTAREA'; } -class KeyboardController extends Disposable { +class KeyboardController implements IDisposable { + private disposables: IDisposable[]; private openController: IOpenController; constructor( @@ -235,8 +236,8 @@ class KeyboardController extends Disposable { private view: ListView, options: IListOptions ) { - super(); const multipleSelectionSupport = !(options.multipleSelectionSupport === false); + this.disposables = []; this.openController = options.openController || DefaultOpenController; @@ -244,15 +245,15 @@ class KeyboardController extends Disposable { .filter(e => !isInputElement(e.target as HTMLElement)) .map(e => new StandardKeyboardEvent(e)); - this._register(onKeyDown.filter(e => e.keyCode === KeyCode.Enter).on(this.onEnter, this)); - this._register(onKeyDown.filter(e => e.keyCode === KeyCode.UpArrow).on(this.onUpArrow, this)); - this._register(onKeyDown.filter(e => e.keyCode === KeyCode.DownArrow).on(this.onDownArrow, this)); - this._register(onKeyDown.filter(e => e.keyCode === KeyCode.PageUp).on(this.onPageUpArrow, this)); - this._register(onKeyDown.filter(e => e.keyCode === KeyCode.PageDown).on(this.onPageDownArrow, this)); - this._register(onKeyDown.filter(e => e.keyCode === KeyCode.Escape).on(this.onEscape, this)); + onKeyDown.filter(e => e.keyCode === KeyCode.Enter).on(this.onEnter, this, this.disposables); + onKeyDown.filter(e => e.keyCode === KeyCode.UpArrow).on(this.onUpArrow, this, this.disposables); + onKeyDown.filter(e => e.keyCode === KeyCode.DownArrow).on(this.onDownArrow, this, this.disposables); + onKeyDown.filter(e => e.keyCode === KeyCode.PageUp).on(this.onPageUpArrow, this, this.disposables); + onKeyDown.filter(e => e.keyCode === KeyCode.PageDown).on(this.onPageDownArrow, this, this.disposables); + onKeyDown.filter(e => e.keyCode === KeyCode.Escape).on(this.onEscape, this, this.disposables); if (multipleSelectionSupport) { - this._register(onKeyDown.filter(e => (platform.isMacintosh ? e.metaKey : e.ctrlKey) && e.keyCode === KeyCode.KEY_A).on(this.onCtrlA, this)); + onKeyDown.filter(e => (platform.isMacintosh ? e.metaKey : e.ctrlKey) && e.keyCode === KeyCode.KEY_A).on(this.onCtrlA, this, this.disposables); } } @@ -311,6 +312,10 @@ class KeyboardController extends Disposable { this.list.setSelection([], e.browserEvent); this.view.domNode.focus(); } + + dispose() { + this.disposables = dispose(this.disposables); + } } enum TypeLabelControllerState { diff --git a/src/vs/code/electron-main/auth.ts b/src/vs/code/electron-main/auth.ts index d6023519555..ed92533c32f 100644 --- a/src/vs/code/electron-main/auth.ts +++ b/src/vs/code/electron-main/auth.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; import { Event } from 'vs/base/common/event'; import { BrowserWindow, app } from 'electron'; @@ -22,18 +22,18 @@ type Credentials = { password: string; }; -export class ProxyAuthHandler extends Disposable { +export class ProxyAuthHandler { _serviceBrand: any; private retryCount = 0; + private disposables: IDisposable[] = []; constructor( @IWindowsMainService private readonly windowsMainService: IWindowsMainService ) { - super(); const onLogin = Event.fromNodeEventEmitter(app, 'login', (event, webContents, req, authInfo, cb) => ({ event, webContents, req, authInfo, cb })); - this._register(onLogin(this.onLogin, this)); + onLogin(this.onLogin, this, this.disposables); } private onLogin({ event, authInfo, cb }: LoginEvent): void { @@ -85,4 +85,8 @@ export class ProxyAuthHandler extends Disposable { win.close(); }); } + + dispose(): void { + this.disposables = dispose(this.disposables); + } } \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts index 607177aa4e5..3f5cb8f648e 100644 --- a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts +++ b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/gotoErrorWidget'; import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; -import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { IMarker, MarkerSeverity, IRelatedInformation } from 'vs/platform/markers/common/markers'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; @@ -28,7 +28,7 @@ import { peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/ import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; -class MessageWidget extends Disposable { +class MessageWidget { private _lines: number = 0; private _longestLineLength: number = 0; @@ -38,9 +38,9 @@ class MessageWidget extends Disposable { private readonly _relatedBlock: HTMLDivElement; private readonly _scrollable: ScrollableElement; private readonly _relatedDiagnostics = new WeakMap(); + private readonly _disposables: IDisposable[] = []; constructor(parent: HTMLElement, editor: ICodeEditor, onRelatedInformation: (related: IRelatedInformation) => void) { - super(); this._editor = editor; const domNode = document.createElement('div'); @@ -54,7 +54,7 @@ class MessageWidget extends Disposable { this._relatedBlock = document.createElement('div'); domNode.appendChild(this._relatedBlock); - this._register(dom.addStandardDisposableListener(this._relatedBlock, 'click', event => { + this._disposables.push(dom.addStandardDisposableListener(this._relatedBlock, 'click', event => { event.preventDefault(); const related = this._relatedDiagnostics.get(event.target); if (related) { @@ -70,11 +70,15 @@ class MessageWidget extends Disposable { verticalScrollbarSize: 3 }); parent.appendChild(this._scrollable.getDomNode()); - this._register(this._scrollable.onScroll(e => { + this._disposables.push(this._scrollable.onScroll(e => { domNode.style.left = `-${e.scrollLeft}px`; domNode.style.top = `-${e.scrollTop}px`; })); - this._register(this._scrollable); + this._disposables.push(this._scrollable); + } + + dispose(): void { + dispose(this._disposables); } update({ source, message, relatedInformation, code }: IMarker): void { diff --git a/src/vs/editor/contrib/rename/renameInputField.ts b/src/vs/editor/contrib/rename/renameInputField.ts index 77028d23d80..b1dce91bfc7 100644 --- a/src/vs/editor/contrib/rename/renameInputField.ts +++ b/src/vs/editor/contrib/rename/renameInputField.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import 'vs/css!./renameInputField'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; @@ -16,7 +16,7 @@ import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; export const CONTEXT_RENAME_INPUT_VISIBLE = new RawContextKey('renameInputVisible', false); -export class RenameInputField extends Disposable implements IContentWidget { +export class RenameInputField implements IContentWidget, IDisposable { private _editor: ICodeEditor; private _position: Position; @@ -24,6 +24,7 @@ export class RenameInputField extends Disposable implements IContentWidget { private _inputField: HTMLInputElement; private _visible: boolean; private readonly _visibleContextKey: IContextKey; + private _disposables: IDisposable[] = []; // Editor.IContentWidget.allowEditorOverflow public allowEditorOverflow: boolean = true; @@ -33,19 +34,18 @@ export class RenameInputField extends Disposable implements IContentWidget { private readonly themeService: IThemeService, contextKeyService: IContextKeyService, ) { - super(); this._visibleContextKey = CONTEXT_RENAME_INPUT_VISIBLE.bindTo(contextKeyService); this._editor = editor; this._editor.addContentWidget(this); - this._register(editor.onDidChangeConfiguration(e => { + this._disposables.push(editor.onDidChangeConfiguration(e => { if (e.fontInfo) { this.updateFont(); } })); - this._register(themeService.onThemeChange(theme => this.onThemeChange(theme))); + this._disposables.push(themeService.onThemeChange(theme => this.onThemeChange(theme))); } private onThemeChange(theme: ITheme): void { @@ -53,7 +53,7 @@ export class RenameInputField extends Disposable implements IContentWidget { } public dispose(): void { - super.dispose(); + this._disposables = dispose(this._disposables); this._editor.removeContentWidget(this); } @@ -138,9 +138,9 @@ export class RenameInputField extends Disposable implements IContentWidget { this._inputField.setAttribute('selectionEnd', selectionEnd.toString()); this._inputField.size = Math.max((where.endColumn - where.startColumn) * 1.1, 20); - const disposeOnDone = new DisposableStore(); + const disposeOnDone: IDisposable[] = []; const always = () => { - disposeOnDone.dispose(); + dispose(disposeOnDone); this._hide(); }; @@ -172,8 +172,8 @@ export class RenameInputField extends Disposable implements IContentWidget { } }; - disposeOnDone.add(this._editor.onDidChangeCursorSelection(onCursorChanged)); - disposeOnDone.add(this._editor.onDidBlurEditorWidget(() => this.cancelInput(false))); + disposeOnDone.push(this._editor.onDidChangeCursorSelection(onCursorChanged)); + disposeOnDone.push(this._editor.onDidBlurEditorWidget(() => this.cancelInput(false))); this._show(); diff --git a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts index 7075aceb641..ba0789bf893 100644 --- a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts +++ b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { isNonEmptyArray } from 'vs/base/common/arrays'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ISelectedSuggestion, SuggestWidget } from './suggestWidget'; import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; -export class CommitCharacterController extends Disposable { +export class CommitCharacterController { + + private _disposables: IDisposable[] = []; private _active?: { readonly acceptCharacters: CharacterSet; @@ -17,13 +19,12 @@ export class CommitCharacterController extends Disposable { }; constructor(editor: ICodeEditor, widget: SuggestWidget, accept: (selected: ISelectedSuggestion) => any) { - super(); - this._register(widget.onDidShow(() => this._onItem(widget.getFocusedItem()))); - this._register(widget.onDidFocus(this._onItem, this)); - this._register(widget.onDidHide(this.reset, this)); + this._disposables.push(widget.onDidShow(() => this._onItem(widget.getFocusedItem()))); + this._disposables.push(widget.onDidFocus(this._onItem, this)); + this._disposables.push(widget.onDidHide(this.reset, this)); - this._register(editor.onWillType(text => { + this._disposables.push(editor.onWillType(text => { if (this._active) { const ch = text.charCodeAt(text.length - 1); if (this._active.acceptCharacters.has(ch) && editor.getConfiguration().contribInfo.acceptSuggestionOnCommitCharacter) { @@ -51,4 +52,8 @@ export class CommitCharacterController extends Disposable { reset(): void { this._active = undefined; } + + dispose() { + dispose(this._disposables); + } } diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index 76b83ec0c7a..d267a41ca4e 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -7,7 +7,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { onUnexpectedError } from 'vs/base/common/errors'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { dispose, IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, EditorCommand, registerEditorAction, registerEditorCommand, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { EditOperation } from 'vs/editor/common/core/editOperation'; @@ -34,7 +34,7 @@ import { IdleValue } from 'vs/base/common/async'; import { isObject } from 'vs/base/common/types'; import { CommitCharacterController } from './suggestCommitCharacters'; -export class SuggestController extends Disposable implements IEditorContribution { +export class SuggestController implements IEditorContribution { private static readonly ID: string = 'editor.contrib.suggestController'; @@ -45,6 +45,7 @@ export class SuggestController extends Disposable implements IEditorContribution private readonly _model: SuggestModel; private readonly _widget: IdleValue; private readonly _alternatives: IdleValue; + private _toDispose: IDisposable[] = []; private readonly _sticky = false; // for development purposes only @@ -56,28 +57,29 @@ export class SuggestController extends Disposable implements IEditorContribution @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { - super(); this._model = new SuggestModel(this._editor, editorWorker); this._widget = new IdleValue(() => { const widget = this._instantiationService.createInstance(SuggestWidget, this._editor); - this._register(widget); - this._register(widget.onDidSelect(item => this._insertSuggestion(item, false, true), this)); + this._toDispose.push(widget); + this._toDispose.push(widget.onDidSelect(item => this._insertSuggestion(item, false, true), this)); // Wire up logic to accept a suggestion on certain characters - const commitCharacterController = this._register(new CommitCharacterController(this._editor, widget, item => this._insertSuggestion(item, false, true))); - this._register(this._model.onDidSuggest(e => { - if (e.completionModel.items.length === 0) { - commitCharacterController.reset(); - } - }) + const commitCharacterController = new CommitCharacterController(this._editor, widget, item => this._insertSuggestion(item, false, true)); + this._toDispose.push( + commitCharacterController, + this._model.onDidSuggest(e => { + if (e.completionModel.items.length === 0) { + commitCharacterController.reset(); + } + }) ); // Wire up makes text edit context key let makesTextEdit = SuggestContext.MakesTextEdit.bindTo(this._contextKeyService); - this._register(widget.onDidFocus(({ item }) => { + this._toDispose.push(widget.onDidFocus(({ item }) => { const position = this._editor.getPosition()!; const startColumn = item.completion.range.startColumn; @@ -101,36 +103,36 @@ export class SuggestController extends Disposable implements IEditorContribution } makesTextEdit.set(value); })); - this._register(toDisposable(() => { - makesTextEdit.reset(); - })); + this._toDispose.push({ + dispose() { makesTextEdit.reset(); } + }); return widget; }); this._alternatives = new IdleValue(() => { let res = new SuggestAlternatives(this._editor, this._contextKeyService); - this._register(res); + this._toDispose.push(res); return res; }); - this._register(_instantiationService.createInstance(WordContextKey, _editor)); + this._toDispose.push(_instantiationService.createInstance(WordContextKey, _editor)); - this._register(this._model.onDidTrigger(e => { + this._toDispose.push(this._model.onDidTrigger(e => { this._widget.getValue().showTriggered(e.auto, e.shy ? 250 : 50); })); - this._register(this._model.onDidSuggest(e => { + this._toDispose.push(this._model.onDidSuggest(e => { if (!e.shy) { let index = this._memoryService.select(this._editor.getModel()!, this._editor.getPosition()!, e.completionModel.items); this._widget.getValue().showSuggestions(e.completionModel, index, e.isFrozen, e.auto); } })); - this._register(this._model.onDidCancel(e => { + this._toDispose.push(this._model.onDidCancel(e => { if (this._widget && !e.retrigger) { this._widget.getValue().hideWidget(); } })); - this._register(this._editor.onDidBlurEditorWidget(() => { + this._toDispose.push(this._editor.onDidBlurEditorWidget(() => { if (!this._sticky) { this._model.cancel(); } @@ -142,7 +144,7 @@ export class SuggestController extends Disposable implements IEditorContribution const { acceptSuggestionOnEnter } = this._editor.getConfiguration().contribInfo; acceptSuggestionsOnEnter.set(acceptSuggestionOnEnter === 'on' || acceptSuggestionOnEnter === 'smart'); }; - this._register(this._editor.onDidChangeConfiguration((e) => updateFromConfig())); + this._toDispose.push(this._editor.onDidChangeConfiguration((e) => updateFromConfig())); updateFromConfig(); } @@ -152,7 +154,7 @@ export class SuggestController extends Disposable implements IEditorContribution } dispose(): void { - super.dispose(); + this._toDispose = dispose(this._toDispose); this._widget.dispose(); if (this._model) { this._model.dispose(); diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 265ccca9ab8..0c0fbb66f0a 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -9,7 +9,7 @@ import { createMatches } from 'vs/base/common/filters'; import * as strings from 'vs/base/common/strings'; import { Event, Emitter } from 'vs/base/common/event'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { IDisposable, dispose, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass, addDisposableListener } from 'vs/base/browser/dom'; import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list'; import { List } from 'vs/base/browser/ui/list/listWidget'; @@ -228,7 +228,7 @@ const enum State { Details } -class SuggestionDetails extends Disposable { +class SuggestionDetails { private el: HTMLElement; private close: HTMLElement; @@ -238,7 +238,8 @@ class SuggestionDetails extends Disposable { private type: HTMLElement; private docs: HTMLElement; private ariaLabel: string | null; - private readonly renderDisposeable = this._register(new DisposableStore()); + private disposables: IDisposable[]; + private renderDisposeable: IDisposable; private borderWidth: number = 1; constructor( @@ -248,16 +249,16 @@ class SuggestionDetails extends Disposable { private readonly markdownRenderer: MarkdownRenderer, private readonly triggerKeybindingLabel: string ) { - super(); + this.disposables = []; this.el = append(container, $('.details')); - this._register(toDisposable(() => container.removeChild(this.el))); + this.disposables.push(toDisposable(() => container.removeChild(this.el))); this.body = $('.body'); this.scrollbar = new DomScrollableElement(this.body, {}); append(this.el, this.scrollbar.getDomNode()); - this._register(this.scrollbar); + this.disposables.push(this.scrollbar); this.header = append(this.body, $('.header')); this.close = append(this.header, $('span.close')); @@ -269,11 +270,11 @@ class SuggestionDetails extends Disposable { this.configureFont(); - this._register(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) .filter(e => e.fontInfo) - .on(this.configureFont, this)); + .on(this.configureFont, this, this.disposables); - this._register(markdownRenderer.onDidRenderCodeBlock(() => this.scrollbar.scanDomNode(), this)); + markdownRenderer.onDidRenderCodeBlock(() => this.scrollbar.scanDomNode(), this, this.disposables); } get element() { @@ -281,7 +282,7 @@ class SuggestionDetails extends Disposable { } render(item: CompletionItem): void { - this.renderDisposeable.clear(); + this.renderDisposeable = dispose(this.renderDisposeable); if (!item || !canExpandCompletionItem(item)) { this.type.textContent = ''; @@ -298,7 +299,7 @@ class SuggestionDetails extends Disposable { addClass(this.docs, 'markdown-docs'); this.docs.innerHTML = ''; const renderedContents = this.markdownRenderer.render(item.completion.documentation); - this.renderDisposeable.add(renderedContents); + this.renderDisposeable = renderedContents; this.docs.appendChild(renderedContents.element); } @@ -378,6 +379,11 @@ class SuggestionDetails extends Disposable { this.close.style.height = lineHeightPx; this.close.style.width = lineHeightPx; } + + dispose(): void { + this.disposables = dispose(this.disposables); + this.renderDisposeable = dispose(this.renderDisposeable); + } } export interface ISelectedSuggestion { diff --git a/src/vs/platform/actions/common/menuService.ts b/src/vs/platform/actions/common/menuService.ts index e0ee881b773..87cd2e9814d 100644 --- a/src/vs/platform/actions/common/menuService.ts +++ b/src/vs/platform/actions/common/menuService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { IMenu, IMenuActionOptions, IMenuItem, IMenuService, isIMenuItem, ISubmenuItem, MenuId, MenuItemAction, MenuRegistry, SubmenuItemAction } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr, IContextKeyService, IContextKeyChangeEvent } from 'vs/platform/contextkey/common/contextkey'; @@ -27,9 +27,10 @@ export class MenuService implements IMenuService { type MenuItemGroup = [string, Array]; -class Menu extends Disposable implements IMenu { +class Menu implements IMenu { - private readonly _onDidChange = this._register(new Emitter()); + private readonly _onDidChange = new Emitter(); + private readonly _dispoables = new DisposableStore(); private _menuGroups: MenuItemGroup[]; private _contextKeys: Set; @@ -39,12 +40,11 @@ class Menu extends Disposable implements IMenu { @ICommandService private readonly _commandService: ICommandService, @IContextKeyService private readonly _contextKeyService: IContextKeyService ) { - super(); this._build(); // rebuild this menu whenever the menu registry reports an // event for this MenuId - this._register(Event.debounce( + this._dispoables.add(Event.debounce( Event.filter(MenuRegistry.onDidChangeMenu, menuId => menuId === this._id), () => { }, 50 @@ -52,13 +52,18 @@ class Menu extends Disposable implements IMenu { // when context keys change we need to check if the menu also // has changed - this._register(Event.debounce( + this._dispoables.add(Event.debounce( this._contextKeyService.onDidChangeContext, (last, event) => last || event.affectsSome(this._contextKeys), 50 )(e => e && this._onDidChange.fire(undefined), this)); } + dispose(): void { + this._dispoables.dispose(); + this._onDidChange.dispose(); + } + private _build(): void { // reset diff --git a/src/vs/platform/url/electron-main/electronUrlListener.ts b/src/vs/platform/url/electron-main/electronUrlListener.ts index d0cdeee8f5d..c88372f8bc1 100644 --- a/src/vs/platform/url/electron-main/electronUrlListener.ts +++ b/src/vs/platform/url/electron-main/electronUrlListener.ts @@ -8,7 +8,7 @@ import { IURLService } from 'vs/platform/url/common/url'; import product from 'vs/platform/product/node/product'; import { app } from 'electron'; import { URI } from 'vs/base/common/uri'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; import { isWindows } from 'vs/base/common/platform'; import { coalesce } from 'vs/base/common/arrays'; @@ -21,14 +21,15 @@ function uriFromRawUrl(url: string): URI | null { } } -export class ElectronURLListener extends Disposable { +export class ElectronURLListener { + + private disposables: IDisposable[] = []; constructor( initial: string | string[], @IURLService private readonly urlService: IURLService, @IWindowsMainService windowsService: IWindowsMainService ) { - super(); const globalBuffer = ((global).getOpenUrls() || []) as string[]; const rawBuffer = [ ...(typeof initial === 'string' ? [initial] : initial), @@ -55,7 +56,7 @@ export class ElectronURLListener extends Disposable { }); const onOpenUrl = Event.filter(Event.map(onOpenElectronUrl, uriFromRawUrl), uri => !!uri); - this._register(onOpenUrl(this.urlService.open, this.urlService)); + onOpenUrl(this.urlService.open, this.urlService, this.disposables); const isWindowReady = windowsService.getWindows() .filter(w => w.isReady) @@ -67,4 +68,8 @@ export class ElectronURLListener extends Disposable { Event.once(windowsService.onWindowReady)(flush); } } + + dispose(): void { + this.disposables = dispose(this.disposables); + } } \ No newline at end of file diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index 12cfac305ef..07d8e6071a9 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import * as os from 'os'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { assign } from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; import product from 'vs/platform/product/node/product'; @@ -24,10 +24,12 @@ import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { isMacintosh, isLinux } from 'vs/base/common/platform'; import { ILogService } from 'vs/platform/log/common/log'; -export class WindowsService extends Disposable implements IWindowsService, IURLHandler { +export class WindowsService implements IWindowsService, IURLHandler, IDisposable { _serviceBrand: any; + private disposables: IDisposable[] = []; + private _activeWindowId: number | undefined; readonly onWindowOpen: Event = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-created', (_, w: Electron.BrowserWindow) => w.id), id => !!this.windowsMainService.getWindowById(id)); @@ -50,12 +52,11 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH @IHistoryMainService private readonly historyService: IHistoryMainService, @ILogService private readonly logService: ILogService ) { - super(); urlService.registerHandler(this); // remember last active window id - this._register(Event.latch(Event.any(this.onWindowOpen, this.onWindowFocus)) - (id => this._activeWindowId = id, null)); + Event.latch(Event.any(this.onWindowOpen, this.onWindowFocus)) + (id => this._activeWindowId = id, null, this.disposables); } async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise { @@ -459,4 +460,8 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH return undefined; } + + dispose(): void { + this.disposables = dispose(this.disposables); + } } diff --git a/src/vs/workbench/api/browser/mainThreadDocuments.ts b/src/vs/workbench/api/browser/mainThreadDocuments.ts index 62b7978fa29..af99b8a7720 100644 --- a/src/vs/workbench/api/browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadDocuments.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { toErrorMessage } from 'vs/base/common/errorMessage'; -import { IDisposable, IReference, dispose, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, IReference, dispose } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ITextModel } from 'vs/editor/common/model'; @@ -64,7 +64,7 @@ export class BoundModelReferenceCollection { } } -export class MainThreadDocuments extends Disposable implements MainThreadDocumentsShape { +export class MainThreadDocuments implements MainThreadDocumentsShape { private readonly _modelService: IModelService; private readonly _textModelResolverService: ITextModelService; @@ -73,6 +73,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen private readonly _untitledEditorService: IUntitledEditorService; private readonly _environmentService: IWorkbenchEnvironmentService; + private _toDispose: IDisposable[]; private _modelToDisposeMap: { [modelUrl: string]: IDisposable; }; private readonly _proxy: ExtHostDocumentsShape; private readonly _modelIsSynced: { [modelId: string]: boolean; }; @@ -89,7 +90,6 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen @IUntitledEditorService untitledEditorService: IUntitledEditorService, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService ) { - super(); this._modelService = modelService; this._textModelResolverService = textModelResolverService; this._textFileService = textFileService; @@ -100,22 +100,23 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments); this._modelIsSynced = {}; - this._register(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this))); - this._register(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this))); - this._register(this._modelReferenceCollection); - this._register(modelService.onModelModeChanged(this._onModelModeChanged, this)); + this._toDispose = []; + this._toDispose.push(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this))); + this._toDispose.push(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this))); + this._toDispose.push(this._modelReferenceCollection); + this._toDispose.push(modelService.onModelModeChanged(this._onModelModeChanged, this)); - this._register(textFileService.models.onModelSaved(e => { + this._toDispose.push(textFileService.models.onModelSaved(e => { if (this._shouldHandleFileEvent(e)) { this._proxy.$acceptModelSaved(e.resource); } })); - this._register(textFileService.models.onModelReverted(e => { + this._toDispose.push(textFileService.models.onModelReverted(e => { if (this._shouldHandleFileEvent(e)) { this._proxy.$acceptDirtyStateChanged(e.resource, false); } })); - this._register(textFileService.models.onModelDirty(e => { + this._toDispose.push(textFileService.models.onModelDirty(e => { if (this._shouldHandleFileEvent(e)) { this._proxy.$acceptDirtyStateChanged(e.resource, true); } @@ -129,7 +130,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen this._modelToDisposeMap[modelUrl].dispose(); }); this._modelToDisposeMap = Object.create(null); - super.dispose(); + this._toDispose = dispose(this._toDispose); } private _shouldHandleFileEvent(e: TextFileModelChangeEvent): boolean { diff --git a/src/vs/workbench/api/browser/mainThreadWindow.ts b/src/vs/workbench/api/browser/mainThreadWindow.ts index 18893db47b2..4c5b038c231 100644 --- a/src/vs/workbench/api/browser/mainThreadWindow.ts +++ b/src/vs/workbench/api/browser/mainThreadWindow.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; @@ -13,9 +13,10 @@ import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @extHostNamedCustomer(MainContext.MainThreadWindow) -export class MainThreadWindow extends Disposable implements MainThreadWindowShape { +export class MainThreadWindow implements MainThreadWindowShape { private readonly proxy: ExtHostWindowShape; + private disposables: IDisposable[] = []; private readonly _tunnels = new Map>(); constructor( @@ -25,15 +26,14 @@ export class MainThreadWindow extends Disposable implements MainThreadWindowShap @ITunnelService private readonly tunnelService: ITunnelService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService ) { - super(); this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostWindow); - this._register(Event.latch(windowService.onDidChangeFocus) - (this.proxy.$onDidChangeWindowFocus, this.proxy)); + Event.latch(windowService.onDidChangeFocus) + (this.proxy.$onDidChangeWindowFocus, this.proxy, this.disposables); } dispose(): void { - super.dispose(); + this.disposables = dispose(this.disposables); for (const tunnel of this._tunnels.values()) { tunnel.then(tunnel => tunnel.dispose()); diff --git a/src/vs/workbench/api/common/extHostDocuments.ts b/src/vs/workbench/api/common/extHostDocuments.ts index 5c5f3ddaf94..b7cf7793138 100644 --- a/src/vs/workbench/api/common/extHostDocuments.ts +++ b/src/vs/workbench/api/common/extHostDocuments.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel'; import { ExtHostDocumentsShape, IMainContext, MainContext, MainThreadDocumentsShape } from 'vs/workbench/api/common/extHost.protocol'; @@ -13,7 +13,7 @@ import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocum import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as vscode from 'vscode'; -export class ExtHostDocuments extends Disposable implements ExtHostDocumentsShape { +export class ExtHostDocuments implements ExtHostDocumentsShape { private _onDidAddDocument = new Emitter(); private _onDidRemoveDocument = new Emitter(); @@ -25,25 +25,31 @@ export class ExtHostDocuments extends Disposable implements ExtHostDocumentsShap readonly onDidChangeDocument: Event = this._onDidChangeDocument.event; readonly onDidSaveDocument: Event = this._onDidSaveDocument.event; + private _toDispose: IDisposable[]; private _proxy: MainThreadDocumentsShape; private _documentsAndEditors: ExtHostDocumentsAndEditors; private _documentLoader = new Map>(); constructor(mainContext: IMainContext, documentsAndEditors: ExtHostDocumentsAndEditors) { - super(); this._proxy = mainContext.getProxy(MainContext.MainThreadDocuments); this._documentsAndEditors = documentsAndEditors; - this._register(this._documentsAndEditors.onDidRemoveDocuments(documents => { - for (const data of documents) { - this._onDidRemoveDocument.fire(data.document); - } - })); - this._register(this._documentsAndEditors.onDidAddDocuments(documents => { - for (const data of documents) { - this._onDidAddDocument.fire(data.document); - } - })); + this._toDispose = [ + this._documentsAndEditors.onDidRemoveDocuments(documents => { + for (const data of documents) { + this._onDidRemoveDocument.fire(data.document); + } + }), + this._documentsAndEditors.onDidAddDocuments(documents => { + for (const data of documents) { + this._onDidAddDocument.fire(data.document); + } + }) + ]; + } + + public dispose(): void { + dispose(this._toDispose); } public getAllDocumentData(): ExtHostDocumentData[] { diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts index 0a983881471..78c08462c11 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts @@ -6,7 +6,7 @@ import 'vs/css!./quickInput'; import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list'; import * as dom from 'vs/base/browser/dom'; -import { dispose, IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { WorkbenchList } from 'vs/platform/list/browser/listService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; @@ -211,7 +211,7 @@ class ListElementDelegate implements IListVirtualDelegate { } } -export class QuickInputList extends Disposable { +export class QuickInputList { readonly id: string; private container: HTMLElement; @@ -235,14 +235,14 @@ export class QuickInputList extends Disposable { private _onLeave = new Emitter(); onLeave: Event = this._onLeave.event; private _fireCheckedEvents = true; - private readonly elementDisposables = this._register(new DisposableStore()); + private elementDisposables: IDisposable[] = []; + private disposables: IDisposable[] = []; constructor( private parent: HTMLElement, id: string, @IInstantiationService private readonly instantiationService: IInstantiationService ) { - super(); this.id = id; this.container = dom.append(this.parent, $('.quick-input-list')); const delegate = new ListElementDelegate(); @@ -254,8 +254,8 @@ export class QuickInputList extends Disposable { horizontalScrolling: false } as IListOptions) as WorkbenchList; this.list.getHTMLElement().id = id; - this._register(this.list); - this._register(this.list.onKeyDown(e => { + this.disposables.push(this.list); + this.disposables.push(this.list.onKeyDown(e => { const event = new StandardKeyboardEvent(e); switch (event.keyCode) { case KeyCode.Space: @@ -282,13 +282,13 @@ export class QuickInputList extends Disposable { break; } })); - this._register(this.list.onMouseDown(e => { + this.disposables.push(this.list.onMouseDown(e => { if (e.browserEvent.button !== 2) { // Works around / fixes #64350. e.browserEvent.preventDefault(); } })); - this._register(dom.addDisposableListener(this.container, dom.EventType.CLICK, e => { + this.disposables.push(dom.addDisposableListener(this.container, dom.EventType.CLICK, e => { if (e.x || e.y) { // Avoid 'click' triggered by 'space' on checkbox. this._onLeave.fire(); } @@ -360,7 +360,7 @@ export class QuickInputList extends Disposable { } setElements(inputElements: Array): void { - this.elementDisposables.clear(); + this.elementDisposables = dispose(this.elementDisposables); const fireButtonTriggered = (event: IQuickPickItemButtonEvent) => this.fireButtonTriggered(event); this.inputElements = inputElements; this.elements = inputElements.reduce((result, item, index) => { @@ -379,10 +379,7 @@ export class QuickInputList extends Disposable { } return result; }, [] as ListElement[]); - - for (const element of this.elements) { - this.elementDisposables.add(element.onChecked(() => this.fireCheckedEvents())); - } + this.elementDisposables.push(...this.elements.map(element => element.onChecked(() => this.fireCheckedEvents()))); this.elementsToIndexes = this.elements.reduce((map, element, index) => { map.set(element.item, index); @@ -559,6 +556,11 @@ export class QuickInputList extends Disposable { return this.container.style.display !== 'none'; } + dispose() { + this.elementDisposables = dispose(this.elementDisposables); + this.disposables = dispose(this.disposables); + } + private fireCheckedEvents() { if (this._fireCheckedEvents) { this._onChangedAllVisibleChecked.fire(this.getAllVisibleChecked()); diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts index 5fac853caaa..b949e001a30 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts @@ -9,7 +9,7 @@ import { Widget } from 'vs/base/browser/ui/widget'; import { Color } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { mixin } from 'vs/base/common/objects'; import { isMacintosh } from 'vs/base/common/platform'; import { URI as uri } from 'vs/base/common/uri'; @@ -103,6 +103,7 @@ export class SuggestEnabledInput extends Widget implements IThemable { private _onInputDidChange = new Emitter(); readonly onInputDidChange: Event = this._onInputDidChange.event; + private disposables: IDisposable[] = []; private readonly inputWidget: CodeEditorWidget; private readonly inputModel: ITextModel; private stylingContainer: HTMLDivElement; @@ -133,31 +134,31 @@ export class SuggestEnabledInput extends Widget implements IThemable { contributions: [SuggestController, SnippetController2, ContextMenuController, MenuPreventer, SelectionClipboard], isSimpleWidget: true, }); - this._register(this.inputWidget); + this.disposables.push(this.inputWidget); let scopeHandle = uri.parse(resourceHandle); this.inputModel = modelService.createModel('', null, scopeHandle, true); this.inputWidget.setModel(this.inputModel); - this._register(this.inputWidget.onDidPaste(() => this.setValue(this.getValue()))); // setter cleanses + this.disposables.push(this.inputWidget.onDidPaste(() => this.setValue(this.getValue()))); // setter cleanses - this._register((this.inputWidget.onDidFocusEditorText(() => { + this.disposables.push((this.inputWidget.onDidFocusEditorText(() => { if (options.focusContextKey) { options.focusContextKey.set(true); } addClass(this.stylingContainer, 'synthetic-focus'); }))); - this._register((this.inputWidget.onDidBlurEditorText(() => { + this.disposables.push((this.inputWidget.onDidBlurEditorText(() => { if (options.focusContextKey) { options.focusContextKey.set(false); } removeClass(this.stylingContainer, 'synthetic-focus'); }))); const onKeyDownMonaco = Event.chain(this.inputWidget.onKeyDown); - this._register(onKeyDownMonaco.filter(e => e.keyCode === KeyCode.Enter).on(e => { e.preventDefault(); this._onEnter.fire(); }, this)); - this._register(onKeyDownMonaco.filter(e => e.keyCode === KeyCode.DownArrow && (isMacintosh ? e.metaKey : e.ctrlKey)).on(() => this._onShouldFocusResults.fire(), this)); + onKeyDownMonaco.filter(e => e.keyCode === KeyCode.Enter).on(e => { e.preventDefault(); this._onEnter.fire(); }, this, this.disposables); + onKeyDownMonaco.filter(e => e.keyCode === KeyCode.DownArrow && (isMacintosh ? e.metaKey : e.ctrlKey)).on(() => this._onShouldFocusResults.fire(), this, this.disposables); let preexistingContent = this.getValue(); const inputWidgetModel = this.inputWidget.getModel(); if (inputWidgetModel) { - this._register(inputWidgetModel.onDidChangeContent(() => { + this.disposables.push(inputWidgetModel.onDidChangeContent(() => { let content = this.getValue(); this.placeholderText.style.visibility = content ? 'hidden' : 'visible'; if (preexistingContent.trim() === content.trim()) { return; } @@ -174,7 +175,7 @@ export class SuggestEnabledInput extends Widget implements IThemable { this.setValue(options.value || ''); - this._register(modes.CompletionProviderRegistry.register({ scheme: scopeHandle.scheme, pattern: '**/' + scopeHandle.path, hasAccessToAllModels: true }, { + this.disposables.push(modes.CompletionProviderRegistry.register({ scheme: scopeHandle.scheme, pattern: '**/' + scopeHandle.path, hasAccessToAllModels: true }, { triggerCharacters: validatedSuggestProvider.triggerCharacters, provideCompletionItems: (model: ITextModel, position: Position, _context: modes.CompletionContext) => { let query = model.getValue(); @@ -248,6 +249,11 @@ export class SuggestEnabledInput extends Widget implements IThemable { private selectAll(): void { this.inputWidget.setSelection(new Range(1, 1, 1, this.getValue().length + 1)); } + + dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } } // Override styles in selections.ts diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts index 2fbc338c721..7bad502bda4 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { timeout, Delayer } from 'vs/base/common/async'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Event as EventOf, Emitter } from 'vs/base/common/event'; import { IAction } from 'vs/base/common/actions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -338,6 +338,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio private extensionsBox: HTMLElement; private primaryActions: IAction[]; private secondaryActions: IAction[] | null; + private disposables: IDisposable[] = []; private searchViewletState: object; constructor( @@ -372,14 +373,14 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService); this.defaultRecommendedExtensionsContextKey = DefaultRecommendedExtensionsContext.bindTo(contextKeyService); this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue(ShowRecommendationsOnlyOnDemandKey)); - this._register(this.viewletService.onDidViewletOpen(this.onViewletOpen, this)); + this.disposables.push(this.viewletService.onDidViewletOpen(this.onViewletOpen, this, this.disposables)); this.searchViewletState = this.getMemento(StorageScope.WORKSPACE); this.extensionManagementService.getInstalled(ExtensionType.User).then(result => { this.hasInstalledExtensionsContextKey.set(result.length > 0); }); - this._register(this.configurationService.onDidChangeConfiguration(e => { + this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(AutoUpdateConfigurationKey)) { this.secondaryActions = null; this.updateTitleArea(); @@ -387,7 +388,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio if (e.affectedKeys.indexOf(ShowRecommendationsOnlyOnDemandKey) > -1) { this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue(ShowRecommendationsOnlyOnDemandKey)); } - }, this)); + }, this, this.disposables); } create(parent: HTMLElement): void { @@ -414,18 +415,18 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio this.triggerSearch(); } - this._register(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService)); + this.disposables.push(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService)); - this._register(this.searchBox); + this.disposables.push(this.searchBox); const _searchChange = new Emitter(); this.onSearchChange = _searchChange.event; - this._register(this.searchBox.onInputDidChange(() => { + this.searchBox.onInputDidChange(() => { this.triggerSearch(); _searchChange.fire(this.searchBox.getValue()); - }, this)); + }, this, this.disposables); - this._register(this.searchBox.onShouldFocusResults(() => this.focusListView(), this)); + this.searchBox.onShouldFocusResults(() => this.focusListView(), this, this.disposables); this._register(this.onDidChangeVisibility(visible => { if (visible) { @@ -612,19 +613,24 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio this.notificationService.error(err); } + + dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } } -export class StatusUpdater extends Disposable implements IWorkbenchContribution { +export class StatusUpdater implements IWorkbenchContribution { - private badgeHandle?: IDisposable; + private disposables: IDisposable[]; + private badgeHandle: IDisposable; constructor( @IActivityService private readonly activityService: IActivityService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService ) { - super(); - this._register(extensionsWorkbenchService.onChange(this.onServiceChange, this)); + extensionsWorkbenchService.onChange(this.onServiceChange, this, this.disposables); } private onServiceChange(): void { @@ -644,13 +650,15 @@ export class StatusUpdater extends Disposable implements IWorkbenchContribution } dispose(): void { - super.dispose(); + this.disposables = dispose(this.disposables); dispose(this.badgeHandle); } } export class MaliciousExtensionChecker implements IWorkbenchContribution { + private disposables: IDisposable[]; + constructor( @IExtensionManagementService private readonly extensionsManagementService: IExtensionManagementService, @IWindowService private readonly windowService: IWindowService, @@ -695,4 +703,8 @@ export class MaliciousExtensionChecker implements IWorkbenchContribution { }).then(() => undefined); }, err => this.logService.error(err)); } + + dispose(): void { + this.disposables = dispose(this.disposables); + } } diff --git a/src/vs/workbench/contrib/files/common/explorerService.ts b/src/vs/workbench/contrib/files/common/explorerService.ts index 480032e9e70..ba20daa7266 100644 --- a/src/vs/workbench/contrib/files/common/explorerService.ts +++ b/src/vs/workbench/contrib/files/common/explorerService.ts @@ -5,7 +5,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IExplorerService, IEditableData, IFilesConfiguration, SortOrder, SortOrderConfiguration } from 'vs/workbench/contrib/files/common/files'; import { ExplorerItem, ExplorerModel } from 'vs/workbench/contrib/files/common/explorerModel'; import { URI } from 'vs/base/common/uri'; @@ -26,7 +26,7 @@ function getFileEventsExcludes(configurationService: IConfigurationService, root return (configuration && configuration.files && configuration.files.exclude) || Object.create(null); } -export class ExplorerService extends Disposable implements IExplorerService { +export class ExplorerService implements IExplorerService { _serviceBrand: any; private static readonly EXPLORER_FILE_CHANGES_REACT_DELAY = 500; // delay in ms to react to file changes to give our internal events a chance to react first @@ -36,6 +36,7 @@ export class ExplorerService extends Disposable implements IExplorerService { private _onDidChangeEditable = new Emitter(); private _onDidSelectResource = new Emitter<{ resource?: URI, reveal?: boolean }>(); private _onDidCopyItems = new Emitter<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }>(); + private disposables: IDisposable[] = []; private editable: { stat: ExplorerItem, data: IEditableData } | undefined; private _sortOrder: SortOrder; private cutItems: ExplorerItem[] | undefined; @@ -49,7 +50,6 @@ export class ExplorerService extends Disposable implements IExplorerService { @IClipboardService private clipboardService: IClipboardService, @IEditorService private editorService: IEditorService ) { - super(); this._sortOrder = this.configurationService.getValue('explorer.sortOrder'); } @@ -88,18 +88,18 @@ export class ExplorerService extends Disposable implements IExplorerService { (root?: URI) => getFileEventsExcludes(this.configurationService, root), (event: IConfigurationChangeEvent) => event.affectsConfiguration(FILES_EXCLUDE_CONFIG) ); - this._register(fileEventsFilter); + this.disposables.push(fileEventsFilter); return fileEventsFilter; } @memoize get model(): ExplorerModel { const model = new ExplorerModel(this.contextService); - this._register(model); - this._register(this.fileService.onAfterOperation(e => this.onFileOperation(e))); - this._register(this.fileService.onFileChanges(e => this.onFileChanges(e))); - this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue()))); - this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => { + this.disposables.push(model); + this.disposables.push(this.fileService.onAfterOperation(e => this.onFileOperation(e))); + this.disposables.push(this.fileService.onFileChanges(e => this.onFileChanges(e))); + this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue()))); + this.disposables.push(this.fileService.onDidChangeFileSystemProviderRegistrations(e => { if (e.added && this.fileSystemProviderSchemes.has(e.scheme)) { // A file system provider got re-registered, we should update all file stats since they might change (got read-only) this._onDidChangeItem.fire({ recursive: true }); @@ -107,7 +107,7 @@ export class ExplorerService extends Disposable implements IExplorerService { this.fileSystemProviderSchemes.add(e.scheme); } })); - this._register(model.onDidChangeRoots(() => this._onDidChangeRoots.fire())); + this.disposables.push(model.onDidChangeRoots(() => this._onDidChangeRoots.fire())); return model; } @@ -377,4 +377,8 @@ export class ExplorerService extends Disposable implements IExplorerService { } } } + + dispose(): void { + dispose(this.disposables); + } } diff --git a/src/vs/workbench/contrib/markers/browser/markersPanel.ts b/src/vs/workbench/contrib/markers/browser/markersPanel.ts index 8d47cfd91af..334c6936016 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanel.ts @@ -40,6 +40,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { domEvent } from 'vs/base/browser/event'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ResourceLabels } from 'vs/workbench/browser/labels'; import { IMarker } from 'vs/platform/markers/common/markers'; import { withUndefinedAsNull } from 'vs/base/common/types'; @@ -89,6 +90,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { private currentResourceGotAddedToMarkersData: boolean = false; readonly markersViewModel: MarkersViewModel; + private disposables: IDisposable[] = []; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -108,7 +110,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { this.panelFoucusContextKey = Constants.MarkerPanelFocusContextKey.bindTo(contextKeyService); this.panelState = this.getMemento(StorageScope.WORKSPACE); this.markersViewModel = instantiationService.createInstance(MarkersViewModel, this.panelState['multiline']); - this._register(this.markersViewModel.onDidChange(this.onDidChangeViewState, this)); + this.markersViewModel.onDidChange(this.onDidChangeViewState, this, this.disposables); this.setCurrentActiveEditor(); } @@ -732,5 +734,6 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { super.dispose(); this.tree.dispose(); this.markersViewModel.dispose(); + this.disposables = dispose(this.disposables); } } diff --git a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts index d5ec9b684db..3d633a1686b 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanelActions.ts @@ -18,7 +18,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { attachInputBoxStyler, attachStylerCallback, attachCheckboxStyler } from 'vs/platform/theme/common/styler'; import { IMarkersWorkbenchService } from 'vs/workbench/contrib/markers/browser/markers'; -import { toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { BaseActionViewItem, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { badgeBackground, badgeForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { localize } from 'vs/nls'; @@ -296,6 +296,8 @@ export class QuickFixAction extends Action { private static readonly CLASS: string = 'markers-panel-action-quickfix'; private static readonly AUTO_FIX_CLASS: string = QuickFixAction.CLASS + ' autofixable'; + private disposables: IDisposable[] = []; + private readonly _onShowQuickFixes: Emitter = new Emitter(); readonly onShowQuickFixes: Event = this._onShowQuickFixes.event; @@ -322,6 +324,11 @@ export class QuickFixAction extends Action { this._onShowQuickFixes.fire(); return Promise.resolve(); } + + dispose(): void { + dispose(this.disposables); + super.dispose(); + } } export class QuickFixActionViewItem extends ActionViewItem { diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index 74b8ca01acb..cb51cf61d64 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -140,9 +140,10 @@ interface RelatedInformationFilterData { export type FilterData = ResourceMarkersFilterData | MarkerFilterData | RelatedInformationFilterData; -export class ResourceMarkersRenderer extends Disposable implements ITreeRenderer { +export class ResourceMarkersRenderer implements ITreeRenderer { private renderedNodes = new Map, IResourceMarkersTemplateData>(); + private disposables: IDisposable[] = []; constructor( private labels: ResourceLabels, @@ -150,8 +151,7 @@ export class ResourceMarkersRenderer extends Disposable implements ITreeRenderer @IThemeService private readonly themeService: IThemeService, @ILabelService private readonly labelService: ILabelService ) { - super(); - this._register(onDidChangeRenderNodeCount(this.onDidChangeRenderNodeCount, this)); + onDidChangeRenderNodeCount(this.onDidChangeRenderNodeCount, this, this.disposables); } templateId = TemplateId.ResourceMarkers; @@ -205,6 +205,10 @@ export class ResourceMarkersRenderer extends Disposable implements ITreeRenderer private updateCount(node: ITreeNode, templateData: IResourceMarkersTemplateData): void { templateData.count.setCount(node.children.reduce((r, n) => r + (n.visible ? 1 : 0), 0)); } + + dispose(): void { + this.disposables = dispose(this.disposables); + } } export class FileResourceMarkersRenderer extends ResourceMarkersRenderer { diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts index f45d098fb72..49beca20e0d 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts @@ -12,7 +12,7 @@ import { Action, IAction } from 'vs/base/common/actions'; import { Emitter, Event } from 'vs/base/common/event'; import { MarkdownString } from 'vs/base/common/htmlContent'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IMarginData } from 'vs/editor/browser/controller/mouseTarget'; import { ICodeEditor, IEditorMouseEvent, IViewZone, MouseTargetType } from 'vs/editor/browser/editorBrowser'; @@ -302,6 +302,8 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { private detailsElement: HTMLElement; private dropDownElement: HTMLElement; + private disposables: IDisposable[] = []; + constructor( action: IAction, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @@ -310,7 +312,7 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { super(null, action); const workspace = this.contextService.getWorkspace(); this._folder = workspace.folders.length === 1 ? workspace.folders[0] : null; - this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.onWorkspaceFoldersChanged())); + this.disposables.push(this.contextService.onDidChangeWorkspaceFolders(() => this.onWorkspaceFoldersChanged())); } get folder(): IWorkspaceFolder | null { @@ -345,8 +347,8 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { 'tabindex': '0' }, this.labelElement, this.detailsElement, this.dropDownElement); this._register(DOM.addDisposableListener(this.anchorElement, DOM.EventType.MOUSE_DOWN, e => DOM.EventHelper.stop(e))); - this._register(DOM.addDisposableListener(this.anchorElement, DOM.EventType.CLICK, e => this.onClick(e))); - this._register(DOM.addDisposableListener(this.anchorElement, DOM.EventType.KEY_UP, e => this.onKeyUp(e))); + this.disposables.push(DOM.addDisposableListener(this.anchorElement, DOM.EventType.CLICK, e => this.onClick(e))); + this.disposables.push(DOM.addDisposableListener(this.anchorElement, DOM.EventType.KEY_UP, e => this.onKeyUp(e))); DOM.append(this.container, this.anchorElement); @@ -458,6 +460,11 @@ export class FolderSettingsActionViewItem extends BaseActionViewItem { return label; } + + dispose(): void { + dispose(this.disposables); + super.dispose(); + } } export type SettingsTarget = ConfigurationTarget.USER_LOCAL | ConfigurationTarget.USER_REMOTE | ConfigurationTarget.WORKSPACE | URI; diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index b3f27dc9e0f..040e86f87fd 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -8,7 +8,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import * as errors from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { getBaseLabel } from 'vs/base/common/labels'; -import { Disposable, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap, TernarySearchTree, values } from 'vs/base/common/map'; import * as objects from 'vs/base/common/objects'; import { lcut } from 'vs/base/common/strings'; @@ -1044,11 +1044,12 @@ export class RangeHighlightDecorations implements IDisposable { private _decorationId: string | null = null; private _model: ITextModel | null = null; - private readonly _modelDisposables = new DisposableStore(); + private _modelDisposables: IDisposable[] = []; constructor( @IModelService private readonly _modelService: IModelService - ) { } + ) { + } removeHighlightRange() { if (this._model && this._decorationId) { @@ -1080,12 +1081,12 @@ export class RangeHighlightDecorations implements IDisposable { if (this._model !== model) { this.disposeModelListeners(); this._model = model; - this._modelDisposables.add(this._model.onDidChangeDecorations((e) => { + this._modelDisposables.push(this._model.onDidChangeDecorations((e) => { this.disposeModelListeners(); this.removeHighlightRange(); this._model = null; })); - this._modelDisposables.add(this._model.onWillDispose(() => { + this._modelDisposables.push(this._model.onWillDispose(() => { this.disposeModelListeners(); this.removeHighlightRange(); this._model = null; @@ -1094,7 +1095,8 @@ export class RangeHighlightDecorations implements IDisposable { } private disposeModelListeners() { - this._modelDisposables.clear(); + this._modelDisposables.forEach(disposable => disposable.dispose()); + this._modelDisposables = []; } dispose() { @@ -1103,7 +1105,6 @@ export class RangeHighlightDecorations implements IDisposable { this.disposeModelListeners(); this._model = null; } - this._modelDisposables.dispose(); } private static readonly _RANGE_HIGHLIGHT_DECORATION = ModelDecorationOptions.register({ diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts index a282dfef00b..abaa82a2654 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts @@ -5,7 +5,7 @@ import { join } from 'vs/base/common/path'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { dispose, IDisposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle'; +import { combinedDisposable, dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { values } from 'vs/base/common/map'; import * as resources from 'vs/base/common/resources'; import { endsWith, isFalsyOrWhitespace } from 'vs/base/common/strings';